Compare commits

..

90 Commits

Author SHA1 Message Date
RPRX
b277bacdf6 v1.8.19 2024-07-17 13:51:21 +00:00
RPRX
9288a7c0dc Upgrade dependencies 2024-07-17 13:45:16 +00:00
ll11l1lIllIl1lll
c40fc44a34 SplitHTTP: Client supports HTTP/3 (#3543)
Closes https://github.com/XTLS/Xray-core/issues/3456

Co-authored-by: Fangliding <Fangliding.fshxy@outlook.com>
Co-authored-by: mmmray <142015632+mmmray@users.noreply.github.com>
2024-07-17 07:55:28 -05:00
yuhan6665
02cd3b8c74 Fix SplitHTTP race condition when creating new sessions (#3533)
Co-authored-by: nobody <nobody@nowhere.mars>
Co-authored-by: mmmray <142015632+mmmray@users.noreply.github.com>
2024-07-17 11:41:17 +00:00
风扇滑翔翼
a7e198e1e2 Fix WS reading X-Forwarded-For & Add tests (#3546)
Fixes https://github.com/XTLS/Xray-core/issues/3545

---------

Co-authored-by: mmmray <142015632+mmmray@users.noreply.github.com>
2024-07-17 10:40:25 +00:00
RPRX
9e6d7a3cb0 v1.8.18 2024-07-15 13:57:18 +00:00
RPRX
a4bc422ed1 README: Remove 13 inactive projects 2024-07-15 13:53:43 +00:00
abvf
59819e2a1b Fix log severity (#3535) 2024-07-15 14:04:04 +02:00
mmmray
573fb4f643 Add Windows 7 builds (#3530)
Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com>
2024-07-15 09:53:40 +00:00
RPRX
558cfcc507 v1.8.17 2024-07-12 11:00:32 +00:00
RPRX
39675b7ef7 Upgrade github.com/xtls/reality to 20240712055506
Fixes https://github.com/XTLS/REALITY/pull/7#issuecomment-2223320694
2024-07-12 06:02:31 +00:00
MHSanaei
16de0937a8 Fix typos (#3527) 2024-07-12 00:20:06 +02:00
mmmray
c69d38ae82 add link to discussions 2024-07-11 14:48:17 -04:00
RPRX
73a001dd7a Upgrade github.com/xtls/reality to 20240711105359
Fixes https://github.com/XTLS/Xray-core/issues/3502
2024-07-11 12:02:49 +00:00
mmmray
c8f6ba9ff0 Add SplitHTTP Browser Dialer support (#3484) 2024-07-11 07:56:20 +00:00
风扇滑翔翼
308f0c64c3 Add custom Sockopt support (#3517)
* Add custom sockopt

* Add custom level

* Change field

* Sth left
2024-07-09 12:19:31 -04:00
dependabot[bot]
ce637c0c23 Bump github.com/refraction-networking/utls from 1.6.6 to 1.6.7
Bumps [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) from 1.6.6 to 1.6.7.
- [Release notes](https://github.com/refraction-networking/utls/releases)
- [Commits](https://github.com/refraction-networking/utls/compare/v1.6.6...v1.6.7)

---
updated-dependencies:
- dependency-name: github.com/refraction-networking/utls
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-07 23:32:33 -04:00
dependabot[bot]
0d130a0489 Bump github.com/sagernet/sing-shadowsocks from 0.2.6 to 0.2.7
Bumps [github.com/sagernet/sing-shadowsocks](https://github.com/sagernet/sing-shadowsocks) from 0.2.6 to 0.2.7.
- [Commits](https://github.com/sagernet/sing-shadowsocks/compare/v0.2.6...v0.2.7)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing-shadowsocks
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-07 23:32:18 -04:00
dependabot[bot]
01a3b4912b Bump golang.org/x/net from 0.26.0 to 0.27.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/net/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-07 23:32:09 -04:00
yuhan6665
b8c0768b16 Properly parse HTTP host for verification
Also fix H2 transport to not verify if host is not defined
2024-07-07 22:35:11 -04:00
yuhan6665
4c51636788 Relax server HTTP host check 2024-07-06 15:06:58 -04:00
dependabot[bot]
1113ee7fa2 Bump golang.org/x/sys from 0.21.0 to 0.22.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.21.0 to 0.22.0.
- [Commits](https://github.com/golang/sys/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-06 12:21:53 -04:00
dependabot[bot]
e13f9f59da Bump google.golang.org/grpc from 1.64.0 to 1.65.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.65.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.65.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-03 16:49:38 -04:00
yuhan6665
60b2c349d2 Try to fix infinite conn read in tests 2024-07-01 23:55:30 -04:00
mmmray
c6a57b2cc1 Fix connection reuse in splithttp HTTP/1.1 (#3485) 2024-07-01 05:30:34 +02:00
yuhan6665
079d0bd8a9 Refactor log (#3446)
* Refactor log

* Add new log methods

* Fix logger test

* Change all logging code

* Clean up pathObj

* Rebase to latest main

* Remove invoking method name after the dot
2024-06-29 14:32:57 -04:00
RPRX
8320732743 SplitHTTP: ok -> ooooooooook (parser in client)
https://github.com/XTLS/Xray-core/pull/3479#issuecomment-2196370334
2024-06-28 16:53:18 +08:00
mmmray
c0f3bf66fd Add new header to disable HTTP middle box buffer
Co-Authored-By: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>
2024-06-28 16:14:59 +08:00
maskedeken
e4f9d03bef splithttp Read() using blocking mode (#3473)
* blocking splithttp read

* Add testcase

* simplify conditions

---------

Co-authored-by: mmmray <142015632+mmmray@users.noreply.github.com>
2024-06-24 11:09:24 -04:00
dependabot[bot]
7acd5a623b Bump github.com/quic-go/quic-go from 0.45.0 to 0.45.1
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.45.0 to 0.45.1.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.45.0...v0.45.1)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-23 23:18:07 -04:00
mmmray
ee2000f6e1 splithttp: Add support for H2C and http/1.1 ALPN on server (#3465)
* Add H2C support to server

* update comment

* Make http1.1 ALPN work on SplitHTTP client

Users that encounter protocol version issues will likely try to set the
ALPN explicitly. In that case we should simply grant their wish, because
the intent is obvious.
2024-06-23 13:05:37 -04:00
mmmray
74d233dd64 More docker tags 2024-06-23 12:55:37 -04:00
mmmray
eb4f9429e6 Use ArrayBuffer in WS browser dialer binaryType (#3468)
On my machine, browserdialer speedtest gives 10 Mbit/s download. Now it
can do 300 Mbit/s.
2024-06-23 05:31:57 +08:00
风扇滑翔翼
028a640b1b Update issues template 2024-06-22 12:18:25 +00:00
RPRX
9432a600e6 v1.8.16 2024-06-20 23:50:32 +00:00
mmmray
8fe976d7ee Upgrade SplitHTTP Transport (#3462)
* move to paths instead of querystrings

* permit early data on serverside

* early data for the client, fix context cancellation
2024-06-20 23:30:51 +00:00
mmmray
c1a7602412 fix compatibility issues with go 1.21 2024-06-18 10:23:29 -04:00
RPRX
404af13b56 v1.8.15 2024-06-18 05:38:04 +00:00
mmmray
c10bd28731 Add SplitHTTP Transport (#3412) 2024-06-18 05:36:36 +00:00
dependabot[bot]
501d5dec60 Bump docker/build-push-action from 5 to 6 (#3454)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 05:34:37 +00:00
dependabot[bot]
d04a9d4fc9 Bump github.com/gorilla/websocket from 1.5.2 to 1.5.3
Bumps [github.com/gorilla/websocket](https://github.com/gorilla/websocket) from 1.5.2 to 1.5.3.
- [Release notes](https://github.com/gorilla/websocket/releases)
- [Commits](https://github.com/gorilla/websocket/compare/v1.5.2...v1.5.3)

---
updated-dependencies:
- dependency-name: github.com/gorilla/websocket
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-16 22:58:45 -04:00
风扇滑翔翼
ae97821e40 Add regex support for domainsExcluded (#3449)
* Add regx support for domainsExcluded

* format
2024-06-16 10:51:52 -04:00
dependabot[bot]
219a7dac20 Bump github.com/miekg/dns from 1.1.59 to 1.1.61
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.59 to 1.1.61.
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.59...v1.1.61)

---
updated-dependencies:
- dependency-name: github.com/miekg/dns
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-14 14:25:44 -04:00
dependabot[bot]
a1626cbf94 Bump github.com/cloudflare/circl from 1.3.8 to 1.3.9
Bumps [github.com/cloudflare/circl](https://github.com/cloudflare/circl) from 1.3.8 to 1.3.9.
- [Release notes](https://github.com/cloudflare/circl/releases)
- [Commits](https://github.com/cloudflare/circl/compare/v1.3.8...v1.3.9)

---
updated-dependencies:
- dependency-name: github.com/cloudflare/circl
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-12 12:29:47 -04:00
dependabot[bot]
f7dd84d6b9 Bump google.golang.org/protobuf from 1.34.1 to 1.34.2
Bumps google.golang.org/protobuf from 1.34.1 to 1.34.2.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-12 12:29:37 -04:00
dependabot[bot]
ea02ae74ed Bump github.com/gorilla/websocket from 1.5.1 to 1.5.2
Bumps [github.com/gorilla/websocket](https://github.com/gorilla/websocket) from 1.5.1 to 1.5.2.
- [Release notes](https://github.com/gorilla/websocket/releases)
- [Commits](https://github.com/gorilla/websocket/compare/v1.5.1...v1.5.2)

---
updated-dependencies:
- dependency-name: github.com/gorilla/websocket
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 10:17:49 -04:00
dependabot[bot]
c15974f7ee Bump github.com/sagernet/sing from 0.4.0 to 0.4.1
Bumps [github.com/sagernet/sing](https://github.com/sagernet/sing) from 0.4.0 to 0.4.1.
- [Commits](https://github.com/sagernet/sing/compare/v0.4.0...v0.4.1)

---
updated-dependencies:
- dependency-name: github.com/sagernet/sing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-07 10:14:22 -04:00
dependabot[bot]
13f0eccb8f Bump github.com/quic-go/quic-go from 0.44.0 to 0.45.0
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.44.0 to 0.45.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.44.0...v0.45.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-07 10:14:13 -04:00
Asen
f0cb292dc6 CI: not create zip file when not releasing
Makefile: remove unneccesary `install` target &

Add build to `.PHONY` target
2024-06-07 10:11:13 -04:00
风扇滑翔翼
3654c0d710 HTTPUpgrade send headers with specified capitalization (#3430)
* Fix HTTPUpgrade header capitalization

* Chore

* Remove excess host headers

Chore : change httpupgrade header "upgrade" to "Upgrade" #3435
2024-06-07 12:53:27 +00:00
mmmray
f8ec93dfdd drain buffer correctly in httpupgrade (#3428)
* drain buffer correctly in httpupgrade

it seems the recently added httupgrade testsuite is causing timeouts on master

i have no evidence this is the real issue, but it feels to me that the
server could accidentally over-read, and then the encapsulated
connection will block forever trying to read data

let's test it in CI a couple of times, i don't have a way to reproduce
the issue

* correctly drain buffer, again
2024-06-05 22:43:15 -04:00
mmmray
980236f2b6 preserve exact header casing when using httpupgrade (#3427)
* preserve exact header casing when using httpupgrade

* fix capitalization of websocket

* oops, we dont need net/url either

* restore old codepath when there are no headers
2024-06-05 20:43:44 -04:00
风扇滑翔翼
be29cc39d7 Add httpupgrade test 2024-06-05 17:39:55 +00:00
dependabot[bot]
9c6685d2ee Bump golang.org/x/net from 0.25.0 to 0.26.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.25.0 to 0.26.0.
- [Commits](https://github.com/golang/net/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-05 10:36:39 -04:00
dependabot[bot]
f5a70e4200 Bump golang.org/x/crypto from 0.23.0 to 0.24.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.23.0 to 0.24.0.
- [Commits](https://github.com/golang/crypto/compare/v0.23.0...v0.24.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-05 10:35:43 -04:00
mmmray
75b3ef71a1 fix filename 2024-06-03 16:40:13 -04:00
风扇滑翔翼
df53afceae Make ws_test uses random ports 2024-06-04 00:52:02 +08:00
AsenHu
459504300c chore: Remove unnecessary if in httpupgrade (#3413) 2024-06-04 00:13:46 +08:00
yuhan6665
075051a693 Add wireguard test 2024-06-01 19:34:31 -04:00
yuhan6665
bbf25b14d9 Update dependencies 2024-06-01 11:56:24 -04:00
isluckys
89074a14b6 Fix udp goroutine leak
v.conn.link.Reader is a pipe.Reader, doesn't implement Close(), it will fail assertion and cause the pipe to be left open
It can be fixed by using Interrupt()
2024-05-30 17:45:29 -04:00
Grvzard
73c5650b17 build: change usage of grep for better compatibility 2024-05-28 21:34:22 +08:00
yuhan6665
0a3c449cdf Inbound worker should fill context outbounds info
https://github.com/XTLS/Xray-core/issues/3388
2024-05-26 12:25:25 -04:00
RPRX
ca07a705dc Generate *.pb.go files with protoc v5.27.0
Download https://github.com/protocolbuffers/protobuf/releases/tag/v27.0
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0
(Xray-core/) go run ./infra/vprotogen
2024-05-26 03:20:53 +00:00
RPRX
3120ca4121 v1.8.13 2024-05-22 22:02:23 +00:00
yuhan6665
9b6141b83f Wireguard dial with context 2024-05-22 09:02:20 -04:00
RPRX
416f2df11c v1.8.12 2024-05-22 04:36:56 +00:00
RPRX
29c6318ffe Upgrade github.com/xtls/reality to 20240429224917
https://github.com/XTLS/Xray-core/discussions/3318
2024-05-22 04:28:58 +00:00
风扇滑翔翼
9ee9a0634e Add UDPFilter to Socks5 server when auth == password (#3371)
Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com>
2024-05-22 03:02:45 +00:00
dependabot[bot]
544f7661ca Bump github.com/quic-go/quic-go from 0.43.1 to 0.44.0
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.43.1 to 0.44.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.43.1...v0.44.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 00:00:56 -04:00
yuhan6665
121eb7b4fc Splice update timer to 8 hours for inbound timer 2024-05-19 23:56:42 -04:00
yuhan6665
3168d27b0b Splice update timer to 8 hours 2024-05-18 11:57:11 -04:00
风扇滑翔翼
b98d060ee0 Improve the issue templates 2024-05-15 10:29:41 -04:00
dependabot[bot]
26d49df22e Bump google.golang.org/grpc from 1.63.2 to 1.64.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.63.2 to 1.64.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.63.2...v1.64.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-14 21:42:51 -04:00
yuhan6665
1d450cfbd2 Fix nil in inbound handler 2024-05-14 21:42:40 -04:00
yuhan6665
017f53b5fc Add session context outbounds as slice (#3356)
* Add session context outbounds as slice

slice is needed for dialer proxy where two outbounds work on top of each other
There are two sets of target addr for example
It also enable Xtls to correctly do splice copy by checking both outbounds are ready to do direct copy

* Fill outbound tag info

* Splice now checks capalibility from all outbounds

* Fix unit tests
2024-05-13 21:52:24 -04:00
dependabot[bot]
0735053348 Bump golang.org/x/net from 0.24.0 to 0.25.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](https://github.com/golang/net/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 23:48:13 -04:00
dependabot[bot]
e41a61c6f7 Bump google.golang.org/protobuf from 1.34.0 to 1.34.1
Bumps google.golang.org/protobuf from 1.34.0 to 1.34.1.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 23:48:03 -04:00
dependabot[bot]
a9715295b8 Bump github.com/refraction-networking/utls from 1.6.5 to 1.6.6
Bumps [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) from 1.6.5 to 1.6.6.
- [Release notes](https://github.com/refraction-networking/utls/releases)
- [Commits](https://github.com/refraction-networking/utls/compare/v1.6.5...v1.6.6)

---
updated-dependencies:
- dependency-name: github.com/refraction-networking/utls
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-05 21:54:14 -04:00
dependabot[bot]
f0b0a7cd4b Bump golang.org/x/sys from 0.19.0 to 0.20.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.19.0 to 0.20.0.
- [Commits](https://github.com/golang/sys/compare/v0.19.0...v0.20.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-05 21:53:01 -04:00
dependabot[bot]
cefae55d7c Bump github.com/quic-go/quic-go from 0.43.0 to 0.43.1
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.43.0 to 0.43.1.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.43.0...v0.43.1)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-05 21:52:53 -04:00
yuhan6665
84eeb56ae4 Select alive only node when fallbackTag is given
- Apply to random and roundrobin strategy
- Require observatory config

Co-authored-by: Mark Ma <38940419+mkmark@users.noreply.github.com>
2024-05-05 10:11:29 -04:00
dependabot[bot]
eba2906d3a Bump github.com/refraction-networking/utls from 1.6.4 to 1.6.5
Bumps [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) from 1.6.4 to 1.6.5.
- [Release notes](https://github.com/refraction-networking/utls/releases)
- [Commits](https://github.com/refraction-networking/utls/compare/v1.6.4...v1.6.5)

---
updated-dependencies:
- dependency-name: github.com/refraction-networking/utls
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-03 14:03:47 -04:00
dependabot[bot]
cc2849025d Bump lukechampine.com/blake3 from 1.2.2 to 1.3.0
Bumps [lukechampine.com/blake3](https://github.com/lukechampine/blake3) from 1.2.2 to 1.3.0.
- [Commits](https://github.com/lukechampine/blake3/compare/v1.2.2...v1.3.0)

---
updated-dependencies:
- dependency-name: lukechampine.com/blake3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-03 14:03:38 -04:00
dependabot[bot]
c1ad35fba8 Bump google.golang.org/protobuf from 1.33.0 to 1.34.0
Bumps google.golang.org/protobuf from 1.33.0 to 1.34.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-01 21:24:32 -04:00
nobody
447a49d16a Add configuration item api->listen. (#3317)
* add api.listen configuration item

* add unit tests

* typo

---------

Co-authored-by: nobody <nobody@nowhere.mars>
2024-05-01 21:23:55 -04:00
dependabot[bot]
51504c624c Bump github.com/quic-go/quic-go from 0.42.0 to 0.43.0
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.42.0 to 0.43.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.42.0...v0.43.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-28 21:54:54 -04:00
Kobe Arthur Scofield
98a2e2c7a1 Adding notes for critical build file (#3308)
* Adding notes for critical build file

* Got trapped by Tabs and fix it
2024-04-28 19:13:59 -04:00
RPRX
a476310aec README: Remove iamybj/docker-xray
https://github.com/XTLS/Xray-core/pull/2459#issuecomment-2079354739

Fixes https://github.com/XTLS/Xray-core/issues/2837
2024-04-26 14:07:35 +00:00
RPRX
b8924782a1 Revert "Makefile: export GOARCH, GOOS"
https://github.com/XTLS/Xray-core/pull/3275#issuecomment-2079093724

Fixes https://github.com/XTLS/Xray-core/issues/3305
2024-04-26 10:28:15 +00:00
422 changed files with 5399 additions and 3159 deletions

View File

@@ -9,36 +9,81 @@ body:
options: options:
- label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values. - label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values.
required: true required: true
- label: I provided the complete config and logs, rather than just providing the truncated parts based on my own judgment.
required: true
- label: I searched issues and did not find any similar issues. - label: I searched issues and did not find any similar issues.
required: true required: true
- type: textarea - type: input
attributes: attributes:
label: Version label: Version
description: Xray-core version description: Version of Xray-core
render: shell validations:
required: true
- type: textarea - type: textarea
attributes: attributes:
label: Description label: Description
description: Please provide a detailed description of the bug. And information that you consider valuable. description: Please provide a detailed description of the error. And the information you think valuable.
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: Reproduction label: Reproduction Method
description: |- description: |-
Provide method to reproduce the bug. Based on the configuration you provided below, provide the method to reproduce the bug.
Please provide config that can reproduce the problem, including both the server and client. validations:
Do not paste a large exported config here. Removing unnecessary inbounds, outbounds, route rules, and options. This cloud help us locate the problem if you really want to get help. required: true
Even if you are using a GUI/script/panel, please follow the above requirements. - type: markdown
DO NOT just write "I'm using xxx GUI/ xxx panel" instead of providing config. We do not have the energy or obligation to find the software and spend time reproducing according to the description. attributes:
value: |-
## Configuration and Log Section
### For config
Please provide the configuration files that can reproduce the problem, including the server and client.
Don't just paste a big exported config file here. Eliminate useless inbound/outbound, rules, options, this can help determine the problem, if you really want to get help.
### For logs
Please set the log level to debug and dnsLog to true first.
Restart Xray-core, then operate according to the reproduction method, try to reduce the irrelevant part in the log.
Remember to delete parts with personal information (such as UUID and IP).
Provide the log of Xray-core, not the log output by the panel or other things.
### Finally
After removing parts that do not affect reproduction, provide the actual running **complete** file, do not only provide inbound or outbound or a few lines of logs based on your own judgment.
Put the content between the preset ```<details><pre><code>``` ```</code></pre></details>``` in the text box.
If the problem is very clear that only related to one end (such as core startup failure/crash after correctly writing the config according to the documents), N/A can be filled in for unnecessary areas below.
- type: textarea
attributes:
label: Client config
value: |-
<details><pre><code>
</code></pre></details>
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: log label: Server config
description: |- value: |-
Set the log level to debug. <details><pre><code>
Please Restart Xray-core, and then follow the reproduction method to reduce irrelevant parts in log.
Remember to remove personal information such as UUID, IP. </code></pre></details>
Provid complete log, DO NOT just paste the the parts that you think necessary based on your own judgment. validations:
render: shell required: true
- type: textarea
attributes:
label: Client log
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: Server log
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true

View File

@@ -9,13 +9,16 @@ body:
options: options:
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。 - label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
required: true required: true
- label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。
required: true
- label: 我搜索了issues没有发现已提出的类似问题。 - label: 我搜索了issues没有发现已提出的类似问题。
required: true required: true
- type: textarea - type: input
attributes: attributes:
label: 版本 label: 版本
description: 使用的Xray-core版本 description: 使用的Xray-core版本
render: shell validations:
required: true
- type: textarea - type: textarea
attributes: attributes:
label: 描述 label: 描述
@@ -26,19 +29,61 @@ body:
attributes: attributes:
label: 重现方式 label: 重现方式
description: |- description: |-
提供重现BUG方法。 基于你下面提供的配置,提供重现BUG方法。
请提供可以重现问题的配置文件,包括服务端和客户端 validations:
required: true
- type: markdown
attributes:
value: |-
## 配置与日志部分
### 对于配置文件
请提供可以重现问题的配置文件,包括服务端和客户端。
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。 不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
即使你在使用图形客户端/脚本/面板,也请遵照上述要求。
不要直接用“我使用xxx客户端/xxx面板”替代config我们没有精力也没有义务去找到项目再花时间按描述重新问题。 ### 对于日志
请先将日志等级设置为 debug, dnsLog 设置为true.
重启 Xray-core ,再按复现方式操作,尽量减少日志中的无关部分。
记得删除有关个人信息如UUID与IP的部分。
提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。
### 最后
在去掉不影响复现的部分后,提供实际运行的**完整**文件,不要出于自己的判断只提供入站出站或者几行日志。
把内容放在文本框预置的 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间。
如果问题十分明确只出现在某一端(如按文档正确编写配置后核心启动失败/崩溃)可以在下面不需要的项目填入N/A.
- type: textarea
attributes:
label: 客户端配置
value: |-
<details><pre><code>
</code></pre></details>
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: 日志 label: 服务端配置
description: |- value: |-
请先将日志等级设置为 debug. <details><pre><code>
重启 Xray-core ,再按复现方式操作,尽量减少日志中的无关部分。
记得删除有关个人信息如UUID与IP的部分。 </code></pre></details>
提供完整的日志,不要仅提供你自己觉得有用的部分。 validations:
render: shell required: true
- type: textarea
attributes:
label: 客户端日志
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true
- type: textarea
attributes:
label: 服务端日志
value: |-
<details><pre><code>
</code></pre></details>
validations:
required: true

4
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
contact_links:
- name: Community Support and Questions
url: https://github.com/XTLS/Xray-core/discussions
about: Please ask and answer questions there. The issue tracker is for issues with core.

View File

@@ -1,6 +1,8 @@
name: Build docker image name: Build docker image
on: on:
release:
types: [published]
push: push:
branches: branches:
- main - main
@@ -19,6 +21,7 @@ jobs:
images: ghcr.io/${{ github.repository_owner }}/xray-core images: ghcr.io/${{ github.repository_owner }}/xray-core
flavor: latest=true flavor: latest=true
tags: | tags: |
type=sha
type=ref,event=branch type=ref,event=branch
type=ref,event=pr type=ref,event=pr
type=semver,pattern={{version}} type=semver,pattern={{version}}
@@ -35,7 +38,7 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Build and push - name: Build and push
uses: docker/build-push-action@v5 uses: docker/build-push-action@v6
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64

View File

@@ -1,5 +1,11 @@
name: Build and Release name: Build and Release
# NOTE: This Github Actions file depends on the Makefile.
# Building the correct package requires the correct binaries generated by the Makefile. To
# ensure the correct output, the Makefile must accept the appropriate input and compile the
# correct file with the correct name. If you need to modify this file, please ensure it won't
# disrupt the Makefile.
on: on:
workflow_dispatch: workflow_dispatch:
release: release:
@@ -11,14 +17,14 @@ on:
- "**/*.go" - "**/*.go"
- "go.mod" - "go.mod"
- "go.sum" - "go.sum"
- ".github/workflows/*.yml" - ".github/workflows/release.yml"
pull_request: pull_request:
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
paths: paths:
- "**/*.go" - "**/*.go"
- "go.mod" - "go.mod"
- "go.sum" - "go.sum"
- ".github/workflows/*.yml" - ".github/workflows/release.yml"
jobs: jobs:
prepare: prepare:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -72,12 +78,15 @@ jobs:
# Include amd64 on all platforms. # Include amd64 on all platforms.
goos: [windows, freebsd, openbsd, linux, darwin] goos: [windows, freebsd, openbsd, linux, darwin]
goarch: [amd64, 386] goarch: [amd64, 386]
gotoolchain: [""]
patch-assetname: [""]
exclude: exclude:
# Exclude i386 on darwin # Exclude i386 on darwin
- goarch: 386 - goarch: 386
goos: darwin goos: darwin
include: include:
# BEIGIN MacOS ARM64 # BEGIN MacOS ARM64
- goos: darwin - goos: darwin
goarch: arm64 goarch: arm64
# END MacOS ARM64 # END MacOS ARM64
@@ -146,6 +155,16 @@ jobs:
goarch: arm goarch: arm
goarm: 7 goarm: 7
# END OPENBSD ARM # END OPENBSD ARM
# BEGIN Windows 7
- goos: windows
goarch: amd64
gotoolchain: 1.21.4
patch-assetname: win7-64
- goos: windows
goarch: 386
gotoolchain: 1.21.4
patch-assetname: win7-32
# END Windows 7
fail-fast: false fail-fast: false
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -160,14 +179,15 @@ jobs:
- name: Show workflow information - name: Show workflow information
run: | run: |
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json) _NAME=${{ matrix.patch-assetname }}
[ -n "$_NAME" ] || _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME" echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version: ${{ matrix.gotoolchain || '1.22' }}
check-latest: true check-latest: true
- name: Get project dependencies - name: Get project dependencies
@@ -177,7 +197,7 @@ jobs:
run: | run: |
mkdir -p build_assets mkdir -p build_assets
make make
find . -maxdepth 1 -type f -regex '.*\(wxray\|xray\|xray_softfloat\)\(\|.exe\)' -exec mv {} ./build_assets/ \; find . -maxdepth 1 -type f -regex './\(wxray\|xray\|xray_softfloat\)\(\|.exe\)' -exec mv {} ./build_assets/ \;
- name: Restore Cache - name: Restore Cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
@@ -192,6 +212,7 @@ jobs:
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
- name: Create ZIP archive - name: Create ZIP archive
if: github.event_name == 'release'
shell: bash shell: bash
run: | run: |
pushd build_assets || exit 1 pushd build_assets || exit 1

View File

@@ -32,7 +32,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version: '1.22'
check-latest: true check-latest: true
- name: Restore Cache - name: Restore Cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4

View File

@@ -2,14 +2,16 @@ NAME = xray
VERSION=$(shell git describe --always --dirty) VERSION=$(shell git describe --always --dirty)
export GOARCH ?= # NOTE: This MAKEFILE can be used to build Xray-core locally and in Automatic workflows. It is \
export GOOS ?= provided for convenience in automatic building and functions as a part of it.
# NOTE: If you need to modify this file, please be aware that:\
ifdef GOARCH - This file is not the main Makefile; it only accepts environment variables and builds the \
ifeq ($(GOOS),darwin) binary.\
NAME:=$(NAME)-$(GOARCH) - Automatic building expects the correct binaries to be built by this Makefile. If you \
endif intend to propose a change to this Makefile, carefully review the file below and ensure \
endif that the change will not accidentally break the automatic building:\
.github/workflows/release.yml \
Otherwise it is recommended to contact the project maintainers.
LDFLAGS = -X github.com/xtls/xray-core/core.build=$(VERSION) -s -w -buildid= LDFLAGS = -X github.com/xtls/xray-core/core.build=$(VERSION) -s -w -buildid=
PARAMS = -trimpath -ldflags "$(LDFLAGS)" -v PARAMS = -trimpath -ldflags "$(LDFLAGS)" -v
@@ -21,18 +23,15 @@ ADDITION = go build -o w$(NAME).exe -trimpath -ldflags "-H windowsgui $(LDFLAGS)
else else
OUTPUT = $(NAME) OUTPUT = $(NAME)
endif endif
ifeq ($(shell echo "$(GOARCH)" | grep -Pq "(mips|mipsle)" && echo true),true) # ifeq ($(shell echo "$(GOARCH)" | grep -Eq "(mips|mipsle)" && echo true),true) #
ADDITION = GOMIPS=softfloat go build -o $(NAME)_softfloat -trimpath -ldflags "$(LDFLAGS)" -v $(MAIN) ADDITION = GOMIPS=softfloat go build -o $(NAME)_softfloat -trimpath -ldflags "$(LDFLAGS)" -v $(MAIN)
endif endif
.PHONY: clean .PHONY: clean build
build: build:
go build -o $(OUTPUT) $(PARAMS) $(MAIN) go build -o $(OUTPUT) $(PARAMS) $(MAIN)
$(ADDITION) $(ADDITION)
install:
go build -o $(PREFIX)/bin/$(OUTPUT) $(PARAMS) $(MAIN)
clean: clean:
go clean -v -i $(PWD) go clean -v -i $(PWD)
rm -f xray xray.exe wxray.exe xray_softfloat rm -f xray xray.exe wxray.exe xray_softfloat

View File

@@ -21,15 +21,13 @@
## Installation ## Installation
- Linux Script - Linux Script
- [XTLS/Xray-install](https://github.com/XTLS/Xray-install) - [XTLS/Xray-install](https://github.com/XTLS/Xray-install) (**Official**)
- [team-cloudchaser/tempest](https://github.com/team-cloudchaser/tempest) (supports [`systemd`](https://systemd.io) and [OpenRC](https://github.com/OpenRC/openrc); Linux-only) - [tempest](https://github.com/team-cloudchaser/tempest) (supports [`systemd`](https://systemd.io) and [OpenRC](https://github.com/OpenRC/openrc); Linux-only)
- Docker - Docker
- Official: [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) - [ghcr.io/xtls/xray-core](https://ghcr.io/xtls/xray-core) (**Official**)
- [iamybj/docker-xray](https://hub.docker.com/r/iamybj/docker-xray)
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray) - [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
- Web Panel - Web Panel
- [X-UI-English](https://github.com/NidukaAkalanka/x-ui-english), [3X-UI](https://github.com/MHSanaei/3x-ui), [X-UI](https://github.com/alireza0/x-ui), [X-UI](https://github.com/diditra/x-ui) - [3X-UI](https://github.com/MHSanaei/3x-ui), [X-UI](https://github.com/alireza0/x-ui), [Xray-UI](https://github.com/qist/xray-ui)
- [Xray-UI](https://github.com/qist/xray-ui), [X-UI](https://github.com/sing-web/x-ui)
- [Hiddify](https://github.com/hiddify/hiddify-config) - [Hiddify](https://github.com/hiddify/hiddify-config)
- [Marzban](https://github.com/Gozargah/Marzban) - [Marzban](https://github.com/Gozargah/Marzban)
- [Libertea](https://github.com/VZiChoushaDui/Libertea) - [Libertea](https://github.com/VZiChoushaDui/Libertea)
@@ -68,13 +66,10 @@
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray)) - [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
- Windows - Windows
- [v2rayN](https://github.com/2dust/v2rayN) - [v2rayN](https://github.com/2dust/v2rayN)
- [NekoRay](https://github.com/Matsuridayo/nekoray)
- [Furious](https://github.com/LorenEteval/Furious) - [Furious](https://github.com/LorenEteval/Furious)
- [HiddifyN](https://github.com/hiddify/HiddifyN)
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient) - [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
- Android - Android
- [v2rayNG](https://github.com/2dust/v2rayNG) - [v2rayNG](https://github.com/2dust/v2rayNG)
- [HiddifyNG](https://github.com/hiddify/HiddifyNG)
- [X-flutter](https://github.com/XTLS/X-flutter) - [X-flutter](https://github.com/XTLS/X-flutter)
- iOS & macOS arm64 - iOS & macOS arm64
- [FoXray](https://apps.apple.com/app/foxray/id6448898396) - [FoXray](https://apps.apple.com/app/foxray/id6448898396)
@@ -86,7 +81,6 @@
- [FoXray](https://apps.apple.com/app/foxray/id6448898396) - [FoXray](https://apps.apple.com/app/foxray/id6448898396)
- Linux - Linux
- [v2rayA](https://github.com/v2rayA/v2rayA) - [v2rayA](https://github.com/v2rayA/v2rayA)
- [NekoRay](https://github.com/Matsuridayo/nekoray)
- [Furious](https://github.com/LorenEteval/Furious) - [Furious](https://github.com/LorenEteval/Furious)
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX... ## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
@@ -99,21 +93,15 @@
- [XTLS/libXray](https://github.com/XTLS/libXray) - [XTLS/libXray](https://github.com/XTLS/libXray)
- [xtlsapi](https://github.com/hiddify/xtlsapi) - [xtlsapi](https://github.com/hiddify/xtlsapi)
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite) - [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
- [XrayKit](https://github.com/arror/XrayKit)
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python) - [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
- [xray-api](https://github.com/XVGuardian/xray-api) - [xray-api](https://github.com/XVGuardian/xray-api)
- [XrayR](https://github.com/XrayR-project/XrayR) - [XrayR](https://github.com/XrayR-project/XrayR)
- [XrayR-release](https://github.com/XrayR-project/XrayR-release) - [XrayR-release](https://github.com/XrayR-project/XrayR-release)
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board) - [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
- [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta) - [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta)
- [Clash Verge](https://github.com/zzzgydi/clash-verge)
- [clashN](https://github.com/2dust/clashN) - [clashN](https://github.com/2dust/clashN)
- [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid) - [Clash Meta for Android](https://github.com/MetaCubeX/ClashMetaForAndroid)
- [meta_for_ios](https://t.me/meta_for_ios)
- [sing-box](https://github.com/SagerNet/sing-box) - [sing-box](https://github.com/SagerNet/sing-box)
- [installReality](https://github.com/BoxXt/installReality)
- [sbox-reality](https://github.com/Misaka-blog/sbox-reality)
- [sing-box-for-ios](https://github.com/SagerNet/sing-box-for-ios)
## Contributing ## Contributing

View File

@@ -8,6 +8,7 @@ import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
@@ -21,12 +22,14 @@ type Commander struct {
services []Service services []Service
ohm outbound.Manager ohm outbound.Manager
tag string tag string
listen string
} }
// NewCommander creates a new Commander based on the given config. // NewCommander creates a new Commander based on the given config.
func NewCommander(ctx context.Context, config *Config) (*Commander, error) { func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
c := &Commander{ c := &Commander{
tag: config.Tag, tag: config.Tag,
listen: config.Listen,
} }
common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) { common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) {
@@ -44,7 +47,7 @@ func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
} }
service, ok := rawService.(Service) service, ok := rawService.(Service)
if !ok { if !ok {
return nil, newError("not a Service.") return nil, errors.New("not a Service.")
} }
c.services = append(c.services, service) c.services = append(c.services, service)
} }
@@ -66,19 +69,32 @@ func (c *Commander) Start() error {
} }
c.Unlock() c.Unlock()
var listen = func(listener net.Listener) {
if err := c.server.Serve(listener); err != nil {
errors.LogErrorInner(context.Background(), err, "failed to start grpc server")
}
}
if len(c.listen) > 0 {
if l, err := net.Listen("tcp", c.listen); err != nil {
errors.LogErrorInner(context.Background(), err, "API server failed to listen on ", c.listen)
return err
} else {
errors.LogInfo(context.Background(), "API server listening on ", l.Addr())
go listen(l)
}
return nil
}
listener := &OutboundListener{ listener := &OutboundListener{
buffer: make(chan net.Conn, 4), buffer: make(chan net.Conn, 4),
done: done.New(), done: done.New(),
} }
go func() { go listen(listener)
if err := c.server.Serve(listener); err != nil {
newError("failed to start grpc server").Base(err).AtError().WriteToLog()
}
}()
if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil { if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil {
newError("failed to remove existing handler").WriteToLog() errors.LogInfoInner(context.Background(), err, "failed to remove existing handler")
} }
return c.ohm.AddHandler(context.Background(), &Outbound{ return c.ohm.AddHandler(context.Background(), &Outbound{

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/commander/config.proto // source: app/commander/config.proto
package commander package commander
@@ -29,6 +29,8 @@ type Config struct {
// Tag of the outbound handler that handles grpc connections. // Tag of the outbound handler that handles grpc connections.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
// Network address of commander grpc service.
Listen string `protobuf:"bytes,3,opt,name=listen,proto3" json:"listen,omitempty"`
// Services that supported by this server. All services must implement Service // Services that supported by this server. All services must implement Service
// interface. // interface.
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"` Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
@@ -73,6 +75,13 @@ func (x *Config) GetTag() string {
return "" return ""
} }
func (x *Config) GetListen() string {
if x != nil {
return x.Listen
}
return ""
}
func (x *Config) GetService() []*serial.TypedMessage { func (x *Config) GetService() []*serial.TypedMessage {
if x != nil { if x != nil {
return x.Service return x.Service
@@ -127,20 +136,21 @@ var file_app_commander_config_proto_rawDesc = []byte{
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72,
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x6f, 0x74, 0x6f, 0x22, 0x6e, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a,
0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,
0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x16, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x3a, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x67, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79,
0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76,
0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x69, 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x72, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x12, 0x58,
0x33, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65,
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -12,6 +12,10 @@ import "common/serial/typed_message.proto";
message Config { message Config {
// Tag of the outbound handler that handles grpc connections. // Tag of the outbound handler that handles grpc connections.
string tag = 1; string tag = 1;
// Network address of commander grpc service.
string listen = 3;
// Services that supported by this server. All services must implement Service // Services that supported by this server. All services must implement Service
// interface. // interface.
repeated xray.common.serial.TypedMessage service = 2; repeated xray.common.serial.TypedMessage service = 2;

View File

@@ -1,9 +0,0 @@
package commander
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -5,6 +5,7 @@ import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc" "github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
@@ -31,7 +32,7 @@ func (l *OutboundListener) add(conn net.Conn) {
func (l *OutboundListener) Accept() (net.Conn, error) { func (l *OutboundListener) Accept() (net.Conn, error) {
select { select {
case <-l.done.Wait(): case <-l.done.Wait():
return nil, newError("listen closed") return nil, errors.New("listen closed")
case c := <-l.buffer: case c := <-l.buffer:
return c, nil return c, nil
} }

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/dispatcher/config.proto // source: app/dispatcher/config.proto
package dispatcher package dispatcher

View File

@@ -4,11 +4,13 @@ package dispatcher
import ( import (
"context" "context"
"regexp"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -25,7 +27,7 @@ import (
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
) )
var errSniffingTimeout = newError("timeout on sniffing") var errSniffingTimeout = errors.New("timeout on sniffing")
type cachedReader struct { type cachedReader struct {
sync.Mutex sync.Mutex
@@ -186,10 +188,22 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
return false return false
} }
for _, d := range request.ExcludeForDomain { for _, d := range request.ExcludeForDomain {
if strings.HasPrefix(d, "regexp:") {
pattern := d[7:]
re, err := regexp.Compile(pattern)
if err != nil {
errors.LogInfo(ctx, "Unable to compile regex")
continue
}
if re.MatchString(domain) {
return false
}
} else {
if strings.ToLower(domain) == d { if strings.ToLower(domain) == d {
return false return false
} }
} }
}
protocolString := result.Protocol() protocolString := result.Protocol()
if resComp, ok := result.(SnifferResultComposite); ok { if resComp, ok := result.(SnifferResultComposite); ok {
protocolString = resComp.ProtocolForDomainResult() protocolString = resComp.ProtocolForDomainResult()
@@ -200,7 +214,7 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
} }
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" && if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
fkr0.IsIPInIPPool(destination.Address) { fkr0.IsIPInIPPool(destination.Address) {
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "Using sniffer ", protocolString, " since the fake DNS missed")
return true return true
} }
if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok { if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok {
@@ -218,11 +232,12 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
if !destination.IsValid() { if !destination.IsValid() {
panic("Dispatcher: Invalid destination.") panic("Dispatcher: Invalid destination.")
} }
ob := session.OutboundFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
if ob == nil { if len(outbounds) == 0 {
ob = &session.Outbound{} outbounds = []*session.Outbound{{}}
ctx = session.ContextWithOutbound(ctx, ob) ctx = session.ContextWithOutbounds(ctx, outbounds)
} }
ob := outbounds[len(outbounds)-1]
ob.OriginalTarget = destination ob.OriginalTarget = destination
ob.Target = destination ob.Target = destination
content := session.ContentFromContext(ctx) content := session.ContentFromContext(ctx)
@@ -247,7 +262,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
} }
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) { if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain() domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "sniffed domain: ", domain)
destination.Address = net.ParseAddress(domain) destination.Address = net.ParseAddress(domain)
protocol := result.Protocol() protocol := result.Protocol()
if resComp, ok := result.(SnifferResultComposite); ok { if resComp, ok := result.(SnifferResultComposite); ok {
@@ -272,13 +287,14 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
// DispatchLink implements routing.Dispatcher. // DispatchLink implements routing.Dispatcher.
func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.Destination, outbound *transport.Link) error { func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.Destination, outbound *transport.Link) error {
if !destination.IsValid() { if !destination.IsValid() {
return newError("Dispatcher: Invalid destination.") return errors.New("Dispatcher: Invalid destination.")
} }
ob := session.OutboundFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
if ob == nil { if len(outbounds) == 0 {
ob = &session.Outbound{} outbounds = []*session.Outbound{{}}
ctx = session.ContextWithOutbound(ctx, ob) ctx = session.ContextWithOutbounds(ctx, outbounds)
} }
ob := outbounds[len(outbounds)-1]
ob.OriginalTarget = destination ob.OriginalTarget = destination
ob.Target = destination ob.Target = destination
content := session.ContentFromContext(ctx) content := session.ContentFromContext(ctx)
@@ -300,7 +316,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
} }
if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) { if err == nil && d.shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain() domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "sniffed domain: ", domain)
destination.Address = net.ParseAddress(domain) destination.Address = net.ParseAddress(domain)
protocol := result.Protocol() protocol := result.Protocol()
if resComp, ok := result.(SnifferResultComposite); ok { if resComp, ok := result.(SnifferResultComposite); ok {
@@ -368,7 +384,8 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
return contentResult, contentErr return contentResult, contentErr
} }
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) { func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
ob := session.OutboundFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() { if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
proxied := hosts.LookupHosts(ob.Target.String()) proxied := hosts.LookupHosts(ob.Target.String())
if proxied != nil { if proxied != nil {
@@ -391,10 +408,10 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
ctx = session.SetForcedOutboundTagToContext(ctx, "") ctx = session.SetForcedOutboundTagToContext(ctx, "")
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil { if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
isPickRoute = 1 isPickRoute = 1
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]")
handler = h handler = h
} else { } else {
newError("non existing tag for platform initialized detour: ", forcedOutboundTag).AtError().WriteToLog(session.ExportIDToError(ctx)) errors.LogError(ctx, "non existing tag for platform initialized detour: ", forcedOutboundTag)
common.Close(link.Writer) common.Close(link.Writer)
common.Interrupt(link.Reader) common.Interrupt(link.Reader)
return return
@@ -404,13 +421,13 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
outTag := route.GetOutboundTag() outTag := route.GetOutboundTag()
if h := d.ohm.GetHandler(outTag); h != nil { if h := d.ohm.GetHandler(outTag); h != nil {
isPickRoute = 2 isPickRoute = 2
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
handler = h handler = h
} else { } else {
newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx)) errors.LogWarning(ctx, "non existing outTag: ", outTag)
} }
} else { } else {
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "default route for ", destination)
} }
} }
@@ -419,12 +436,13 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
} }
if handler == nil { if handler == nil {
newError("default outbound handler not exist").WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "default outbound handler not exist")
common.Close(link.Writer) common.Close(link.Writer)
common.Interrupt(link.Reader) common.Interrupt(link.Reader)
return return
} }
ob.Tag = handler.Tag()
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil { if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
if tag := handler.Tag(); tag != "" { if tag := handler.Tag(); tag != "" {
if inTag == "" { if inTag == "" {

View File

@@ -1,9 +0,0 @@
package dispatcher
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -5,6 +5,7 @@ import (
"strings" "strings"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -22,15 +23,16 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
} }
if fakeDNSEngine == nil { if fakeDNSEngine == nil {
errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError() errNotInit := errors.New("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
return protocolSnifferWithMetadata{}, errNotInit return protocolSnifferWithMetadata{}, errNotInit
} }
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) { return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
Target := session.OutboundFromContext(ctx).Target outbounds := session.OutboundsFromContext(ctx)
if Target.Network == net.Network_TCP || Target.Network == net.Network_UDP { ob := outbounds[len(outbounds) - 1]
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(Target.Address) if ob.Target.Network == net.Network_TCP || ob.Target.Network == net.Network_UDP {
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(ob.Target.Address)
if domainFromFakeDNS != "" { if domainFromFakeDNS != "" {
newError("fake dns got domain: ", domainFromFakeDNS, " for ip: ", Target.Address.String()).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, "fake dns got domain: ", domainFromFakeDNS, " for ip: ", ob.Target.Address.String())
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
} }
} }
@@ -38,7 +40,7 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil { if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {
ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt) ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok { if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
inPool := fkr0.IsIPInIPPool(Target.Address) inPool := fkr0.IsIPInIPPool(ob.Target.Address)
ipAddressInRangeValue.addressInRange = &inPool ipAddressInRangeValue.addressInRange = &inPool
} }
} }
@@ -108,10 +110,10 @@ func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWit
} }
return nil, common.ErrNoClue return nil, common.ErrNoClue
} }
newError("ip address not in fake dns range, return as is").AtDebug().WriteToLog() errors.LogDebug(ctx, "ip address not in fake dns range, return as is")
return nil, common.ErrNoClue return nil, common.ErrNoClue
} }
newError("fake dns sniffer did not set address in range option, assume false.").AtWarning().WriteToLog() errors.LogWarning(ctx, "fake dns sniffer did not set address in range option, assume false.")
return nil, common.ErrNoClue return nil, common.ErrNoClue
}, },
metadataSniffer: false, metadataSniffer: false,

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol/bittorrent" "github.com/xtls/xray-core/common/protocol/bittorrent"
"github.com/xtls/xray-core/common/protocol/http" "github.com/xtls/xray-core/common/protocol/http"
@@ -52,7 +53,7 @@ func NewSniffer(ctx context.Context) *Sniffer {
return ret return ret
} }
var errUnknownContent = newError("unknown content") var errUnknownContent = errors.New("unknown content")
func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) { func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
var pendingSniffer []protocolSnifferWithMetadata var pendingSniffer []protocolSnifferWithMetadata

View File

@@ -1,6 +1,7 @@
package dns package dns
import ( import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher" "github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/common/uuid"
@@ -36,11 +37,11 @@ var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) { func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
strMType, f := typeMap[t] strMType, f := typeMap[t]
if !f { if !f {
return nil, newError("unknown mapping type", t).AtWarning() return nil, errors.New("unknown mapping type", t).AtWarning()
} }
matcher, err := strMType.New(domain) matcher, err := strMType.New(domain)
if err != nil { if err != nil {
return nil, newError("failed to create str matcher").Base(err) return nil, errors.New("failed to create str matcher").Base(err)
} }
return matcher, nil return matcher, nil
} }
@@ -51,7 +52,7 @@ func toNetIP(addrs []net.Address) ([]net.IP, error) {
if addr.Family().IsIP() { if addr.Family().IsIP() {
ips = append(ips, addr.IP()) ips = append(ips, addr.IP())
} else { } else {
return nil, newError("Failed to convert address", addr, "to Net IP.").AtWarning() return nil, errors.New("Failed to convert address", addr, "to Net IP.").AtWarning()
} }
} }
return ips, nil return ips, nil

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/dns/config.proto // source: app/dns/config.proto
package dns package dns

View File

@@ -54,7 +54,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
case 0, net.IPv4len, net.IPv6len: case 0, net.IPv4len, net.IPv6len:
clientIP = net.IP(config.ClientIp) clientIP = net.IP(config.ClientIp)
default: default:
return nil, newError("unexpected client IP length ", len(config.ClientIp)) return nil, errors.New("unexpected client IP length ", len(config.ClientIp))
} }
var ipOption *dns.IPOption var ipOption *dns.IPOption
@@ -81,7 +81,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts) hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts)
if err != nil { if err != nil {
return nil, newError("failed to create hosts").Base(err) return nil, errors.New("failed to create hosts").Base(err)
} }
clients := []*Client{} clients := []*Client{}
@@ -99,7 +99,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
features.PrintDeprecatedFeatureWarning("simple DNS server") features.PrintDeprecatedFeatureWarning("simple DNS server")
client, err := NewSimpleClient(ctx, endpoint, clientIP) client, err := NewSimpleClient(ctx, endpoint, clientIP)
if err != nil { if err != nil {
return nil, newError("failed to create client").Base(err) return nil, errors.New("failed to create client").Base(err)
} }
clients = append(clients, client) clients = append(clients, client)
} }
@@ -122,7 +122,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
} }
client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain) client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain)
if err != nil { if err != nil {
return nil, newError("failed to create client").Base(err) return nil, errors.New("failed to create client").Base(err)
} }
clients = append(clients, client) clients = append(clients, client)
} }
@@ -170,7 +170,7 @@ func (s *DNS) IsOwnLink(ctx context.Context) bool {
// LookupIP implements dns.Client. // LookupIP implements dns.Client.
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) { func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
if domain == "" { if domain == "" {
return nil, newError("empty domain name") return nil, errors.New("empty domain name")
} }
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
@@ -190,10 +190,10 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled) case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
return nil, dns.ErrEmptyResponse return nil, dns.ErrEmptyResponse
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
newError("domain replaced: ", domain, " -> ", addrs[0].Domain()).WriteToLog() errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].Domain())
domain = addrs[0].Domain() domain = addrs[0].Domain()
default: // Successfully found ip records in static host default: // Successfully found ip records in static host
newError("returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs).WriteToLog() errors.LogInfo(s.ctx, "returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs)
return toNetIP(addrs) return toNetIP(addrs)
} }
@@ -202,7 +202,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag}) ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
for _, client := range s.sortClients(domain) { for _, client := range s.sortClients(domain) {
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") { if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
newError("skip DNS resolution for domain ", domain, " at server ", client.Name()).AtDebug().WriteToLog() errors.LogDebug(s.ctx, "skip DNS resolution for domain ", domain, " at server ", client.Name())
continue continue
} }
ips, err := client.QueryIP(ctx, domain, option, s.disableCache) ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
@@ -210,7 +210,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
return ips, nil return ips, nil
} }
if err != nil { if err != nil {
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog() errors.LogInfoInner(s.ctx, err, "failed to lookup ip for domain ", domain, " at server ", client.Name())
errs = append(errs, err) errs = append(errs, err)
} }
// 5 for RcodeRefused in miekg/dns, hardcode to reduce binary size // 5 for RcodeRefused in miekg/dns, hardcode to reduce binary size
@@ -219,7 +219,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
} }
} }
return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...)) return nil, errors.New("returning nil for domain ", domain).Base(errors.Combine(errs...))
} }
// LookupHosts implements dns.HostsLookup. // LookupHosts implements dns.HostsLookup.
@@ -231,7 +231,7 @@ func (s *DNS) LookupHosts(domain string) *net.Address {
// Normalize the FQDN form query // Normalize the FQDN form query
addrs := s.hosts.Lookup(domain, *s.ipOption) addrs := s.hosts.Lookup(domain, *s.ipOption)
if len(addrs) > 0 { if len(addrs) > 0 {
newError("domain replaced: ", domain, " -> ", addrs[0].String()).AtInfo().WriteToLog() errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].String())
return &addrs[0] return &addrs[0]
} }
@@ -289,16 +289,16 @@ func (s *DNS) sortClients(domain string) []*Client {
} }
if len(domainRules) > 0 { if len(domainRules) > 0 {
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog() errors.LogDebug(s.ctx, "domain ", domain, " matches following rules: ", domainRules)
} }
if len(clientNames) > 0 { if len(clientNames) > 0 {
newError("domain ", domain, " will use DNS in order: ", clientNames).AtDebug().WriteToLog() errors.LogDebug(s.ctx, "domain ", domain, " will use DNS in order: ", clientNames)
} }
if len(clients) == 0 { if len(clients) == 0 {
clients = append(clients, s.clients[0]) clients = append(clients, s.clients[0])
clientNames = append(clientNames, s.clients[0].Name()) clientNames = append(clientNames, s.clients[0].Name())
newError("domain ", domain, " will use the first DNS: ", clientNames).AtDebug().WriteToLog() errors.LogDebug(s.ctx, "domain ", domain, " will use the first DNS: ", clientNames)
} }
return clients return clients

View File

@@ -171,10 +171,10 @@ func parseResponse(payload []byte) (*IPRecord, error) {
var parser dnsmessage.Parser var parser dnsmessage.Parser
h, err := parser.Start(payload) h, err := parser.Start(payload)
if err != nil { if err != nil {
return nil, newError("failed to parse DNS response").Base(err).AtWarning() return nil, errors.New("failed to parse DNS response").Base(err).AtWarning()
} }
if err := parser.SkipAllQuestions(); err != nil { if err := parser.SkipAllQuestions(); err != nil {
return nil, newError("failed to skip questions in DNS response").Base(err).AtWarning() return nil, errors.New("failed to skip questions in DNS response").Base(err).AtWarning()
} }
now := time.Now() now := time.Now()
@@ -189,7 +189,7 @@ L:
ah, err := parser.AnswerHeader() ah, err := parser.AnswerHeader()
if err != nil { if err != nil {
if err != dnsmessage.ErrSectionDone { if err != dnsmessage.ErrSectionDone {
newError("failed to parse answer section for domain: ", ah.Name.String()).Base(err).WriteToLog() errors.LogInfoInner(context.Background(), err, "failed to parse answer section for domain: ", ah.Name.String())
} }
break break
} }
@@ -207,20 +207,20 @@ L:
case dnsmessage.TypeA: case dnsmessage.TypeA:
ans, err := parser.AResource() ans, err := parser.AResource()
if err != nil { if err != nil {
newError("failed to parse A record for domain: ", ah.Name).Base(err).WriteToLog() errors.LogInfoInner(context.Background(), err, "failed to parse A record for domain: ", ah.Name)
break L break L
} }
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:])) ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]))
case dnsmessage.TypeAAAA: case dnsmessage.TypeAAAA:
ans, err := parser.AAAAResource() ans, err := parser.AAAAResource()
if err != nil { if err != nil {
newError("failed to parse AAAA record for domain: ", ah.Name).Base(err).WriteToLog() errors.LogInfoInner(context.Background(), err, "failed to parse AAAA record for domain: ", ah.Name)
break L break L
} }
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:])) ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
default: default:
if err := parser.SkipAnswer(); err != nil { if err := parser.SkipAnswer(); err != nil {
newError("failed to skip answer").Base(err).WriteToLog() errors.LogInfoInner(context.Background(), err, "failed to skip answer")
break L break L
} }
continue continue

View File

@@ -1,9 +0,0 @@
package dns
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,9 +0,0 @@
package fakedns
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/cache" "github.com/xtls/xray-core/common/cache"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
) )
@@ -45,7 +46,7 @@ func (fkdns *Holder) Start() error {
if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 { if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 {
return fkdns.initializeFromConfig() return fkdns.initializeFromConfig()
} }
return newError("invalid fakeDNS setting") return errors.New("invalid fakeDNS setting")
} }
func (fkdns *Holder) Close() error { func (fkdns *Holder) Close() error {
@@ -60,7 +61,7 @@ func NewFakeDNSHolder() (*Holder, error) {
var err error var err error
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil { if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
return nil, newError("Unable to create Fake Dns Engine").Base(err).AtError() return nil, errors.New("Unable to create Fake Dns Engine").Base(err).AtError()
} }
err = fkdns.initialize(dns.FakeIPv4Pool, 65535) err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
if err != nil { if err != nil {
@@ -82,13 +83,13 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
var err error var err error
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil { if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
return newError("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError() return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
} }
ones, bits := ipRange.Mask.Size() ones, bits := ipRange.Mask.Size()
rooms := bits - ones rooms := bits - ones
if math.Log2(float64(lruSize)) >= float64(rooms) { if math.Log2(float64(lruSize)) >= float64(rooms) {
return newError("LRU size is bigger than subnet size").AtError() return errors.New("LRU size is bigger than subnet size").AtError()
} }
fkdns.domainToIP = cache.NewLru(lruSize) fkdns.domainToIP = cache.NewLru(lruSize)
fkdns.ipRange = ipRange fkdns.ipRange = ipRange
@@ -137,7 +138,7 @@ func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok { if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok {
return k.(string) return k.(string)
} }
newError("A fake ip request to ", ip, ", however there is no matching domain name in fake DNS").AtInfo().WriteToLog() errors.LogInfo(context.Background(), "A fake ip request to ", ip, ", however there is no matching domain name in fake DNS")
return "" return ""
} }
@@ -192,10 +193,10 @@ func (h *HolderMulti) Start() error {
for _, v := range h.holders { for _, v := range h.holders {
if v.config != nil && v.config.IpPool != "" && v.config.LruSize != 0 { if v.config != nil && v.config.IpPool != "" && v.config.LruSize != 0 {
if err := v.Start(); err != nil { if err := v.Start(); err != nil {
return newError("Cannot start all fake dns pools").Base(err) return errors.New("Cannot start all fake dns pools").Base(err)
} }
} else { } else {
return newError("invalid fakeDNS setting") return errors.New("invalid fakeDNS setting")
} }
} }
return nil return nil
@@ -204,7 +205,7 @@ func (h *HolderMulti) Start() error {
func (h *HolderMulti) Close() error { func (h *HolderMulti) Close() error {
for _, v := range h.holders { for _, v := range h.holders {
if err := v.Close(); err != nil { if err := v.Close(); err != nil {
return newError("Cannot close all fake dns pools").Base(err) return errors.New("Cannot close all fake dns pools").Base(err)
} }
} }
return nil return nil

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/dns/fakedns/fakedns.proto // source: app/dns/fakedns/fakedns.proto
package fakedns package fakedns

View File

@@ -1,7 +1,10 @@
package dns package dns
import ( import (
"context"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher" "github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features" "github.com/xtls/xray-core/features"
@@ -32,7 +35,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
address := ip.AsAddress() address := ip.AsAddress()
if address.Family().IsDomain() { if address.Family().IsDomain() {
return nil, newError("invalid domain address in static hosts: ", address.Domain()).AtWarning() return nil, errors.New("invalid domain address in static hosts: ", address.Domain()).AtWarning()
} }
sh.ips[id] = []net.Address{address} sh.ips[id] = []net.Address{address}
@@ -42,7 +45,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
for _, mapping := range hosts { for _, mapping := range hosts {
matcher, err := toStrMatcher(mapping.Type, mapping.Domain) matcher, err := toStrMatcher(mapping.Type, mapping.Domain)
if err != nil { if err != nil {
return nil, newError("failed to create domain matcher").Base(err) return nil, errors.New("failed to create domain matcher").Base(err)
} }
id := g.Add(matcher) id := g.Add(matcher)
ips := make([]net.Address, 0, len(mapping.Ip)+1) ips := make([]net.Address, 0, len(mapping.Ip)+1)
@@ -53,12 +56,12 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
for _, ip := range mapping.Ip { for _, ip := range mapping.Ip {
addr := net.IPAddress(ip) addr := net.IPAddress(ip)
if addr == nil { if addr == nil {
return nil, newError("invalid IP address in static hosts: ", ip).AtWarning() return nil, errors.New("invalid IP address in static hosts: ", ip).AtWarning()
} }
ips = append(ips, addr) ips = append(ips, addr)
} }
default: default:
return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning() return nil, errors.New("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
} }
sh.ips[id] = ips sh.ips[id] = ips
@@ -90,7 +93,7 @@ func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) [
case len(addrs) == 0: // Not recorded in static hosts, return nil case len(addrs) == 0: // Not recorded in static hosts, return nil
return nil return nil
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
newError("found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it").AtDebug().WriteToLog() errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
if maxDepth > 0 { if maxDepth > 0 {
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1) unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
if unwrapped != nil { if unwrapped != nil {

View File

@@ -64,7 +64,7 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrateg
if dest.Network == net.Network_UDP { // UDP classic DNS mode if dest.Network == net.Network_UDP { // UDP classic DNS mode
return NewClassicNameServer(dest, dispatcher), nil return NewClassicNameServer(dest, dispatcher), nil
} }
return nil, newError("No available name server could be created from ", dest).AtWarning() return nil, errors.New("No available name server could be created from ", dest).AtWarning()
} }
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs. // NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
@@ -82,10 +82,10 @@ func NewClient(
// Create a new server for each client for now // Create a new server for each client for now
server, err := NewServer(ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy()) server, err := NewServer(ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy())
if err != nil { if err != nil {
return newError("failed to create nameserver").Base(err).AtWarning() return errors.New("failed to create nameserver").Base(err).AtWarning()
} }
// Priotize local domains with specific TLDs or without any dot to local DNS // Prioritize local domains with specific TLDs or those without any dot for the local DNS
if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS { if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS {
ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...) ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)
ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule) ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule)
@@ -111,7 +111,7 @@ func NewClient(
for _, domain := range ns.PrioritizedDomain { for _, domain := range ns.PrioritizedDomain {
domainRule, err := toStrMatcher(domain.Type, domain.Domain) domainRule, err := toStrMatcher(domain.Type, domain.Domain)
if err != nil { if err != nil {
return newError("failed to create prioritized domain").Base(err).AtWarning() return errors.New("failed to create prioritized domain").Base(err).AtWarning()
} }
originalRuleIdx := ruleCurr originalRuleIdx := ruleCurr
if ruleCurr < len(ns.OriginalRules) { if ruleCurr < len(ns.OriginalRules) {
@@ -130,7 +130,7 @@ func NewClient(
} }
err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos) err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos)
if err != nil { if err != nil {
return newError("failed to create prioritized domain").Base(err).AtWarning() return errors.New("failed to create prioritized domain").Base(err).AtWarning()
} }
} }
@@ -139,7 +139,7 @@ func NewClient(
for _, geoip := range ns.Geoip { for _, geoip := range ns.Geoip {
matcher, err := container.Add(geoip) matcher, err := container.Add(geoip)
if err != nil { if err != nil {
return newError("failed to create ip matcher").Base(err).AtWarning() return errors.New("failed to create ip matcher").Base(err).AtWarning()
} }
matchers = append(matchers, matcher) matchers = append(matchers, matcher)
} }
@@ -147,9 +147,9 @@ func NewClient(
if len(clientIP) > 0 { if len(clientIP) > 0 {
switch ns.Address.Address.GetAddress().(type) { switch ns.Address.Address.GetAddress().(type) {
case *net.IPOrDomain_Domain: case *net.IPOrDomain_Domain:
newError("DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog() errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
case *net.IPOrDomain_Ip: case *net.IPOrDomain_Ip:
newError("DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog() errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetIp(), " uses clientIP ", clientIP.String())
} }
} }
@@ -169,7 +169,7 @@ func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.I
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
server, err := NewServer(endpoint.AsDestination(), dispatcher, QueryStrategy_USE_IP) server, err := NewServer(endpoint.AsDestination(), dispatcher, QueryStrategy_USE_IP)
if err != nil { if err != nil {
return newError("failed to create nameserver").Base(err).AtWarning() return errors.New("failed to create nameserver").Base(err).AtWarning()
} }
client.server = server client.server = server
client.clientIP = clientIP client.clientIP = clientIP
@@ -179,9 +179,9 @@ func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.I
if len(clientIP) > 0 { if len(clientIP) > 0 {
switch endpoint.Address.GetAddress().(type) { switch endpoint.Address.GetAddress().(type) {
case *net.IPOrDomain_Domain: case *net.IPOrDomain_Domain:
newError("DNS: client ", endpoint.Address.GetDomain(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog() errors.LogInfo(ctx, "DNS: client ", endpoint.Address.GetDomain(), " uses clientIP ", clientIP.String())
case *net.IPOrDomain_Ip: case *net.IPOrDomain_Ip:
newError("DNS: client ", endpoint.Address.GetIp(), " uses clientIP ", clientIP.String()).AtInfo().WriteToLog() errors.LogInfo(ctx, "DNS: client ", endpoint.Address.GetIp(), " uses clientIP ", clientIP.String())
} }
} }
@@ -222,7 +222,7 @@ func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error)
if len(newIps) == 0 { if len(newIps) == 0 {
return nil, errExpectedIPNonMatch return nil, errExpectedIPNonMatch
} }
newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog() errors.LogDebug(context.Background(), "domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name())
return newIps, nil return newIps, nil
} }

View File

@@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc" "github.com/xtls/xray-core/common/net/cnc"
@@ -43,7 +44,7 @@ type DoHNameServer struct {
// NewDoHNameServer creates DOH server object for remote resolving. // NewDoHNameServer creates DOH server object for remote resolving.
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) { func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) {
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog() errors.LogInfo(context.Background(), "DNS: created Remote DOH client for ", url.String())
s := baseDOHNameServer(url, "DOH", queryStrategy) s := baseDOHNameServer(url, "DOH", queryStrategy)
s.dispatcher = dispatcher s.dispatcher = dispatcher
@@ -119,7 +120,7 @@ func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameSe
Timeout: time.Second * 180, Timeout: time.Second * 180,
Transport: tr, Transport: tr,
} }
newError("DNS: created Local DOH client for ", url.String()).AtInfo().WriteToLog() errors.LogInfo(context.Background(), "DNS: created Local DOH client for ", url.String())
return s return s
} }
@@ -150,7 +151,7 @@ func (s *DoHNameServer) Cleanup() error {
defer s.Unlock() defer s.Unlock()
if len(s.ips) == 0 { if len(s.ips) == 0 {
return newError("nothing to do. stopping...") return errors.New("nothing to do. stopping...")
} }
for domain, record := range s.ips { for domain, record := range s.ips {
@@ -162,7 +163,7 @@ func (s *DoHNameServer) Cleanup() error {
} }
if record.A == nil && record.AAAA == nil { if record.A == nil && record.AAAA == nil {
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog() errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
delete(s.ips, domain) delete(s.ips, domain)
} else { } else {
s.ips[domain] = record s.ips[domain] = record
@@ -205,7 +206,7 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
updated = true updated = true
} }
} }
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog() errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
if updated { if updated {
s.ips[req.domain] = rec s.ips[req.domain] = rec
@@ -225,10 +226,10 @@ func (s *DoHNameServer) newReqID() uint16 {
} }
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) { func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, s.name, " querying: ", domain)
if s.name+"." == "DOH//"+domain { if s.name+"." == "DOH//"+domain {
newError(s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.").AtError().WriteToLog(session.ExportIDToError(ctx)) errors.LogError(ctx, s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.")
return return
} }
@@ -258,7 +259,7 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
}) })
// forced to use mux for DOH // forced to use mux for DOH
// dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true) // dnsCtx = session.ContextWithMuxPreferred(dnsCtx, true)
var cancel context.CancelFunc var cancel context.CancelFunc
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline) dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
@@ -266,17 +267,17 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
b, err := dns.PackMessage(r.msg) b, err := dns.PackMessage(r.msg)
if err != nil { if err != nil {
newError("failed to pack dns query for ", domain).Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to pack dns query for ", domain)
return return
} }
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes()) resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
if err != nil { if err != nil {
newError("failed to retrieve response for ", domain).Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to retrieve response for ", domain)
return return
} }
rec, err := parseResponse(resp) rec, err := parseResponse(resp)
if err != nil { if err != nil {
newError("failed to handle DOH response for ", domain).Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to handle DOH response for ", domain)
return return
} }
s.updateIP(r, rec) s.updateIP(r, rec)
@@ -361,11 +362,11 @@ func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net
} }
if disableCache { if disableCache {
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else { } else {
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog() errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err}) log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err return ips, err
} }

View File

@@ -3,6 +3,7 @@ package dns
import ( import (
"context" "context"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
@@ -25,7 +26,7 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) { if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
f.fakeDNSEngine = fd f.fakeDNSEngine = fd
}); err != nil { }); err != nil {
return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError() return nil, errors.New("Unable to locate a fake DNS Engine").Base(err).AtError()
} }
} }
var ips []net.Address var ips []net.Address
@@ -37,10 +38,10 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
netIP, err := toNetIP(ips) netIP, err := toNetIP(ips)
if err != nil { if err != nil {
return nil, newError("Unable to convert IP to net ip").Base(err).AtError() return nil, errors.New("Unable to convert IP to net ip").Base(err).AtError()
} }
newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog() errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
if len(netIP) > 0 { if len(netIP) > 0 {
return netIP, nil return netIP, nil

View File

@@ -5,6 +5,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
@@ -19,7 +20,7 @@ type LocalNameServer struct {
const errEmptyResponse = "No address associated with hostname" const errEmptyResponse = "No address associated with hostname"
// QueryIP implements Server. // QueryIP implements Server.
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) { func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
start := time.Now() start := time.Now()
ips, err = s.client.LookupIP(domain, option) ips, err = s.client.LookupIP(domain, option)
@@ -28,7 +29,7 @@ func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, op
} }
if len(ips) > 0 { if len(ips) > 0 {
newError("Localhost got answer: ", domain, " -> ", ips).AtInfo().WriteToLog() errors.LogInfo(ctx, "Localhost got answer: ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err}) log.Record(&log.DNSLog{Server: s.Name(), Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
} }
@@ -42,7 +43,7 @@ func (s *LocalNameServer) Name() string {
// NewLocalNameServer creates localdns server object for directly lookup in system DNS. // NewLocalNameServer creates localdns server object for directly lookup in system DNS.
func NewLocalNameServer() *LocalNameServer { func NewLocalNameServer() *LocalNameServer {
newError("DNS: created localhost client").AtInfo().WriteToLog() errors.LogInfo(context.Background(), "DNS: created localhost client")
return &LocalNameServer{ return &LocalNameServer{
client: localdns.New(), client: localdns.New(),
} }

View File

@@ -12,6 +12,7 @@ import (
"github.com/quic-go/quic-go" "github.com/quic-go/quic-go"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol/dns" "github.com/xtls/xray-core/common/protocol/dns"
@@ -45,7 +46,7 @@ type QUICNameServer struct {
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving // NewQUICNameServer creates DNS-over-QUIC client object for local resolving
func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) { func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) {
newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog() errors.LogInfo(context.Background(), "DNS: created Local DNS-over-QUIC client for ", url.String())
var err error var err error
port := net.Port(853) port := net.Port(853)
@@ -84,7 +85,7 @@ func (s *QUICNameServer) Cleanup() error {
defer s.Unlock() defer s.Unlock()
if len(s.ips) == 0 { if len(s.ips) == 0 {
return newError("nothing to do. stopping...") return errors.New("nothing to do. stopping...")
} }
for domain, record := range s.ips { for domain, record := range s.ips {
@@ -96,7 +97,7 @@ func (s *QUICNameServer) Cleanup() error {
} }
if record.A == nil && record.AAAA == nil { if record.A == nil && record.AAAA == nil {
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog() errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
delete(s.ips, domain) delete(s.ips, domain)
} else { } else {
s.ips[domain] = record s.ips[domain] = record
@@ -139,7 +140,7 @@ func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
updated = true updated = true
} }
} }
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog() errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
if updated { if updated {
s.ips[req.domain] = rec s.ips[req.domain] = rec
@@ -159,7 +160,7 @@ func (s *QUICNameServer) newReqID() uint16 {
} }
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) { func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, s.name, " querying: ", domain)
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP)) reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
@@ -192,7 +193,7 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
b, err := dns.PackMessage(r.msg) b, err := dns.PackMessage(r.msg)
if err != nil { if err != nil {
newError("failed to pack dns query").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to pack dns query")
return return
} }
@@ -203,13 +204,13 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
conn, err := s.openStream(dnsCtx) conn, err := s.openStream(dnsCtx)
if err != nil { if err != nil {
newError("failed to open quic connection").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to open quic connection")
return return
} }
_, err = conn.Write(dnsReqBuf.Bytes()) _, err = conn.Write(dnsReqBuf.Bytes())
if err != nil { if err != nil {
newError("failed to send query").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to send query")
return return
} }
@@ -219,25 +220,25 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
defer respBuf.Release() defer respBuf.Release()
n, err := respBuf.ReadFullFrom(conn, 2) n, err := respBuf.ReadFullFrom(conn, 2)
if err != nil && n == 0 { if err != nil && n == 0 {
newError("failed to read response length").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to read response length")
return return
} }
var length int16 var length int16
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length) err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
if err != nil { if err != nil {
newError("failed to parse response length").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to parse response length")
return return
} }
respBuf.Clear() respBuf.Clear()
n, err = respBuf.ReadFullFrom(conn, int32(length)) n, err = respBuf.ReadFullFrom(conn, int32(length))
if err != nil && n == 0 { if err != nil && n == 0 {
newError("failed to read response length").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to read response length")
return return
} }
rec, err := parseResponse(respBuf.Bytes()) rec, err := parseResponse(respBuf.Bytes())
if err != nil { if err != nil {
newError("failed to handle response").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to handle response")
return return
} }
s.updateIP(r, rec) s.updateIP(r, rec)
@@ -296,11 +297,11 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP ne
} }
if disableCache { if disableCache {
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else { } else {
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog() errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err}) log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err return ips, err
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc" "github.com/xtls/xray-core/common/net/cnc"
@@ -114,7 +115,7 @@ func (s *TCPNameServer) Cleanup() error {
defer s.Unlock() defer s.Unlock()
if len(s.ips) == 0 { if len(s.ips) == 0 {
return newError("nothing to do. stopping...") return errors.New("nothing to do. stopping...")
} }
for domain, record := range s.ips { for domain, record := range s.ips {
@@ -126,7 +127,7 @@ func (s *TCPNameServer) Cleanup() error {
} }
if record.A == nil && record.AAAA == nil { if record.A == nil && record.AAAA == nil {
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog() errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
delete(s.ips, domain) delete(s.ips, domain)
} else { } else {
s.ips[domain] = record s.ips[domain] = record
@@ -169,7 +170,7 @@ func (s *TCPNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
updated = true updated = true
} }
} }
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog() errors.LogInfo(context.Background(), s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
if updated { if updated {
s.ips[req.domain] = rec s.ips[req.domain] = rec
@@ -189,7 +190,7 @@ func (s *TCPNameServer) newReqID() uint16 {
} }
func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) { func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx)) errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP)) reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
@@ -219,13 +220,13 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
b, err := dns.PackMessage(r.msg) b, err := dns.PackMessage(r.msg)
if err != nil { if err != nil {
newError("failed to pack dns query").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to pack dns query")
return return
} }
conn, err := s.dial(dnsCtx) conn, err := s.dial(dnsCtx)
if err != nil { if err != nil {
newError("failed to dial namesever").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to dial namesever")
return return
} }
defer conn.Close() defer conn.Close()
@@ -236,7 +237,7 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
_, err = conn.Write(dnsReqBuf.Bytes()) _, err = conn.Write(dnsReqBuf.Bytes())
if err != nil { if err != nil {
newError("failed to send query").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to send query")
return return
} }
dnsReqBuf.Release() dnsReqBuf.Release()
@@ -245,25 +246,25 @@ func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP n
defer respBuf.Release() defer respBuf.Release()
n, err := respBuf.ReadFullFrom(conn, 2) n, err := respBuf.ReadFullFrom(conn, 2)
if err != nil && n == 0 { if err != nil && n == 0 {
newError("failed to read response length").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to read response length")
return return
} }
var length int16 var length int16
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length) err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
if err != nil { if err != nil {
newError("failed to parse response length").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to parse response length")
return return
} }
respBuf.Clear() respBuf.Clear()
n, err = respBuf.ReadFullFrom(conn, int32(length)) n, err = respBuf.ReadFullFrom(conn, int32(length))
if err != nil && n == 0 { if err != nil && n == 0 {
newError("failed to read response length").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to read response length")
return return
} }
rec, err := parseResponse(respBuf.Bytes()) rec, err := parseResponse(respBuf.Bytes())
if err != nil { if err != nil {
newError("failed to parse DNS over TCP response").Base(err).AtError().WriteToLog() errors.LogErrorInner(ctx, err, "failed to parse DNS over TCP response")
return return
} }
@@ -319,11 +320,11 @@ func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net
} }
if disableCache { if disableCache {
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else { } else {
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog() errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err}) log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err return ips, err
} }

View File

@@ -8,11 +8,11 @@ import (
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol/dns" "github.com/xtls/xray-core/common/protocol/dns"
udp_proto "github.com/xtls/xray-core/common/protocol/udp" udp_proto "github.com/xtls/xray-core/common/protocol/udp"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/pubsub" "github.com/xtls/xray-core/common/signal/pubsub"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
dns_feature "github.com/xtls/xray-core/features/dns" dns_feature "github.com/xtls/xray-core/features/dns"
@@ -53,7 +53,7 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
Execute: s.Cleanup, Execute: s.Cleanup,
} }
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse) s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
newError("DNS: created UDP client initialized for ", address.NetAddr()).AtInfo().WriteToLog() errors.LogInfo(context.Background(), "DNS: created UDP client initialized for ", address.NetAddr())
return s return s
} }
@@ -69,7 +69,7 @@ func (s *ClassicNameServer) Cleanup() error {
defer s.Unlock() defer s.Unlock()
if len(s.ips) == 0 && len(s.requests) == 0 { if len(s.ips) == 0 && len(s.requests) == 0 {
return newError(s.name, " nothing to do. stopping...") return errors.New(s.name, " nothing to do. stopping...")
} }
for domain, record := range s.ips { for domain, record := range s.ips {
@@ -81,7 +81,7 @@ func (s *ClassicNameServer) Cleanup() error {
} }
if record.A == nil && record.AAAA == nil { if record.A == nil && record.AAAA == nil {
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog() errors.LogDebug(context.Background(), s.name, " cleanup ", domain)
delete(s.ips, domain) delete(s.ips, domain)
} else { } else {
s.ips[domain] = record s.ips[domain] = record
@@ -109,7 +109,7 @@ func (s *ClassicNameServer) Cleanup() error {
func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) { func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {
ipRec, err := parseResponse(packet.Payload.Bytes()) ipRec, err := parseResponse(packet.Payload.Bytes())
if err != nil { if err != nil {
newError(s.name, " fail to parse responded DNS udp").AtError().WriteToLog() errors.LogError(ctx, s.name, " fail to parse responded DNS udp")
return return
} }
@@ -122,7 +122,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
} }
s.Unlock() s.Unlock()
if !ok { if !ok {
newError(s.name, " cannot find the pending request").AtError().WriteToLog() errors.LogError(ctx, s.name, " cannot find the pending request")
return return
} }
@@ -135,7 +135,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
} }
elapsed := time.Since(req.start) elapsed := time.Since(req.start)
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog() errors.LogInfo(ctx, s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed)
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) { if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
s.updateIP(req.domain, &rec) s.updateIP(req.domain, &rec)
} }
@@ -160,7 +160,7 @@ func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
} }
if updated { if updated {
newError(s.name, " updating IP records for domain:", domain).AtDebug().WriteToLog() errors.LogDebug(context.Background(), s.name, " updating IP records for domain:", domain)
s.ips[domain] = rec s.ips[domain] = rec
} }
if newRec.A != nil { if newRec.A != nil {
@@ -187,7 +187,7 @@ func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
} }
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) { func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx)) errors.LogDebug(ctx, s.name, " querying DNS for: ", domain)
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP)) reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
@@ -241,11 +241,11 @@ func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP
fqdn := Fqdn(domain) fqdn := Fqdn(domain)
if disableCache { if disableCache {
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() errors.LogDebug(ctx, "DNS cache is disabled. Querying IP for ", domain, " at ", s.name)
} else { } else {
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound { if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog() errors.LogDebugInner(ctx, err, s.name, " cache HIT ", domain, " -> ", ips)
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err}) log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
return ips, err return ips, err
} }

View File

@@ -7,6 +7,7 @@ import (
"github.com/xtls/xray-core/app/log" "github.com/xtls/xray-core/app/log"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
) )
@@ -19,13 +20,13 @@ type LoggerServer struct {
func (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) { func (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) {
logger := s.V.GetFeature((*log.Instance)(nil)) logger := s.V.GetFeature((*log.Instance)(nil))
if logger == nil { if logger == nil {
return nil, newError("unable to get logger instance") return nil, errors.New("unable to get logger instance")
} }
if err := logger.Close(); err != nil { if err := logger.Close(); err != nil {
return nil, newError("failed to close logger").Base(err) return nil, errors.New("failed to close logger").Base(err)
} }
if err := logger.Start(); err != nil { if err := logger.Start(); err != nil {
return nil, newError("failed to start logger").Base(err) return nil, errors.New("failed to start logger").Base(err)
} }
return &RestartLoggerResponse{}, nil return &RestartLoggerResponse{}, nil
} }

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/log/command/config.proto // source: app/log/command/config.proto
package command package command

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions: // versions:
// - protoc-gen-go-grpc v1.3.0 // - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1 // - protoc v5.27.0
// source: app/log/command/config.proto // source: app/log/command/config.proto
package command package command

View File

@@ -1,9 +0,0 @@
package command
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/log/config.proto // source: app/log/config.proto
package log package log

View File

@@ -1,9 +0,0 @@
package log
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -7,6 +7,7 @@ import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
) )
@@ -29,13 +30,13 @@ func New(ctx context.Context, config *Config) (*Instance, error) {
} }
log.RegisterHandler(g) log.RegisterHandler(g)
// start logger instantly on inited // Start logger instantly on initialization
// other modules would log during init // Other modules would log during initialization
if err := g.startInternal(); err != nil { if err := g.startInternal(); err != nil {
return nil, err return nil, err
} }
newError("Logger started").AtDebug().WriteToLog() errors.LogDebug(ctx, "Logger started")
return g, nil return g, nil
} }
@@ -77,10 +78,10 @@ func (g *Instance) startInternal() error {
g.active = true g.active = true
if err := g.initAccessLogger(); err != nil { if err := g.initAccessLogger(); err != nil {
return newError("failed to initialize access logger").Base(err).AtWarning() return errors.New("failed to initialize access logger").Base(err).AtWarning()
} }
if err := g.initErrorLogger(); err != nil { if err := g.initErrorLogger(); err != nil {
return newError("failed to initialize error logger").Base(err).AtWarning() return errors.New("failed to initialize error logger").Base(err).AtWarning()
} }
return nil return nil
@@ -120,7 +121,7 @@ func (g *Instance) Handle(msg log.Message) {
// Close implements common.Closable.Close(). // Close implements common.Closable.Close().
func (g *Instance) Close() error { func (g *Instance) Close() error {
newError("Logger closing").AtDebug().WriteToLog() errors.LogDebug(context.Background(), "Logger closing")
g.Lock() g.Lock()
defer g.Unlock() defer g.Unlock()

View File

@@ -4,6 +4,7 @@ import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/log"
) )
@@ -19,7 +20,7 @@ var handlerCreatorMapLock = &sync.RWMutex{}
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error { func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
if f == nil { if f == nil {
return newError("nil HandlerCreator") return errors.New("nil HandlerCreator")
} }
handlerCreatorMapLock.Lock() handlerCreatorMapLock.Lock()
@@ -35,7 +36,7 @@ func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler,
creator, found := handlerCreatorMap[logType] creator, found := handlerCreatorMap[logType]
if !found { if !found {
return nil, newError("unable to create log handler for ", logType) return nil, errors.New("unable to create log handler for ", logType)
} }
return creator(logType, options) return creator(logType, options)
} }

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/metrics/config.proto // source: app/metrics/config.proto
package metrics package metrics

View File

@@ -1,9 +0,0 @@
package metrics
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/xtls/xray-core/app/observatory" "github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -93,12 +94,12 @@ func (p *MetricsHandler) Start() error {
go func() { go func() {
if err := http.Serve(listener, http.DefaultServeMux); err != nil { if err := http.Serve(listener, http.DefaultServeMux); err != nil {
newError("failed to start metrics server").Base(err).AtError().WriteToLog() errors.LogErrorInner(context.Background(), err, "failed to start metrics server")
} }
}() }()
if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil { if err := p.ohm.RemoveHandler(context.Background(), p.tag); err != nil {
newError("failed to remove existing handler").WriteToLog() errors.LogInfo(context.Background(), "failed to remove existing handler")
} }
return p.ohm.AddHandler(context.Background(), &Outbound{ return p.ohm.AddHandler(context.Background(), &Outbound{

View File

@@ -5,6 +5,7 @@ import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc" "github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
@@ -31,7 +32,7 @@ func (l *OutboundListener) add(conn net.Conn) {
func (l *OutboundListener) Accept() (net.Conn, error) { func (l *OutboundListener) Accept() (net.Conn, error) {
select { select {
case <-l.done.Wait(): case <-l.done.Wait():
return nil, newError("listen closed") return nil, errors.New("listen closed")
case c := <-l.buffer: case c := <-l.buffer:
return c, nil return c, nil
} }

View File

@@ -3,14 +3,16 @@ package burst
import ( import (
"context" "context"
"github.com/xtls/xray-core/core" "sync"
"github.com/xtls/xray-core/app/observatory" "github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension" "github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"sync"
) )
type Observer struct { type Observer struct {
@@ -66,7 +68,7 @@ func (o *Observer) Start() error {
hs, ok := o.ohm.(outbound.HandlerSelector) hs, ok := o.ohm.(outbound.HandlerSelector)
if !ok { if !ok {
return nil, newError("outbound.Manager is not a HandlerSelector") return nil, errors.New("outbound.Manager is not a HandlerSelector")
} }
outbounds := hs.Select(o.config.SubjectSelector) outbounds := hs.Select(o.config.SubjectSelector)
@@ -90,7 +92,7 @@ func New(ctx context.Context, config *Config) (*Observer, error) {
outboundManager = om outboundManager = om
}) })
if err != nil { if err != nil {
return nil, newError("Cannot get depended features").Base(err) return nil, errors.New("Cannot get depended features").Base(err)
} }
hp := NewHealthPing(ctx, config.PingConfig) hp := NewHealthPing(ctx, config.PingConfig)
return &Observer{ return &Observer{

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/observatory/burst/config.proto // source: app/observatory/burst/config.proto
package burst package burst

View File

@@ -1,9 +0,0 @@
package burst
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
) )
// HealthPingSettings holds settings for health Checker // HealthPingSettings holds settings for health Checker
@@ -51,7 +52,7 @@ func NewHealthPing(ctx context.Context, config *HealthPingConfig) *HealthPing {
if settings.Interval == 0 { if settings.Interval == 0 {
settings.Interval = time.Duration(1) * time.Minute settings.Interval = time.Duration(1) * time.Minute
} else if settings.Interval < 10 { } else if settings.Interval < 10 {
newError("health check interval is too small, 10s is applied").AtWarning().WriteToLog() errors.LogWarning(ctx, "health check interval is too small, 10s is applied")
settings.Interval = time.Duration(10) * time.Second settings.Interval = time.Duration(10) * time.Second
} }
if settings.SamplingCount <= 0 { if settings.SamplingCount <= 0 {
@@ -82,7 +83,7 @@ func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
go func() { go func() {
tags, err := selector() tags, err := selector()
if err != nil { if err != nil {
newError("error select outbounds for initial health check: ", err).AtWarning().WriteToLog() errors.LogWarning(h.ctx, "error select outbounds for initial health check: ", err)
return return
} }
h.Check(tags) h.Check(tags)
@@ -93,7 +94,7 @@ func (h *HealthPing) StartScheduler(selector func() ([]string, error)) {
go func() { go func() {
tags, err := selector() tags, err := selector()
if err != nil { if err != nil {
newError("error select outbounds for scheduled health check: ", err).AtWarning().WriteToLog() errors.LogWarning(h.ctx, "error select outbounds for scheduled health check: ", err)
return return
} }
h.doCheck(tags, interval, h.Settings.SamplingCount) h.doCheck(tags, interval, h.Settings.SamplingCount)
@@ -125,7 +126,7 @@ func (h *HealthPing) Check(tags []string) error {
if len(tags) == 0 { if len(tags) == 0 {
return nil return nil
} }
newError("perform one-time health check for tags ", tags).AtInfo().WriteToLog() errors.LogInfo(h.ctx, "perform one-time health check for tags ", tags)
h.doCheck(tags, 0, 1) h.doCheck(tags, 0, 1)
return nil return nil
} }
@@ -158,7 +159,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
delay = time.Duration(dice.Roll(int(duration))) delay = time.Duration(dice.Roll(int(duration)))
} }
time.AfterFunc(delay, func() { time.AfterFunc(delay, func() {
newError("checking ", handler).AtDebug().WriteToLog() errors.LogDebug(h.ctx, "checking ", handler)
delay, err := client.MeasureDelay() delay, err := client.MeasureDelay()
if err == nil { if err == nil {
ch <- &rtt{ ch <- &rtt{
@@ -168,19 +169,19 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
return return
} }
if !h.checkConnectivity() { if !h.checkConnectivity() {
newError("network is down").AtWarning().WriteToLog() errors.LogWarning(h.ctx, "network is down")
ch <- &rtt{ ch <- &rtt{
handler: handler, handler: handler,
value: 0, value: 0,
} }
return return
} }
newError(fmt.Sprintf( errors.LogWarning(h.ctx, fmt.Sprintf(
"error ping %s with %s: %s", "error ping %s with %s: %s",
h.Settings.Destination, h.Settings.Destination,
handler, handler,
err, err,
)).AtWarning().WriteToLog() ))
ch <- &rtt{ ch <- &rtt{
handler: handler, handler: handler,
value: rttFailed, value: rttFailed,
@@ -208,7 +209,7 @@ func (h *HealthPing) PutResult(tag string, rtt time.Duration) {
if !ok { if !ok {
// validity is 2 times to sampling period, since the check are // validity is 2 times to sampling period, since the check are
// distributed in the time line randomly, in extreme cases, // distributed in the time line randomly, in extreme cases,
// previous checks are distributed on the left, and latters // Previous checks are distributed on the left, and later ones
// on the right // on the right
validity := h.Settings.Interval * time.Duration(h.Settings.SamplingCount) * 2 validity := h.Settings.Interval * time.Duration(h.Settings.SamplingCount) * 2
r = NewHealthPingResult(h.Settings.SamplingCount, validity) r = NewHealthPingResult(h.Settings.SamplingCount, validity)

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/observatory/command/command.proto // source: app/observatory/command/command.proto
package command package command

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions: // versions:
// - protoc-gen-go-grpc v1.3.0 // - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1 // - protoc v5.27.0
// source: app/observatory/command/command.proto // source: app/observatory/command/command.proto
package command package command

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/observatory/config.proto // source: app/observatory/config.proto
package observatory package observatory

View File

@@ -1,9 +0,0 @@
package observatory
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -8,10 +8,10 @@ type errorCollector struct {
func (e *errorCollector) SubmitError(err error) { func (e *errorCollector) SubmitError(err error) {
if e.errors == nil { if e.errors == nil {
e.errors = newError("underlying connection error").Base(err) e.errors = errors.New("underlying connection error").Base(err)
return return
} }
e.errors = e.errors.Base(newError("underlying connection error").Base(err)) e.errors = e.errors.Base(errors.New("underlying connection error").Base(err))
} }
func newErrorCollector() *errorCollector { func newErrorCollector() *errorCollector {
@@ -20,7 +20,7 @@ func newErrorCollector() *errorCollector {
func (e *errorCollector) UnderlyingError() error { func (e *errorCollector) UnderlyingError() error {
if e.errors == nil { if e.errors == nil {
return newError("failed to produce report") return errors.New("failed to produce report")
} }
return e.errors return e.errors
} }

View File

@@ -10,6 +10,7 @@ import (
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
v2net "github.com/xtls/xray-core/common/net" v2net "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
@@ -60,7 +61,7 @@ func (o *Observer) background() {
for !o.finished.Done() { for !o.finished.Done() {
hs, ok := o.ohm.(outbound.HandlerSelector) hs, ok := o.ohm.(outbound.HandlerSelector)
if !ok { if !ok {
newError("outbound.Manager is not a HandlerSelector").WriteToLog() errors.LogInfo(o.ctx, "outbound.Manager is not a HandlerSelector")
return return
} }
@@ -127,18 +128,18 @@ func (o *Observer) probe(outbound string) ProbeResult {
// MUST use Xray's built in context system // MUST use Xray's built in context system
dest, err := v2net.ParseDestination(network + ":" + addr) dest, err := v2net.ParseDestination(network + ":" + addr)
if err != nil { if err != nil {
return newError("cannot understand address").Base(err) return errors.New("cannot understand address").Base(err)
} }
trackedCtx := session.TrackedConnectionError(o.ctx, errorCollectorForRequest) trackedCtx := session.TrackedConnectionError(o.ctx, errorCollectorForRequest)
conn, err := tagged.Dialer(trackedCtx, dest, outbound) conn, err := tagged.Dialer(trackedCtx, dest, outbound)
if err != nil { if err != nil {
return newError("cannot dial remote address ", dest).Base(err) return errors.New("cannot dial remote address ", dest).Base(err)
} }
connection = conn connection = conn
return nil return nil
}) })
if taskErr != nil { if taskErr != nil {
return nil, newError("cannot finish connection").Base(taskErr) return nil, errors.New("cannot finish connection").Base(taskErr)
} }
return connection, nil return connection, nil
}, },
@@ -161,7 +162,7 @@ func (o *Observer) probe(outbound string) ProbeResult {
} }
response, err := httpClient.Get(probeURL) response, err := httpClient.Get(probeURL)
if err != nil { if err != nil {
return newError("outbound failed to relay connection").Base(err) return errors.New("outbound failed to relay connection").Base(err)
} }
if response.Body != nil { if response.Body != nil {
response.Body.Close() response.Body.Close()
@@ -171,15 +172,11 @@ func (o *Observer) probe(outbound string) ProbeResult {
return nil return nil
}) })
if err != nil { if err != nil {
fullerr := newError("underlying connection failed").Base(errorCollectorForRequest.UnderlyingError()) var errorMessage = "the outbound " + outbound + " is dead: GET request failed:" + err.Error() + "with outbound handler report underlying connection failed"
fullerr = newError("with outbound handler report").Base(fullerr) errors.LogInfoInner(o.ctx, errorCollectorForRequest.UnderlyingError(), errorMessage)
fullerr = newError("GET request failed:", err).Base(fullerr) return ProbeResult{Alive: false, LastErrorReason: errorMessage}
fullerr = newError("the outbound ", outbound, " is dead:").Base(fullerr)
fullerr = fullerr.AtInfo()
fullerr.WriteToLog()
return ProbeResult{Alive: false, LastErrorReason: fullerr.Error()}
} }
newError("the outbound ", outbound, " is alive:", GETTime.Seconds()).AtInfo().WriteToLog() errors.LogInfo(o.ctx, "the outbound ", outbound, " is alive:", GETTime.Seconds())
return ProbeResult{Alive: true, Delay: GETTime.Milliseconds()} return ProbeResult{Alive: true, Delay: GETTime.Milliseconds()}
} }
@@ -222,7 +219,7 @@ func New(ctx context.Context, config *Config) (*Observer, error) {
outboundManager = om outboundManager = om
}) })
if err != nil { if err != nil {
return nil, newError("Cannot get depended features").Base(err) return nil, errors.New("Cannot get depended features").Base(err)
} }
return &Observer{ return &Observer{
config: config, config: config,

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/policy/config.proto // source: app/policy/config.proto
package policy package policy

View File

@@ -1,9 +0,0 @@
package policy
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/inbound" "github.com/xtls/xray-core/features/inbound"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
@@ -26,7 +27,7 @@ type OutboundOperation interface {
func getInbound(handler inbound.Handler) (proxy.Inbound, error) { func getInbound(handler inbound.Handler) (proxy.Inbound, error) {
gi, ok := handler.(proxy.GetInbound) gi, ok := handler.(proxy.GetInbound)
if !ok { if !ok {
return nil, newError("can't get inbound proxy from handler.") return nil, errors.New("can't get inbound proxy from handler.")
} }
return gi.GetInbound(), nil return gi.GetInbound(), nil
} }
@@ -39,11 +40,11 @@ func (op *AddUserOperation) ApplyInbound(ctx context.Context, handler inbound.Ha
} }
um, ok := p.(proxy.UserManager) um, ok := p.(proxy.UserManager)
if !ok { if !ok {
return newError("proxy is not a UserManager") return errors.New("proxy is not a UserManager")
} }
mUser, err := op.User.ToMemoryUser() mUser, err := op.User.ToMemoryUser()
if err != nil { if err != nil {
return newError("failed to parse user").Base(err) return errors.New("failed to parse user").Base(err)
} }
return um.AddUser(ctx, mUser) return um.AddUser(ctx, mUser)
} }
@@ -56,7 +57,7 @@ func (op *RemoveUserOperation) ApplyInbound(ctx context.Context, handler inbound
} }
um, ok := p.(proxy.UserManager) um, ok := p.(proxy.UserManager)
if !ok { if !ok {
return newError("proxy is not a UserManager") return errors.New("proxy is not a UserManager")
} }
return um.RemoveUser(ctx, op.Email) return um.RemoveUser(ctx, op.Email)
} }
@@ -82,16 +83,16 @@ func (s *handlerServer) RemoveInbound(ctx context.Context, request *RemoveInboun
func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) { func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) {
rawOperation, err := request.Operation.GetInstance() rawOperation, err := request.Operation.GetInstance()
if err != nil { if err != nil {
return nil, newError("unknown operation").Base(err) return nil, errors.New("unknown operation").Base(err)
} }
operation, ok := rawOperation.(InboundOperation) operation, ok := rawOperation.(InboundOperation)
if !ok { if !ok {
return nil, newError("not an inbound operation") return nil, errors.New("not an inbound operation")
} }
handler, err := s.ihm.GetHandler(ctx, request.Tag) handler, err := s.ihm.GetHandler(ctx, request.Tag)
if err != nil { if err != nil {
return nil, newError("failed to get handler: ", request.Tag).Base(err) return nil, errors.New("failed to get handler: ", request.Tag).Base(err)
} }
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler) return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
@@ -111,11 +112,11 @@ func (s *handlerServer) RemoveOutbound(ctx context.Context, request *RemoveOutbo
func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) { func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) {
rawOperation, err := request.Operation.GetInstance() rawOperation, err := request.Operation.GetInstance()
if err != nil { if err != nil {
return nil, newError("unknown operation").Base(err) return nil, errors.New("unknown operation").Base(err)
} }
operation, ok := rawOperation.(OutboundOperation) operation, ok := rawOperation.(OutboundOperation)
if !ok { if !ok {
return nil, newError("not an outbound operation") return nil, errors.New("not an outbound operation")
} }
handler := s.ohm.GetHandler(request.Tag) handler := s.ohm.GetHandler(request.Tag)

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/proxyman/command/command.proto // source: app/proxyman/command/command.proto
package command package command

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions: // versions:
// - protoc-gen-go-grpc v1.3.0 // - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1 // - protoc v5.27.0
// source: app/proxyman/command/command.proto // source: app/proxyman/command/command.proto
package command package command

View File

@@ -1,9 +0,0 @@
package command
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/proxyman/config.proto // source: app/proxyman/config.proto
package proxyman package proxyman

View File

@@ -55,7 +55,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
} }
p, ok := rawProxy.(proxy.Inbound) p, ok := rawProxy.(proxy.Inbound)
if !ok { if !ok {
return nil, newError("not an inbound proxy.") return nil, errors.New("not an inbound proxy.")
} }
h := &AlwaysOnInboundHandler{ h := &AlwaysOnInboundHandler{
@@ -75,7 +75,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings) mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
if err != nil { if err != nil {
return nil, newError("failed to parse stream config").Base(err).AtWarning() return nil, errors.New("failed to parse stream config").Base(err).AtWarning()
} }
if receiverConfig.ReceiveOriginalDestination { if receiverConfig.ReceiveOriginalDestination {
@@ -89,7 +89,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
} }
if pl == nil { if pl == nil {
if net.HasNetwork(nl, net.Network_UNIX) { if net.HasNetwork(nl, net.Network_UNIX) {
newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog() errors.LogDebug(ctx, "creating unix domain socket worker on ", address)
worker := &dsWorker{ worker := &dsWorker{
address: address, address: address,
@@ -109,7 +109,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
for _, pr := range pl.Range { for _, pr := range pl.Range {
for port := pr.From; port <= pr.To; port++ { for port := pr.From; port <= pr.To; port++ {
if net.HasNetwork(nl, net.Network_TCP) { if net.HasNetwork(nl, net.Network_TCP) {
newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog() errors.LogDebug(ctx, "creating stream worker on ", address, ":", port)
worker := &tcpWorker{ worker := &tcpWorker{
address: address, address: address,
@@ -167,7 +167,7 @@ func (h *AlwaysOnInboundHandler) Close() error {
} }
errs = append(errs, h.mux.Close()) errs = append(errs, h.mux.Close())
if err := errors.Combine(errs...); err != nil { if err := errors.Combine(errs...); err != nil {
return newError("failed to close all resources").Base(err) return errors.New("failed to close all resources").Base(err)
} }
return nil return nil
} }

View File

@@ -7,6 +7,7 @@ import (
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
@@ -46,7 +47,7 @@ func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *p
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings) mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
if err != nil { if err != nil {
return nil, newError("failed to parse stream settings").Base(err).AtWarning() return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
} }
if receiverConfig.ReceiveOriginalDestination { if receiverConfig.ReceiveOriginalDestination {
if mss.SocketSettings == nil { if mss.SocketSettings == nil {
@@ -94,7 +95,7 @@ func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
for idx, worker := range workers { for idx, worker := range workers {
ports2Del[idx] = worker.Port() ports2Del[idx] = worker.Port()
if err := worker.Close(); err != nil { if err := worker.Close(); err != nil {
newError("failed to close worker").Base(err).WriteToLog() errors.LogInfoInner(h.ctx, err, "failed to close worker")
} }
} }
@@ -123,7 +124,7 @@ func (h *DynamicInboundHandler) refresh() error {
port := h.allocatePort() port := h.allocatePort()
rawProxy, err := core.CreateObject(h.v, h.proxyConfig) rawProxy, err := core.CreateObject(h.v, h.proxyConfig)
if err != nil { if err != nil {
newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog() errors.LogWarningInner(h.ctx, err, "failed to create proxy instance")
continue continue
} }
p := rawProxy.(proxy.Inbound) p := rawProxy.(proxy.Inbound)
@@ -143,7 +144,7 @@ func (h *DynamicInboundHandler) refresh() error {
ctx: h.ctx, ctx: h.ctx,
} }
if err := worker.Start(); err != nil { if err := worker.Start(); err != nil {
newError("failed to create TCP worker").Base(err).AtWarning().WriteToLog() errors.LogWarningInner(h.ctx, err, "failed to create TCP worker")
continue continue
} }
workers = append(workers, worker) workers = append(workers, worker)
@@ -163,7 +164,7 @@ func (h *DynamicInboundHandler) refresh() error {
ctx: h.ctx, ctx: h.ctx,
} }
if err := worker.Start(); err != nil { if err := worker.Start(); err != nil {
newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog() errors.LogWarningInner(h.ctx, err, "failed to create UDP worker")
continue continue
} }
workers = append(workers, worker) workers = append(workers, worker)

View File

@@ -1,9 +0,0 @@
package inbound
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -43,7 +44,7 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
tag := handler.Tag() tag := handler.Tag()
if len(tag) > 0 { if len(tag) > 0 {
if _, found := m.taggedHandlers[tag]; found { if _, found := m.taggedHandlers[tag]; found {
return newError("existing tag found: " + tag) return errors.New("existing tag found: " + tag)
} }
m.taggedHandlers[tag] = handler m.taggedHandlers[tag] = handler
} else { } else {
@@ -64,7 +65,7 @@ func (m *Manager) GetHandler(ctx context.Context, tag string) (inbound.Handler,
handler, found := m.taggedHandlers[tag] handler, found := m.taggedHandlers[tag]
if !found { if !found {
return nil, newError("handler not found: ", tag) return nil, errors.New("handler not found: ", tag)
} }
return handler, nil return handler, nil
} }
@@ -80,7 +81,7 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
if handler, found := m.taggedHandlers[tag]; found { if handler, found := m.taggedHandlers[tag]; found {
if err := handler.Close(); err != nil { if err := handler.Close(); err != nil {
newError("failed to close handler ", tag).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx)) errors.LogWarningInner(ctx, err, "failed to close handler ", tag)
} }
delete(m.taggedHandlers, tag) delete(m.taggedHandlers, tag)
return nil return nil
@@ -117,20 +118,20 @@ func (m *Manager) Close() error {
m.running = false m.running = false
var errors []interface{} var errs []interface{}
for _, handler := range m.taggedHandlers { for _, handler := range m.taggedHandlers {
if err := handler.Close(); err != nil { if err := handler.Close(); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
} }
for _, handler := range m.untaggedHandler { for _, handler := range m.untaggedHandler {
if err := handler.Close(); err != nil { if err := handler.Close(); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
} }
if len(errors) > 0 { if len(errs) > 0 {
return newError("failed to close all handlers").Base(newError(serial.Concat(errors...))) return errors.New("failed to close all handlers").Base(errors.New(serial.Concat(errs...)))
} }
return nil return nil
@@ -150,7 +151,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig) receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
if !ok { if !ok {
return nil, newError("not a ReceiverConfig").AtError() return nil, errors.New("not a ReceiverConfig").AtError()
} }
streamSettings := receiverSettings.StreamSettings streamSettings := receiverSettings.StreamSettings
@@ -168,7 +169,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
if allocStrategy.Type == proxyman.AllocationStrategy_Random { if allocStrategy.Type == proxyman.AllocationStrategy_Random {
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings) return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
} }
return nil, newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError() return nil, errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
} }
func init() { func init() {

View File

@@ -9,6 +9,8 @@ import (
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
c "github.com/xtls/xray-core/common/ctx"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
@@ -58,16 +60,16 @@ func getTProxyType(s *internet.MemoryStreamConfig) internet.SocketConfig_TProxyM
func (w *tcpWorker) callback(conn stat.Connection) { func (w *tcpWorker) callback(conn stat.Connection) {
ctx, cancel := context.WithCancel(w.ctx) ctx, cancel := context.WithCancel(w.ctx)
sid := session.NewID() sid := session.NewID()
ctx = session.ContextWithID(ctx, sid) ctx = c.ContextWithID(ctx, sid)
var outbound = &session.Outbound{} outbounds := []*session.Outbound{{}}
if w.recvOrigDest { if w.recvOrigDest {
var dest net.Destination var dest net.Destination
switch getTProxyType(w.stream) { switch getTProxyType(w.stream) {
case internet.SocketConfig_Redirect: case internet.SocketConfig_Redirect:
d, err := tcp.GetOriginalDestination(conn) d, err := tcp.GetOriginalDestination(conn)
if err != nil { if err != nil {
newError("failed to get original destination").Base(err).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfoInner(ctx, err, "failed to get original destination")
} else { } else {
dest = d dest = d
} }
@@ -75,10 +77,10 @@ func (w *tcpWorker) callback(conn stat.Connection) {
dest = net.DestinationFromAddr(conn.LocalAddr()) dest = net.DestinationFromAddr(conn.LocalAddr())
} }
if dest.IsValid() { if dest.IsValid() {
outbound.Target = dest outbounds[0].Target = dest
} }
} }
ctx = session.ContextWithOutbound(ctx, outbound) ctx = session.ContextWithOutbounds(ctx, outbounds)
if w.uplinkCounter != nil || w.downlinkCounter != nil { if w.uplinkCounter != nil || w.downlinkCounter != nil {
conn = &stat.CounterConnection{ conn = &stat.CounterConnection{
@@ -105,7 +107,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfoInner(ctx, err, "connection ends")
} }
cancel() cancel()
conn.Close() conn.Close()
@@ -121,24 +123,24 @@ func (w *tcpWorker) Start() error {
go w.callback(conn) go w.callback(conn)
}) })
if err != nil { if err != nil {
return newError("failed to listen TCP on ", w.port).AtWarning().Base(err) return errors.New("failed to listen TCP on ", w.port).AtWarning().Base(err)
} }
w.hub = hub w.hub = hub
return nil return nil
} }
func (w *tcpWorker) Close() error { func (w *tcpWorker) Close() error {
var errors []interface{} var errs []interface{}
if w.hub != nil { if w.hub != nil {
if err := common.Close(w.hub); err != nil { if err := common.Close(w.hub); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
if err := common.Close(w.proxy); err != nil { if err := common.Close(w.proxy); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
} }
if len(errors) > 0 { if len(errs) > 0 {
return newError("failed to close all resources").Base(newError(serial.Concat(errors...))) return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
} }
return nil return nil
@@ -306,13 +308,13 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
go func() { go func() {
ctx := w.ctx ctx := w.ctx
sid := session.NewID() sid := session.NewID()
ctx = session.ContextWithID(ctx, sid) ctx = c.ContextWithID(ctx, sid)
outbounds := []*session.Outbound{{}}
if originalDest.IsValid() { if originalDest.IsValid() {
ctx = session.ContextWithOutbound(ctx, &session.Outbound{ outbounds[0].Target = originalDest
Target: originalDest,
})
} }
ctx = session.ContextWithOutbounds(ctx, outbounds)
ctx = session.ContextWithInbound(ctx, &session.Inbound{ ctx = session.ContextWithInbound(ctx, &session.Inbound{
Source: source, Source: source,
Gateway: net.UDPDestination(w.address, w.port), Gateway: net.UDPDestination(w.address, w.port),
@@ -327,7 +329,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
} }
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfoInner(ctx, err, "connection ends")
} }
conn.Close() conn.Close()
// conn not removed by checker TODO may be lock worker here is better // conn not removed by checker TODO may be lock worker here is better
@@ -358,7 +360,7 @@ func (w *udpWorker) clean() error {
defer w.Unlock() defer w.Unlock()
if len(w.activeConn) == 0 { if len(w.activeConn) == 0 {
return newError("no more connections. stopping...") return errors.New("no more connections. stopping...")
} }
for addr, conn := range w.activeConn { for addr, conn := range w.activeConn {
@@ -402,26 +404,26 @@ func (w *udpWorker) Close() error {
w.Lock() w.Lock()
defer w.Unlock() defer w.Unlock()
var errors []interface{} var errs []interface{}
if w.hub != nil { if w.hub != nil {
if err := w.hub.Close(); err != nil { if err := w.hub.Close(); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
} }
if w.checker != nil { if w.checker != nil {
if err := w.checker.Close(); err != nil { if err := w.checker.Close(); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
} }
if err := common.Close(w.proxy); err != nil { if err := common.Close(w.proxy); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
if len(errors) > 0 { if len(errs) > 0 {
return newError("failed to close all resources").Base(newError(serial.Concat(errors...))) return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
} }
return nil return nil
} }
@@ -452,7 +454,7 @@ type dsWorker struct {
func (w *dsWorker) callback(conn stat.Connection) { func (w *dsWorker) callback(conn stat.Connection) {
ctx, cancel := context.WithCancel(w.ctx) ctx, cancel := context.WithCancel(w.ctx)
sid := session.NewID() sid := session.NewID()
ctx = session.ContextWithID(ctx, sid) ctx = c.ContextWithID(ctx, sid)
if w.uplinkCounter != nil || w.downlinkCounter != nil { if w.uplinkCounter != nil || w.downlinkCounter != nil {
conn = &stat.CounterConnection{ conn = &stat.CounterConnection{
@@ -479,11 +481,11 @@ func (w *dsWorker) callback(conn stat.Connection) {
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfoInner(ctx, err, "connection ends")
} }
cancel() cancel()
if err := conn.Close(); err != nil { if err := conn.Close(); err != nil {
newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfoInner(ctx, err, "failed to close connection")
} }
} }
@@ -501,24 +503,24 @@ func (w *dsWorker) Start() error {
go w.callback(conn) go w.callback(conn)
}) })
if err != nil { if err != nil {
return newError("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err) return errors.New("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
} }
w.hub = hub w.hub = hub
return nil return nil
} }
func (w *dsWorker) Close() error { func (w *dsWorker) Close() error {
var errors []interface{} var errs []interface{}
if w.hub != nil { if w.hub != nil {
if err := common.Close(w.hub); err != nil { if err := common.Close(w.hub); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
if err := common.Close(w.proxy); err != nil { if err := common.Close(w.proxy); err != nil {
errors = append(errors, err) errs = append(errs, err)
} }
} }
if len(errors) > 0 { if len(errs) > 0 {
return newError("failed to close all resources").Base(newError(serial.Concat(errors...))) return errors.New("failed to close all resources").Base(errors.New(serial.Concat(errs...)))
} }
return nil return nil

View File

@@ -1,9 +0,0 @@
package outbound
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -3,9 +3,15 @@ package outbound
import ( import (
"context" "context"
"crypto/rand" "crypto/rand"
"errors" goerrors "errors"
"io"
"math/big"
gonet "net"
"os"
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
@@ -21,10 +27,6 @@ import (
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe" "github.com/xtls/xray-core/transport/pipe"
"io"
"math/big"
gonet "net"
"os"
) )
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) { func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
@@ -87,11 +89,11 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
h.senderSettings = s h.senderSettings = s
mss, err := internet.ToMemoryStreamConfig(s.StreamSettings) mss, err := internet.ToMemoryStreamConfig(s.StreamSettings)
if err != nil { if err != nil {
return nil, newError("failed to parse stream settings").Base(err).AtWarning() return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
} }
h.streamSettings = mss h.streamSettings = mss
default: default:
return nil, newError("settings is not SenderConfig") return nil, errors.New("settings is not SenderConfig")
} }
} }
@@ -107,7 +109,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
proxyHandler, ok := rawProxyHandler.(proxy.Outbound) proxyHandler, ok := rawProxyHandler.(proxy.Outbound)
if !ok { if !ok {
return nil, newError("not an outbound handler") return nil, errors.New("not an outbound handler")
} }
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil { if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {
@@ -169,30 +171,31 @@ func (h *Handler) Tag() string {
// Dispatch implements proxy.Outbound.Dispatch. // Dispatch implements proxy.Outbound.Dispatch.
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
outbound := session.OutboundFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
if outbound.Target.Network == net.Network_UDP && outbound.OriginalTarget.Address != nil && outbound.OriginalTarget.Address != outbound.Target.Address { ob := outbounds[len(outbounds)-1]
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: outbound.Target.Address, OriginalDest: outbound.OriginalTarget.Address} if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: outbound.Target.Address, OriginalDest: outbound.OriginalTarget.Address} link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
} }
if h.mux != nil { if h.mux != nil {
test := func(err error) { test := func(err error) {
if err != nil { if err != nil {
err := newError("failed to process mux outbound traffic").Base(err) err := errors.New("failed to process mux outbound traffic").Base(err)
session.SubmitOutboundErrorToOriginator(ctx, err) session.SubmitOutboundErrorToOriginator(ctx, err)
err.WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, err.Error())
common.Interrupt(link.Writer) common.Interrupt(link.Writer)
} }
} }
if outbound.Target.Network == net.Network_UDP && outbound.Target.Port == 443 { if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
switch h.udp443 { switch h.udp443 {
case "reject": case "reject":
test(newError("XUDP rejected UDP/443 traffic").AtInfo()) test(errors.New("XUDP rejected UDP/443 traffic").AtInfo())
return return
case "skip": case "skip":
goto out goto out
} }
} }
if h.xudp != nil && outbound.Target.Network == net.Network_UDP { if h.xudp != nil && ob.Target.Network == net.Network_UDP {
if !h.xudp.Enabled { if !h.xudp.Enabled {
goto out goto out
} }
@@ -207,15 +210,15 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
out: out:
err := h.proxy.Process(ctx, link, h) err := h.proxy.Process(ctx, link, h)
if err != nil { if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) { if goerrors.Is(err, io.EOF) || goerrors.Is(err, io.ErrClosedPipe) || goerrors.Is(err, context.Canceled) {
err = nil err = nil
} }
} }
if err != nil { if err != nil {
// Ensure outbound ray is properly closed. // Ensure outbound ray is properly closed.
err := newError("failed to process outbound traffic").Base(err) err := errors.New("failed to process outbound traffic").Base(err)
session.SubmitOutboundErrorToOriginator(ctx, err) session.SubmitOutboundErrorToOriginator(ctx, err)
err.WriteToLog(session.ExportIDToError(ctx)) errors.LogInfo(ctx, err.Error())
common.Interrupt(link.Writer) common.Interrupt(link.Writer)
} else { } else {
common.Close(link.Writer) common.Close(link.Writer)
@@ -242,11 +245,12 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
tag := h.senderSettings.ProxySettings.Tag tag := h.senderSettings.ProxySettings.Tag
handler := h.outboundManager.GetHandler(tag) handler := h.outboundManager.GetHandler(tag)
if handler != nil { if handler != nil {
newError("proxying to ", tag, " for dest ", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx)) errors.LogDebug(ctx, "proxying to ", tag, " for dest ", dest)
ctx = session.ContextWithOutbound(ctx, &session.Outbound{ outbounds := session.OutboundsFromContext(ctx)
ctx = session.ContextWithOutbounds(ctx, append(outbounds, &session.Outbound{
Target: dest, Target: dest,
}) Tag: tag,
})) // add another outbound in session ctx
opts := pipe.OptionsFromContext(ctx) opts := pipe.OptionsFromContext(ctx)
uplinkReader, uplinkWriter := pipe.New(opts...) uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...) downlinkReader, downlinkWriter := pipe.New(opts...)
@@ -262,19 +266,16 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
return h.getStatCouterConnection(conn), nil return h.getStatCouterConnection(conn), nil
} }
newError("failed to get outbound handler with tag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx)) errors.LogWarning(ctx, "failed to get outbound handler with tag: ", tag)
} }
if h.senderSettings.Via != nil { if h.senderSettings.Via != nil {
outbound := session.OutboundFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
if outbound == nil { ob := outbounds[len(outbounds)-1]
outbound = new(session.Outbound)
ctx = session.ContextWithOutbound(ctx, outbound)
}
if h.senderSettings.ViaCidr == "" { if h.senderSettings.ViaCidr == "" {
outbound.Gateway = h.senderSettings.Via.AsAddress() ob.Gateway = h.senderSettings.Via.AsAddress()
} else { //Get a random address. } else { //Get a random address.
outbound.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr) ob.Gateway = ParseRandomIPv6(h.senderSettings.Via.AsAddress(), h.senderSettings.ViaCidr)
} }
} }
} }
@@ -285,10 +286,9 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
conn, err := internet.Dial(ctx, dest, h.streamSettings) conn, err := internet.Dial(ctx, dest, h.streamSettings)
conn = h.getStatCouterConnection(conn) conn = h.getStatCouterConnection(conn)
outbound := session.OutboundFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
if outbound != nil { ob := outbounds[len(outbounds)-1]
outbound.Conn = conn ob.Conn = conn
}
return conn, err return conn, err
} }
@@ -319,7 +319,6 @@ func (h *Handler) Close() error {
return nil return nil
} }
func ParseRandomIPv6(address net.Address, prefix string) net.Address { func ParseRandomIPv6(address net.Address, prefix string) net.Address {
_, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix) _, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix)

View File

@@ -14,6 +14,7 @@ import (
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/session"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/proxy/freedom" "github.com/xtls/xray-core/proxy/freedom"
@@ -44,6 +45,7 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
v, _ := core.New(config) v, _ := core.New(config)
v.AddFeature((outbound.Manager)(new(Manager))) v.AddFeature((outbound.Manager)(new(Manager)))
ctx := context.WithValue(context.Background(), xrayKey, v) ctx := context.WithValue(context.Background(), xrayKey, v)
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{ h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
Tag: "tag", Tag: "tag",
ProxySettings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
@@ -73,6 +75,7 @@ func TestOutboundWithStatCounter(t *testing.T) {
v, _ := core.New(config) v, _ := core.New(config)
v.AddFeature((outbound.Manager)(new(Manager))) v.AddFeature((outbound.Manager)(new(Manager)))
ctx := context.WithValue(context.Background(), xrayKey, v) ctx := context.WithValue(context.Background(), xrayKey, v)
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{ h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
Tag: "tag", Tag: "tag",
ProxySettings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),

View File

@@ -115,7 +115,7 @@ func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) erro
tag := handler.Tag() tag := handler.Tag()
if len(tag) > 0 { if len(tag) > 0 {
if _, found := m.taggedHandler[tag]; found { if _, found := m.taggedHandler[tag]; found {
return newError("existing tag found: " + tag) return errors.New("existing tag found: " + tag)
} }
m.taggedHandler[tag] = handler m.taggedHandler[tag] = handler
} else { } else {

View File

@@ -5,6 +5,7 @@ import (
"os" "os"
"github.com/sagernet/sing/common/uot" "github.com/sagernet/sing/common/uot"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
@@ -12,7 +13,7 @@ import (
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) { func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
if dest.Address == nil { if dest.Address == nil {
return nil, newError("nil destination address") return nil, errors.New("nil destination address")
} }
if !dest.Address.Family().IsDomain() { if !dest.Address.Family().IsDomain() {
return nil, os.ErrInvalid return nil, os.ErrInvalid
@@ -27,7 +28,7 @@ func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (s
} }
packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings) packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings)
if err != nil { if err != nil {
return nil, newError("unable to listen socket").Base(err) return nil, errors.New("unable to listen socket").Base(err)
} }
conn := uot.NewServerConn(packetConn, uotVersion) conn := uot.NewServerConn(packetConn, uotVersion)
return h.getStatCouterConnection(conn), nil return h.getStatCouterConnection(conn), nil

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
@@ -26,10 +27,10 @@ type Bridge struct {
// NewBridge creates a new Bridge instance. // NewBridge creates a new Bridge instance.
func NewBridge(config *BridgeConfig, dispatcher routing.Dispatcher) (*Bridge, error) { func NewBridge(config *BridgeConfig, dispatcher routing.Dispatcher) (*Bridge, error) {
if config.Tag == "" { if config.Tag == "" {
return nil, newError("bridge tag is empty") return nil, errors.New("bridge tag is empty")
} }
if config.Domain == "" { if config.Domain == "" {
return nil, newError("bridge domain is empty") return nil, errors.New("bridge domain is empty")
} }
b := &Bridge{ b := &Bridge{
@@ -74,7 +75,7 @@ func (b *Bridge) monitor() error {
if numWorker == 0 || numConnections/numWorker > 16 { if numWorker == 0 || numConnections/numWorker > 16 {
worker, err := NewBridgeWorker(b.domain, b.tag, b.dispatcher) worker, err := NewBridgeWorker(b.domain, b.tag, b.dispatcher)
if err != nil { if err != nil {
newError("failed to create bridge worker").Base(err).AtWarning().WriteToLog() errors.LogWarningInner(context.Background(), err, "failed to create bridge worker")
return nil return nil
} }
b.workers = append(b.workers, worker) b.workers = append(b.workers, worker)
@@ -157,7 +158,7 @@ func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
for _, b := range mb { for _, b := range mb {
var ctl Control var ctl Control
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil { if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
newError("failed to parse proto message").Base(err).WriteToLog() errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
break break
} }
if ctl.State != w.state { if ctl.State != w.state {

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/reverse/config.proto // source: app/reverse/config.proto
package reverse package reverse

View File

@@ -1,9 +0,0 @@
package reverse
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/mux" "github.com/xtls/xray-core/common/mux"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
@@ -27,11 +28,11 @@ type Portal struct {
func NewPortal(config *PortalConfig, ohm outbound.Manager) (*Portal, error) { func NewPortal(config *PortalConfig, ohm outbound.Manager) (*Portal, error) {
if config.Tag == "" { if config.Tag == "" {
return nil, newError("portal tag is empty") return nil, errors.New("portal tag is empty")
} }
if config.Domain == "" { if config.Domain == "" {
return nil, newError("portal domain is empty") return nil, errors.New("portal domain is empty")
} }
picker, err := NewStaticMuxPicker() picker, err := NewStaticMuxPicker()
@@ -62,20 +63,21 @@ func (p *Portal) Close() error {
} }
func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) error { func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) error {
outboundMeta := session.OutboundFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
if outboundMeta == nil { ob := outbounds[len(outbounds)-1]
return newError("outbound metadata not found").AtError() if ob == nil {
return errors.New("outbound metadata not found").AtError()
} }
if isDomain(outboundMeta.Target, p.domain) { if isDomain(ob.Target, p.domain) {
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{}) muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
if err != nil { if err != nil {
return newError("failed to create mux client worker").Base(err).AtWarning() return errors.New("failed to create mux client worker").Base(err).AtWarning()
} }
worker, err := NewPortalWorker(muxClient) worker, err := NewPortalWorker(muxClient)
if err != nil { if err != nil {
return newError("failed to create portal worker").Base(err) return errors.New("failed to create portal worker").Base(err)
} }
p.picker.AddWorker(worker) p.picker.AddWorker(worker)
@@ -96,7 +98,7 @@ func (o *Outbound) Tag() string {
func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) { func (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
if err := o.portal.HandleConnection(ctx, link); err != nil { if err := o.portal.HandleConnection(ctx, link); err != nil {
newError("failed to process reverse connection").Base(err).WriteToLog(session.ExportIDToError(ctx)) errors.LogInfoInner(ctx, err, "failed to process reverse connection")
common.Interrupt(link.Writer) common.Interrupt(link.Writer)
} }
} }
@@ -148,7 +150,7 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
defer p.access.Unlock() defer p.access.Unlock()
if len(p.workers) == 0 { if len(p.workers) == 0 {
return nil, newError("empty worker list") return nil, errors.New("empty worker list")
} }
var minIdx int = -1 var minIdx int = -1
@@ -182,7 +184,7 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
return p.workers[minIdx].client, nil return p.workers[minIdx].client, nil
} }
return nil, newError("no mux client worker available") return nil, errors.New("no mux client worker available")
} }
func (p *StaticMuxPicker) AddWorker(worker *PortalWorker) { func (p *StaticMuxPicker) AddWorker(worker *PortalWorker) {
@@ -206,15 +208,16 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
downlinkReader, downlinkWriter := pipe.New(opt...) downlinkReader, downlinkWriter := pipe.New(opt...)
ctx := context.Background() ctx := context.Background()
ctx = session.ContextWithOutbound(ctx, &session.Outbound{ outbounds := []*session.Outbound{{
Target: net.UDPDestination(net.DomainAddress(internalDomain), 0), Target: net.UDPDestination(net.DomainAddress(internalDomain), 0),
}) }}
ctx = session.ContextWithOutbounds(ctx, outbounds)
f := client.Dispatch(ctx, &transport.Link{ f := client.Dispatch(ctx, &transport.Link{
Reader: uplinkReader, Reader: uplinkReader,
Writer: downlinkWriter, Writer: downlinkWriter,
}) })
if !f { if !f {
return nil, newError("unable to dispatch control connection") return nil, errors.New("unable to dispatch control connection")
} }
w := &PortalWorker{ w := &PortalWorker{
client: client, client: client,
@@ -231,11 +234,11 @@ func NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {
func (w *PortalWorker) heartbeat() error { func (w *PortalWorker) heartbeat() error {
if w.client.Closed() { if w.client.Closed() {
return newError("client worker stopped") return errors.New("client worker stopped")
} }
if w.draining || w.writer == nil { if w.draining || w.writer == nil {
return newError("already disposed") return errors.New("already disposed")
} }
msg := &Control{} msg := &Control{}

View File

@@ -4,6 +4,10 @@ import (
"context" "context"
sync "sync" sync "sync"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension" "github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
) )
@@ -17,14 +21,58 @@ type BalancingPrincipleTarget interface {
} }
type RoundRobinStrategy struct { type RoundRobinStrategy struct {
FallbackTag string
ctx context.Context
observatory extension.Observatory
mu sync.Mutex mu sync.Mutex
index int index int
} }
func (s *RoundRobinStrategy) InjectContext(ctx context.Context) {
s.ctx = ctx
}
func (s *RoundRobinStrategy) GetPrincipleTarget(strings []string) []string {
return strings
}
func (s *RoundRobinStrategy) PickOutbound(tags []string) string { func (s *RoundRobinStrategy) PickOutbound(tags []string) string {
if len(s.FallbackTag) > 0 && s.observatory == nil {
common.Must(core.RequireFeatures(s.ctx, func(observatory extension.Observatory) error {
s.observatory = observatory
return nil
}))
}
if s.observatory != nil {
observeReport, err := s.observatory.GetObservation(s.ctx)
if err == nil {
aliveTags := make([]string, 0)
if result, ok := observeReport.(*observatory.ObservationResult); ok {
status := result.Status
statusMap := make(map[string]*observatory.OutboundStatus)
for _, outboundStatus := range status {
statusMap[outboundStatus.OutboundTag] = outboundStatus
}
for _, candidate := range tags {
if outboundStatus, found := statusMap[candidate]; found {
if outboundStatus.Alive {
aliveTags = append(aliveTags, candidate)
}
} else {
// unfound candidate is considered alive
aliveTags = append(aliveTags, candidate)
}
}
tags = aliveTags
}
}
}
n := len(tags) n := len(tags)
if n == 0 { if n == 0 {
panic("0 tags") // goes to fallbackTag
return ""
} }
s.mu.Lock() s.mu.Lock()
@@ -48,7 +96,7 @@ func (b *Balancer) PickOutbound() (string, error) {
candidates, err := b.SelectOutbounds() candidates, err := b.SelectOutbounds()
if err != nil { if err != nil {
if b.fallbackTag != "" { if b.fallbackTag != "" {
newError("fallback to [", b.fallbackTag, "], due to error: ", err).AtInfo().WriteToLog() errors.LogInfo(context.Background(), "fallback to [", b.fallbackTag, "], due to error: ", err)
return b.fallbackTag, nil return b.fallbackTag, nil
} }
return "", err return "", err
@@ -61,11 +109,11 @@ func (b *Balancer) PickOutbound() (string, error) {
} }
if tag == "" { if tag == "" {
if b.fallbackTag != "" { if b.fallbackTag != "" {
newError("fallback to [", b.fallbackTag, "], due to empty tag returned").AtInfo().WriteToLog() errors.LogInfo(context.Background(), "fallback to [", b.fallbackTag, "], due to empty tag returned")
return b.fallbackTag, nil return b.fallbackTag, nil
} }
// will use default handler // will use default handler
return "", newError("balancing strategy returns empty tag") return "", errors.New("balancing strategy returns empty tag")
} }
return tag, nil return tag, nil
} }
@@ -80,7 +128,7 @@ func (b *Balancer) InjectContext(ctx context.Context) {
func (b *Balancer) SelectOutbounds() ([]string, error) { func (b *Balancer) SelectOutbounds() ([]string, error) {
hs, ok := b.ohm.(outbound.HandlerSelector) hs, ok := b.ohm.(outbound.HandlerSelector)
if !ok { if !ok {
return nil, newError("outbound.Manager is not a HandlerSelector") return nil, errors.New("outbound.Manager is not a HandlerSelector")
} }
tags := hs.Select(b.selectors) tags := hs.Select(b.selectors)
return tags, nil return tags, nil
@@ -92,13 +140,13 @@ func (r *Router) GetPrincipleTarget(tag string) ([]string, error) {
if s, ok := b.strategy.(BalancingPrincipleTarget); ok { if s, ok := b.strategy.(BalancingPrincipleTarget); ok {
candidates, err := b.SelectOutbounds() candidates, err := b.SelectOutbounds()
if err != nil { if err != nil {
return nil, newError("unable to select outbounds").Base(err) return nil, errors.New("unable to select outbounds").Base(err)
} }
return s.GetPrincipleTarget(candidates), nil return s.GetPrincipleTarget(candidates), nil
} }
return nil, newError("unsupported GetPrincipleTarget") return nil, errors.New("unsupported GetPrincipleTarget")
} }
return nil, newError("cannot find tag") return nil, errors.New("cannot find tag")
} }
// SetOverrideTarget implements routing.BalancerOverrider // SetOverrideTarget implements routing.BalancerOverrider
@@ -107,7 +155,7 @@ func (r *Router) SetOverrideTarget(tag, target string) error {
b.override.Put(target) b.override.Put(target)
return nil return nil
} }
return newError("cannot find tag") return errors.New("cannot find tag")
} }
// GetOverrideTarget implements routing.BalancerOverrider // GetOverrideTarget implements routing.BalancerOverrider
@@ -115,5 +163,5 @@ func (r *Router) GetOverrideTarget(tag string) (string, error) {
if b, ok := r.balancers[tag]; ok { if b, ok := r.balancers[tag]; ok {
return b.override.Get(), nil return b.override.Get(), nil
} }
return "", newError("cannot find tag") return "", errors.New("cannot find tag")
} }

View File

@@ -2,6 +2,8 @@ package router
import ( import (
sync "sync" sync "sync"
"github.com/xtls/xray-core/common/errors"
) )
func (r *Router) OverrideBalancer(balancer string, target string) error { func (r *Router) OverrideBalancer(balancer string, target string) error {
@@ -13,7 +15,7 @@ func (r *Router) OverrideBalancer(balancer string, target string) error {
} }
} }
if b == nil { if b == nil {
return newError("balancer '", balancer, "' not found") return errors.New("balancer '", balancer, "' not found")
} }
b.override.Put(target) b.override.Put(target)
return nil return nil

View File

@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
@@ -38,7 +39,7 @@ func (s *routingServer) GetBalancerInfo(ctx context.Context, request *GetBalance
{ {
res, err := pt.GetPrincipleTarget(request.GetTag()) res, err := pt.GetPrincipleTarget(request.GetTag())
if err != nil { if err != nil {
newError("unable to obtain principle target").Base(err).AtInfo().WriteToLog() errors.LogInfoInner(ctx, err, "unable to obtain principle target")
} else { } else {
ret.Balancer.PrincipleTarget = &PrincipleTargetInfo{Tag: res} ret.Balancer.PrincipleTarget = &PrincipleTargetInfo{Tag: res}
} }
@@ -51,21 +52,21 @@ func (s *routingServer) OverrideBalancerTarget(ctx context.Context, request *Ove
if bo, ok := s.router.(routing.BalancerOverrider); ok { if bo, ok := s.router.(routing.BalancerOverrider); ok {
return &OverrideBalancerTargetResponse{}, bo.SetOverrideTarget(request.BalancerTag, request.Target) return &OverrideBalancerTargetResponse{}, bo.SetOverrideTarget(request.BalancerTag, request.Target)
} }
return nil, newError("unsupported router implementation") return nil, errors.New("unsupported router implementation")
} }
func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*AddRuleResponse, error) { func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*AddRuleResponse, error) {
if bo, ok := s.router.(routing.Router); ok { if bo, ok := s.router.(routing.Router); ok {
return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend) return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend)
} }
return nil, newError("unsupported router implementation") return nil, errors.New("unsupported router implementation")
} }
func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) { func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
if bo, ok := s.router.(routing.Router); ok { if bo, ok := s.router.(routing.Router); ok {
return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag) return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
} }
return nil, newError("unsupported router implementation") return nil, errors.New("unsupported router implementation")
} }
// NewRoutingServer creates a statistics service with statistics manager. // NewRoutingServer creates a statistics service with statistics manager.
@@ -78,7 +79,7 @@ func NewRoutingServer(router routing.Router, routingStats stats.Channel) Routing
func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest) (*RoutingContext, error) { func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest) (*RoutingContext, error) {
if request.RoutingContext == nil { if request.RoutingContext == nil {
return nil, newError("Invalid routing request.") return nil, errors.New("Invalid routing request.")
} }
route, err := s.router.PickRoute(AsRoutingContext(request.RoutingContext)) route, err := s.router.PickRoute(AsRoutingContext(request.RoutingContext))
if err != nil { if err != nil {
@@ -93,7 +94,7 @@ func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest
func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequest, stream RoutingService_SubscribeRoutingStatsServer) error { func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequest, stream RoutingService_SubscribeRoutingStatsServer) error {
if s.routingStats == nil { if s.routingStats == nil {
return newError("Routing statistics not enabled.") return errors.New("Routing statistics not enabled.")
} }
genMessage := AsProtobufMessage(request.FieldSelectors) genMessage := AsProtobufMessage(request.FieldSelectors)
subscriber, err := stats.SubscribeRunnableChannel(s.routingStats) subscriber, err := stats.SubscribeRunnableChannel(s.routingStats)
@@ -105,11 +106,11 @@ func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequ
select { select {
case value, ok := <-subscriber: case value, ok := <-subscriber:
if !ok { if !ok {
return newError("Upstream closed the subscriber channel.") return errors.New("Upstream closed the subscriber channel.")
} }
route, ok := value.(routing.Route) route, ok := value.(routing.Route)
if !ok { if !ok {
return newError("Upstream sent malformed statistics.") return errors.New("Upstream sent malformed statistics.")
} }
err := stream.Send(genMessage(route)) err := stream.Send(genMessage(route))
if err != nil { if err != nil {

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/router/command/command.proto // source: app/router/command/command.proto
package command package command

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions: // versions:
// - protoc-gen-go-grpc v1.3.0 // - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1 // - protoc v5.27.0
// source: app/router/command/command.proto // source: app/router/command/command.proto
package command package command

View File

@@ -272,7 +272,7 @@ func TestServiceSubscribeSubsetOfFields(t *testing.T) {
} }
} }
func TestSerivceTestRoute(t *testing.T) { func TestServiceTestRoute(t *testing.T) {
c := stats.NewChannel(&stats.ChannelConfig{ c := stats.NewChannel(&stats.ChannelConfig{
SubscriberLimit: 1, SubscriberLimit: 1,
BufferSize: 16, BufferSize: 16,

View File

@@ -1,9 +0,0 @@
package command
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -4,6 +4,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher" "github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
@@ -49,12 +50,12 @@ var matcherTypeMap = map[Domain_Type]strmatcher.Type{
func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) { func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
matcherType, f := matcherTypeMap[domain.Type] matcherType, f := matcherTypeMap[domain.Type]
if !f { if !f {
return nil, newError("unsupported domain type", domain.Type) return nil, errors.New("unsupported domain type", domain.Type)
} }
matcher, err := matcherType.New(domain.Value) matcher, err := matcherType.New(domain.Value)
if err != nil { if err != nil {
return nil, newError("failed to create domain matcher").Base(err) return nil, errors.New("failed to create domain matcher").Base(err)
} }
return matcher, nil return matcher, nil
@@ -69,7 +70,7 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
for _, d := range domains { for _, d := range domains {
matcherType, f := matcherTypeMap[d.Type] matcherType, f := matcherTypeMap[d.Type]
if !f { if !f {
return nil, newError("unsupported domain type", d.Type) return nil, errors.New("unsupported domain type", d.Type)
} }
_, err := g.AddPattern(d.Value, matcherType) _, err := g.AddPattern(d.Value, matcherType)
if err != nil { if err != nil {

View File

@@ -1,9 +1,11 @@
package router package router
import ( import (
"context"
"regexp" "regexp"
"strings" "strings"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
@@ -36,7 +38,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
case "linear": case "linear":
matcher, err := NewDomainMatcher(rr.Domain) matcher, err := NewDomainMatcher(rr.Domain)
if err != nil { if err != nil {
return nil, newError("failed to build domain condition").Base(err) return nil, errors.New("failed to build domain condition").Base(err)
} }
conds.Add(matcher) conds.Add(matcher)
case "mph", "hybrid": case "mph", "hybrid":
@@ -44,9 +46,9 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
default: default:
matcher, err := NewMphMatcherGroup(rr.Domain) matcher, err := NewMphMatcherGroup(rr.Domain)
if err != nil { if err != nil {
return nil, newError("failed to build domain condition with MphDomainMatcher").Base(err) return nil, errors.New("failed to build domain condition with MphDomainMatcher").Base(err)
} }
newError("MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)").AtDebug().WriteToLog() errors.LogDebug(context.Background(), "MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)")
conds.Add(matcher) conds.Add(matcher)
} }
} }
@@ -116,7 +118,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
} }
if conds.Len() == 0 { if conds.Len() == 0 {
return nil, newError("this rule has no effective fields").AtWarning() return nil, errors.New("this rule has no effective fields").AtWarning()
} }
return conds, nil return conds, nil
@@ -135,7 +137,7 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
case "roundrobin": case "roundrobin":
return &Balancer{ return &Balancer{
selectors: br.OutboundSelector, selectors: br.OutboundSelector,
strategy: &RoundRobinStrategy{}, strategy: &RoundRobinStrategy{FallbackTag: br.FallbackTag},
fallbackTag: br.FallbackTag, fallbackTag: br.FallbackTag,
ohm: ohm, ohm: ohm,
}, nil }, nil
@@ -146,7 +148,7 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
} }
s, ok := i.(*StrategyLeastLoadConfig) s, ok := i.(*StrategyLeastLoadConfig)
if !ok { if !ok {
return nil, newError("not a StrategyLeastLoadConfig").AtError() return nil, errors.New("not a StrategyLeastLoadConfig").AtError()
} }
leastLoadStrategy := NewLeastLoadStrategy(s) leastLoadStrategy := NewLeastLoadStrategy(s)
return &Balancer{ return &Balancer{
@@ -162,9 +164,9 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
selectors: br.OutboundSelector, selectors: br.OutboundSelector,
ohm: ohm, ohm: ohm,
fallbackTag: br.FallbackTag, fallbackTag: br.FallbackTag,
strategy: &RandomStrategy{}, strategy: &RandomStrategy{FallbackTag: br.FallbackTag},
}, nil }, nil
default: default:
return nil, newError("unrecognized balancer type") return nil, errors.New("unrecognized balancer type")
} }
} }

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/router/config.proto // source: app/router/config.proto
package router package router

View File

@@ -1,9 +0,0 @@
package router
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -7,6 +7,7 @@ import (
sync "sync" sync "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
@@ -68,7 +69,7 @@ func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm out
if len(btag) > 0 { if len(btag) > 0 {
brule, found := r.balancers[btag] brule, found := r.balancers[btag]
if !found { if !found {
return newError("balancer ", btag, " not found") return errors.New("balancer ", btag, " not found")
} }
rr.Balancer = brule rr.Balancer = brule
} }
@@ -101,7 +102,7 @@ func (r *Router) AddRule(config *serial.TypedMessage, shouldAppend bool) error {
if c, ok := inst.(*Config); ok { if c, ok := inst.(*Config); ok {
return r.ReloadRules(c, shouldAppend) return r.ReloadRules(c, shouldAppend)
} }
return newError("AddRule: config type error") return errors.New("AddRule: config type error")
} }
func (r *Router) ReloadRules(config *Config, shouldAppend bool) error { func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
@@ -115,7 +116,7 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
for _, rule := range config.BalancingRule { for _, rule := range config.BalancingRule {
_, found := r.balancers[rule.Tag] _, found := r.balancers[rule.Tag]
if found { if found {
return newError("duplicate balancer tag") return errors.New("duplicate balancer tag")
} }
balancer, err := rule.Build(r.ohm, r.dispatcher) balancer, err := rule.Build(r.ohm, r.dispatcher)
if err != nil { if err != nil {
@@ -127,7 +128,7 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
for _, rule := range config.Rule { for _, rule := range config.Rule {
if r.RuleExists(rule.GetRuleTag()) { if r.RuleExists(rule.GetRuleTag()) {
return newError("duplicate ruleTag ", rule.GetRuleTag()) return errors.New("duplicate ruleTag ", rule.GetRuleTag())
} }
cond, err := rule.BuildCondition() cond, err := rule.BuildCondition()
if err != nil { if err != nil {
@@ -142,7 +143,7 @@ func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
if len(btag) > 0 { if len(btag) > 0 {
brule, found := r.balancers[btag] brule, found := r.balancers[btag]
if !found { if !found {
return newError("balancer ", btag, " not found") return errors.New("balancer ", btag, " not found")
} }
rr.Balancer = brule rr.Balancer = brule
} }
@@ -178,7 +179,7 @@ func (r *Router) RemoveRule(tag string) error {
r.rules = newRules r.rules = newRules
return nil return nil
} }
return newError("empty tag name!") return errors.New("empty tag name!")
} }
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) { func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {

View File

@@ -45,7 +45,9 @@ func TestSimpleRouter(t *testing.T) {
HandlerSelector: mockHs, HandlerSelector: mockHs,
}, nil)) }, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)}) ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
}})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err) common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" { if tag := route.GetOutboundTag(); tag != "test" {
@@ -86,7 +88,9 @@ func TestSimpleBalancer(t *testing.T) {
HandlerSelector: mockHs, HandlerSelector: mockHs,
}, nil)) }, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)}) ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
}})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err) common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" { if tag := route.GetOutboundTag(); tag != "test" {
@@ -174,7 +178,9 @@ func TestIPOnDemand(t *testing.T) {
r := new(Router) r := new(Router)
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil)) common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)}) ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
}})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err) common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" { if tag := route.GetOutboundTag(); tag != "test" {
@@ -213,7 +219,9 @@ func TestIPIfNonMatchDomain(t *testing.T) {
r := new(Router) r := new(Router)
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil)) common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress("example.com"), 80)}) ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
Target: net.TCPDestination(net.DomainAddress("example.com"), 80),
}})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err) common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" { if tag := route.GetOutboundTag(); tag != "test" {
@@ -247,7 +255,9 @@ func TestIPIfNonMatchIP(t *testing.T) {
r := new(Router) r := new(Router)
common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil)) common.Must(r.Init(context.TODO(), config, mockDNS, nil, nil))
ctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)}) ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
Target: net.TCPDestination(net.LocalHostIP, 80),
}})
route, err := r.PickRoute(routing_session.AsRoutingContext(ctx)) route, err := r.PickRoute(routing_session.AsRoutingContext(ctx))
common.Must(err) common.Must(err)
if tag := route.GetOutboundTag(); tag != "test" { if tag := route.GetOutboundTag(); tag != "test" {

View File

@@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/app/observatory" "github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension" "github.com/xtls/xray-core/features/extension"
) )
@@ -95,7 +96,7 @@ func (s *LeastLoadStrategy) pickOutbounds(candidates []string) []*node {
// with 'balancer.fallbackTag', it means: selects qualified nodes or use the fallback. // with 'balancer.fallbackTag', it means: selects qualified nodes or use the fallback.
func (s *LeastLoadStrategy) selectLeastLoad(nodes []*node) []*node { func (s *LeastLoadStrategy) selectLeastLoad(nodes []*node) []*node {
if len(nodes) == 0 { if len(nodes) == 0 {
newError("least load: no qualified outbound").AtInfo().WriteToLog() errors.LogInfo(s.ctx, "least load: no qualified outbound")
return nil return nil
} }
expected := int(s.settings.Expected) expected := int(s.settings.Expected)
@@ -123,7 +124,7 @@ func (s *LeastLoadStrategy) selectLeastLoad(nodes []*node) []*node {
} }
// don't continue if find expected selects // don't continue if find expected selects
if count >= expected { if count >= expected {
newError("applied baseline: ", baseline).AtDebug().WriteToLog() errors.LogDebug(s.ctx, "applied baseline: ", baseline)
break break
} }
} }
@@ -142,7 +143,7 @@ func (s *LeastLoadStrategy) getNodes(candidates []string, maxRTT time.Duration)
} }
observeResult, err := s.observer.GetObservation(s.ctx) observeResult, err := s.observer.GetObservation(s.ctx)
if err != nil { if err != nil {
newError("cannot get observation").Base(err).WriteToLog() errors.LogInfoInner(s.ctx, err, "cannot get observation")
return make([]*node, 0) return make([]*node, 0)
} }

View File

@@ -5,6 +5,7 @@ import (
"github.com/xtls/xray-core/app/observatory" "github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension" "github.com/xtls/xray-core/features/extension"
) )
@@ -32,7 +33,7 @@ func (l *LeastPingStrategy) PickOutbound(strings []string) string {
observeReport, err := l.observatory.GetObservation(l.ctx) observeReport, err := l.observatory.GetObservation(l.ctx)
if err != nil { if err != nil {
newError("cannot get observe report").Base(err).WriteToLog() errors.LogInfoInner(l.ctx, err, "cannot get observe report")
return "" return ""
} }
outboundsList := outboundList(strings) outboundsList := outboundList(strings)

View File

@@ -1,17 +1,63 @@
package router package router
import ( import (
"context"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension"
) )
// RandomStrategy represents a random balancing strategy // RandomStrategy represents a random balancing strategy
type RandomStrategy struct{} type RandomStrategy struct{
FallbackTag string
ctx context.Context
observatory extension.Observatory
}
func (s *RandomStrategy) InjectContext(ctx context.Context) {
s.ctx = ctx
}
func (s *RandomStrategy) GetPrincipleTarget(strings []string) []string { func (s *RandomStrategy) GetPrincipleTarget(strings []string) []string {
return strings return strings
} }
func (s *RandomStrategy) PickOutbound(candidates []string) string { func (s *RandomStrategy) PickOutbound(candidates []string) string {
if len(s.FallbackTag) > 0 && s.observatory == nil {
common.Must(core.RequireFeatures(s.ctx, func(observatory extension.Observatory) error {
s.observatory = observatory
return nil
}))
}
if s.observatory != nil {
observeReport, err := s.observatory.GetObservation(s.ctx)
if err == nil {
aliveTags := make([]string, 0)
if result, ok := observeReport.(*observatory.ObservationResult); ok {
status := result.Status
statusMap := make(map[string]*observatory.OutboundStatus)
for _, outboundStatus := range status {
statusMap[outboundStatus.OutboundTag] = outboundStatus
}
for _, candidate := range candidates {
if outboundStatus, found := statusMap[candidate]; found {
if outboundStatus.Alive {
aliveTags = append(aliveTags, candidate)
}
} else {
// unfound candidate is considered alive
aliveTags = append(aliveTags, candidate)
}
}
candidates = aliveTags
}
}
}
count := len(candidates) count := len(candidates)
if count == 0 { if count == 0 {
// goes to fallbackTag // goes to fallbackTag

View File

@@ -1,10 +1,13 @@
package router package router
import ( import (
"context"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"github.com/xtls/xray-core/common/errors"
) )
type weightScaler func(value, weight float64) float64 type weightScaler func(value, weight float64) float64
@@ -64,7 +67,7 @@ func (s *WeightManager) findValue(tag string) float64 {
} }
weight, err := strconv.ParseFloat(numStr, 64) weight, err := strconv.ParseFloat(numStr, 64)
if err != nil { if err != nil {
newError("unexpected error from ParseFloat: ", err).AtError().WriteToLog() errors.LogError(context.Background(), "unexpected error from ParseFloat: ", err)
return s.defaultWeight return s.defaultWeight
} }
return weight return weight
@@ -82,7 +85,7 @@ func (s *WeightManager) getMatch(tag, find string, isRegexp bool) string {
} }
r, err := regexp.Compile(find) r, err := regexp.Compile(find)
if err != nil { if err != nil {
newError("invalid regexp: ", find, "err: ", err).AtError().WriteToLog() errors.LogError(context.Background(), "invalid regexp: ", find, "err: ", err)
return "" return ""
} }
return r.FindString(tag) return r.FindString(tag)

View File

@@ -5,6 +5,7 @@ import (
"sync" "sync"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
) )
// Channel is an implementation of stats.Channel. // Channel is an implementation of stats.Channel.
@@ -44,7 +45,7 @@ func (c *Channel) Subscribe() (chan interface{}, error) {
c.access.Lock() c.access.Lock()
defer c.access.Unlock() defer c.access.Unlock()
if c.subsLimit > 0 && len(c.subscribers) >= c.subsLimit { if c.subsLimit > 0 && len(c.subscribers) >= c.subsLimit {
return nil, newError("Number of subscribers has reached limit") return nil, errors.New("Number of subscribers has reached limit")
} }
subscriber := make(chan interface{}, c.bufferSize) subscriber := make(chan interface{}, c.bufferSize)
c.subscribers = append(c.subscribers, subscriber) c.subscribers = append(c.subscribers, subscriber)

View File

@@ -95,7 +95,7 @@ func TestStatsChannel(t *testing.T) {
} }
} }
func TestStatsChannelUnsubcribe(t *testing.T) { func TestStatsChannelUnsubscribe(t *testing.T) {
c := NewChannel(&ChannelConfig{Blocking: true}) c := NewChannel(&ChannelConfig{Blocking: true})
common.Must(c.Start()) common.Must(c.Start())
defer c.Close() defer c.Close()

View File

@@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/strmatcher" "github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
feature_stats "github.com/xtls/xray-core/features/stats" feature_stats "github.com/xtls/xray-core/features/stats"
@@ -31,7 +32,7 @@ func NewStatsServer(manager feature_stats.Manager) StatsServiceServer {
func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) { func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {
c := s.stats.GetCounter(request.Name) c := s.stats.GetCounter(request.Name)
if c == nil { if c == nil {
return nil, newError(request.Name, " not found.") return nil, errors.New(request.Name, " not found.")
} }
var value int64 var value int64
if request.Reset_ { if request.Reset_ {
@@ -57,7 +58,7 @@ func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest
manager, ok := s.stats.(*stats.Manager) manager, ok := s.stats.(*stats.Manager)
if !ok { if !ok {
return nil, newError("QueryStats only works its own stats.Manager.") return nil, errors.New("QueryStats only works its own stats.Manager.")
} }
manager.VisitCounters(func(name string, c feature_stats.Counter) bool { manager.VisitCounters(func(name string, c feature_stats.Counter) bool {

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.33.0 // protoc-gen-go v1.34.1
// protoc v4.23.1 // protoc v5.27.0
// source: app/stats/command/command.proto // source: app/stats/command/command.proto
package command package command

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions: // versions:
// - protoc-gen-go-grpc v1.3.0 // - protoc-gen-go-grpc v1.3.0
// - protoc v4.23.1 // - protoc v5.27.0
// source: app/stats/command/command.proto // source: app/stats/command/command.proto
package command package command

View File

@@ -1,9 +0,0 @@
package command
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

Some files were not shown because too many files have changed in this diff Show More