diff --git a/.github/update.log b/.github/update.log
index e144cf604c..8465ae23d9 100644
--- a/.github/update.log
+++ b/.github/update.log
@@ -642,3 +642,4 @@ Update On Mon May 6 20:31:49 CEST 2024
Update On Tue May 7 20:29:39 CEST 2024
Update On Thu May 9 16:22:44 CEST 2024
Update On Thu May 9 20:28:46 CEST 2024
+Update On Fri May 10 20:29:17 CEST 2024
diff --git a/brook/README.md b/brook/README.md
index a8c46140ec..a2faa25747 100644
--- a/brook/README.md
+++ b/brook/README.md
@@ -4,7 +4,7 @@
A cross-platform programmable network tool.
# Sponsor
-**❤️ [Shiliew - China Optimized Network App](https://www.txthinking.com/shiliew.html)**
+**❤️ [Shiliew - A network app designed for those who value their time](https://www.txthinking.com/shiliew.html)**
# Getting Started
## Server
@@ -28,11 +28,7 @@ brook server -l :9999 -p hello
| [](https://apps.apple.com/us/app/brook-network-tool/id1216002642) | [](https://github.com/txthinking/brook/releases/latest/download/Brook.apk) | [](https://apps.apple.com/us/app/brook-network-tool/id1216002642) | [](https://github.com/txthinking/brook/releases/latest/download/Brook.msix) | [](https://github.com/txthinking/brook/releases/latest/download/Brook.bin) | [](https://github.com/txthinking/brook/releases) |
| / | / | [App Mode](https://www.txthinking.com/talks/articles/macos-app-mode-en.article) | [How](https://www.txthinking.com/talks/articles/msix-brook-en.article) | [How](https://www.txthinking.com/talks/articles/linux-app-brook-en.article) | [How](https://www.txthinking.com/talks/articles/brook-openwrt-en.article) |
-## CLI Client
-
-```
-brook client -s 1.2.3.4:9999 -p hello --socks5 127.0.0.1:1080
-```
+> You may want to use `brook link` to customize some parameters
# GUI Documentation
## Software for which this article applies
@@ -43,11 +39,12 @@ brook client -s 1.2.3.4:9999 -p hello --socks5 127.0.0.1:1080
## Programmable
-```
-Brook GUI will pass different global variables to the script at different times, and the script only needs to assign the processing result to the global variable out
-```
+Brook GUI will pass different _global variables_ to the script at different times, and the script only needs to assign the processing result to the global variable `out`
-### Introduction to incoming variables
+- address: We call it address which includes both host and port. For example, an ip address contains an ip and a port; a domain address contains a domain and a port.
+- Fake DNS: Fake DNS can allow you to obtain domain address on `in_address` step. [How Fake DNS works](https://www.txthinking.com/talks/articles/brook-fakedns-en.article)
+
+### Variables
| variable | type | condition | timing | description | out type |
| ------------------------------ | ---- | ----------- | --------------------------------- | ------------------------------------------------- | -------- |
@@ -139,7 +136,53 @@ Brook GUI will pass different global variables to the script at different times,
`out`, must be set to a response
-## Write script
+## Module
+
+There are already some modules: https://github.com/txthinking/brook/blob/master/programmable/modules/
+
+### Brook GUI
+
+In Brook GUI, scripts are abstracted into modules, and it will automatically combine [_header.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo) and [_footer.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo), so you only need to write the module itself.
+
+```
+modules = append(modules, {
+ // If you want to predefine multiple brook links, and then programmatically specify which one to connect to, then define `brooklinks` key a function
+ brooklinks: func(m) {
+ // Please refer to the example in `brooklinks.tengo`
+ },
+ // If you want to intercept and handle a DNS query, then define `dnsquery` key a function, `m` is the `in_dnsquery`
+ dnsquery: func(m) {
+ // Please refer to the example in `block_aaaa.tengo`
+ },
+ // If you want to intercept and handle an address, then define `address` key a function, `m` is the `in_address`
+ address: func(m) {
+ // Please refer to the example in `block_google_secure_dns.tengo`
+ },
+ // If you want to intercept and handle a http request, then define `httprequest` key a function, `request` is the `in_httprequest`
+ httprequest: func(request) {
+ // Please refer to the example in `ios_app_downgrade.tengo` or `redirect_google_cn.tengo`
+ },
+ // If you want to intercept and handle a http response, then define `httpresponse` key a function, `request` is the `in_httprequest`, `response` is the `in_httpresponse`
+ httpresponse: func(request, response) {
+ // Please refer to the example in `response_sample.tengo`
+ }
+})
+```
+
+### tun2brook
+
+If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:
+
+```
+cat _header.tengo > my.tengo
+
+cat block_google_secure_dns.tengo >> my.tengo
+cat block_aaaa.tengo >> my.tengo
+
+cat _footer.tengo >> my.tengo
+```
+
+## Syntax
[Tengo Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
@@ -186,9 +229,9 @@ Library
* hexencode(s string) => string/error: returns the hexadecimal encoding of src
```
-## Debug script
+## Debug
-It is recommended to use [tun2brook](https://github.com/txthinking/tun2brook) on desktop to debug with `fmt.println`
+If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use [tun2brook](https://github.com/txthinking/tun2brook) on desktop to debug with `fmt.println`
## Install CA
@@ -232,8 +275,7 @@ https://txthinking.github.io/ca/ca.pem
| [Socks5 Configurator](https://chromewebstore.google.com/detail/socks5-configurator/hnpgnjkeaobghpjjhaiemlahikgmnghb) | If you prefer CLI brook client |
| [IPvBar](https://chromewebstore.google.com/detail/ipvbar/nepjlegfiihpkcdhlmaebfdfppckonlj) | See domain, IP and country in browser |
| [TxThinking SSH](https://www.txthinking.com/ssh.html) | A SSH Terminal |
-| [Brook Deploy](https://www.txthinking.com/deploy.html) | Deploy brook with GUI |
-| [brook-manager](https://github.com/txthinking/brook-manager) | Brook Manager is a Brook management system for medium to large merchants |
+| [brook-user-system](https://github.com/txthinkinginc/brook-user-system) | A Brook User System |
| [TxThinking](https://www.txthinking.com) | Everything |
# CLI Documentation
@@ -257,6 +299,16 @@ Brook [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...]
# GLOBAL OPTIONS
+- **--blockCIDR4List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt. Works with server/wsserver/wssserver/quicserver
+
+- **--blockCIDR6List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt. Works with server/wsserver/wssserver/quicserver
+
+- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt. Works with server/wsserver/wssserver/quicserver
+
+- **--blockGeoIP**="": Block IP by Geo country code, such as US. Works with server/wsserver/wssserver/quicserver
+
+- **--blockListUpdateInterval**="": Update list --blockDomainList,--blockCIDR4List,--blockCIDR6List interval, second. default 0, only read one time on start (default: 0)
+
- **--clientHKDFInfo**="": client HKDF info, most time you don't need to change this, if changed, all and each brook links in client side must be same, I mean each (default: "brook")
- **--dialWithDNS**="": When a domain name needs to be resolved, use the specified DNS. Such as 8.8.8.8:53 or https://dns.google/dns-query?address=8.8.8.8%3A443, the address is required. Note that for client-side commands, this does not affect the client passing the domain address to the server
@@ -287,7 +339,9 @@ Brook [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...]
- **--ipLimitWait**="": How long (s) to wait for recovery after exceeding ipLimitMax (default: 0)
-- **--log**="": Enable log. A valid value is file path or 'console'. If you want to debug SOCKS5 lib, set env SOCKS5_DEBUG=true
+- **--log**="": Enable log. A valid value is file path or 'console'. Send SIGUSR1 to me to reset the log file on unix system. If you want to debug SOCKS5 lib, set env SOCKS5_DEBUG=true
+
+- **--pid**="": A file path used to store pid. Send SIGUSR1 to me to reset the --serverLog file on unix system
- **--pprof**="": go http pprof listen addr, such as :6060
@@ -297,11 +351,17 @@ Brook [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...]
- **--serverHKDFInfo**="": server HKDF info, most time you don't need to change this, if changed, all and each brook links in client side must be same, I mean each (default: "brook")
-- **--serverLog**="": Enable server log, traffic and more. A valid value is file path or 'console'. Mutually exclusive with the --log parameter. Works with server/wsserver/wssserver/quicserver
+- **--serverLog**="": Enable server log, traffic and more. A valid value is file path or 'console'. Send SIGUSR1 to me to reset the log file on unix system. Mutually exclusive with the --log parameter. Works with server/wsserver/wssserver/quicserver with brook protocol
-- **--speedLimit**="": Limit speed (b), such as 500kb/s: 500000, works with server/wsserver/wssserver/quicserver (default: 0)
+- **--speedLimit**="": Limit speed (b), 500kb/s such as: 500000, works with server/wsserver/wssserver/quicserver (default: 0)
-- **--tag**="": Tag can be used to the process, will be append into log or serverLog, such as: 'key1:value1'
+- **--tag**="": Tag can be used to the process, will be append into log or serverLog, such as: 'key1:value1'. All tags will also be appended as query parameters one by one to the userAPI
+
+- **--userAPI**="": When you build your own user system, Brook Server will send GET request to your userAPI to check if token is valid, for example: https://your-api-server.com/a_unpredictable_path. Yes, it is recommended to add an unpredictable path to your https API, of course, you can also use the http api for internal network communication. The request format is https://your-api-server.com/a_unpredictable_path?token=xxx. When the response is 200, the body should be the user's unique identifier, such as user ID; all other status codes are considered to represent an illegitimate user, and in these cases, the body should be a string describing the error. It should be used with --serverLog and server/wsserver/wssserver/quicserver with brook protocol. For more information, please read https://github.com/txthinking/brook/blob/master/protocol/user.md
+
+- **--userAPIInvalidCacheTime**="": Once a token is checked and invalid, the userAPI will not be requested to validate again for a certain period (s). A reasonable value must be set, otherwise it will affect the performance of each incoming connection. Note that this may affect the user experience, when you change the user status from invalid to valid in your user system (default: 1800)
+
+- **--userAPIValidCacheTime**="": Once a token is checked and valid, the userAPI will not be requested to validate again for a certain period (s). A reasonable value must be set, otherwise it will affect the performance of each incoming connection (default: 3600)
- **--version, -v**: print the version
@@ -310,15 +370,17 @@ Brook [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...]
## server
-Run as brook server, both TCP and UDP
+Start a brook server that supports tcp and udp
-- **--blockCIDR4List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead
-- **--blockCIDR6List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead
-- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead
-- **--blockGeoIP**="": Block IP by Geo country code, such as US
+- **--blockGeoIP**="": This option will be removed in a future version, please use the global option instead
+
+- **--example**: Show a minimal example of usage
- **--listen, -l**="": Listen address, like: ':9999'
@@ -328,14 +390,18 @@ Run as brook server, both TCP and UDP
- **--udpTimeout**="": time (s) (default: 0)
-- **--updateListInterval**="": Update list interval, second. default 0, only read one time on start (default: 0)
+- **--updateListInterval**="": This option will be removed in a future version, please use the global option instead (default: 0)
## client
-Run as brook client, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook client <-> $ brook server <-> dst]
+Start a brook client that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook client <-> $ brook server <-> dst]
+
+- **--example**: Show a minimal example of usage
- **--http**="": Where to listen for HTTP proxy connections
+- **--link**="": brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored
+
- **--password, -p**="": Brook server password
- **--server, -s**="": Brook server address, like: 1.2.3.4:9999
@@ -348,19 +414,19 @@ Run as brook client, both TCP and UDP, to start a socks5 proxy, [src <-> socks5
- **--udpTimeout**="": time (s) (default: 0)
-- **--udpovertcp**: UDP over TCP
-
## wsserver
-Run as brook wsserver, both TCP and UDP, it will start a standard http server and websocket server
+Start a brook wsserver that supports tcp and udp. It opens a standard http server and a websocket server
-- **--blockCIDR4List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead
-- **--blockCIDR6List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead
-- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead
-- **--blockGeoIP**="": Block IP by Geo country code, such as US
+- **--blockGeoIP**="": This option will be removed in a future version, please use the global option instead
+
+- **--example**: Show a minimal example of usage
- **--listen, -l**="": Listen address, like: ':80'
@@ -372,7 +438,7 @@ Run as brook wsserver, both TCP and UDP, it will start a standard http server an
- **--udpTimeout**="": time (s) (default: 0)
-- **--updateListInterval**="": Update list interval, second. default 0, only read one time on start (default: 0)
+- **--updateListInterval**="": This option will be removed in a future version, please use the global option instead (default: 0)
- **--withoutBrookProtocol**: The data will not be encrypted with brook protocol
@@ -380,12 +446,14 @@ Run as brook wsserver, both TCP and UDP, it will start a standard http server an
## wsclient
-Run as brook wsclient, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook wsclient <-> $ brook wsserver <-> dst]
+Start a brook wsclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook wsclient <-> $ brook wsserver <-> dst]
-- **--address**="": Specify address instead of resolving addresses from host, such as 1.2.3.4:443
+- **--example**: Show a minimal example of usage
- **--http**="": Where to listen for HTTP proxy connections
+- **--link**="": brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored
+
- **--password, -p**="": Brook wsserver password
- **--socks5**="": Where to listen for SOCKS5 connections (default: 127.0.0.1:1080)
@@ -396,21 +464,19 @@ Run as brook wsclient, both TCP and UDP, to start a socks5 proxy, [src <-> socks
- **--udpTimeout**="": time (s) (default: 0)
-- **--withoutBrookProtocol**: The data will not be encrypted with brook protocol
-
- **--wsserver, -s**="": Brook wsserver address, like: ws://1.2.3.4:80, if no path then /ws will be used. Do not omit the port under any circumstances
## wssserver
-Run as brook wssserver, both TCP and UDP, it will start a standard https server and websocket server
+Start a brook wssserver that supports tcp and udp. It opens a standard https server and a websocket server
-- **--blockCIDR4List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead
-- **--blockCIDR6List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead
-- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead
-- **--blockGeoIP**="": Block IP by Geo country code, such as US
+- **--blockGeoIP**="": This option will be removed in a future version, please use the global option instead
- **--cert**="": The cert file absolute path for the domain, such as /path/to/cert.pem. If cert or certkey is empty, a certificate will be issued automatically
@@ -418,6 +484,8 @@ Run as brook wssserver, both TCP and UDP, it will start a standard https server
- **--domainaddress**="": Such as: domain.com:443. If you choose to automatically issue certificates, the domain must have been resolved to the server IP and 80 port also will be used
+- **--example**: Show a minimal example of usage
+
- **--password, -p**="": Server password
- **--path**="": URL path (default: /ws)
@@ -426,13 +494,15 @@ Run as brook wssserver, both TCP and UDP, it will start a standard https server
- **--udpTimeout**="": time (s) (default: 0)
-- **--updateListInterval**="": Update list interval, second. default 0, only read one time on start (default: 0)
+- **--updateListInterval**="": This option will be removed in a future version, please use the global option instead (default: 0)
- **--withoutBrookProtocol**: The data will not be encrypted with brook protocol
## wssclient
-Run as brook wssclient, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook wssclient <-> $ brook wssserver <-> dst]
+Start a brook wssclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook wssclient <-> $ brook wssserver <-> dst]
+
+- **--example**: Show a minimal example of usage
- **--http**="": Where to listen for HTTP proxy connections
@@ -452,15 +522,15 @@ Run as brook wssclient, both TCP and UDP, to start a socks5 proxy, [src <-> sock
## quicserver
-Run as brook quicserver, both TCP and UDP
+Start a brook quicserver that supports tcp and udp.
-- **--blockCIDR4List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead
-- **--blockCIDR6List**="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead
-- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead
-- **--blockGeoIP**="": Block IP by Geo country code, such as US
+- **--blockGeoIP**="": This option will be removed in a future version, please use the global option instead
- **--cert**="": The cert file absolute path for the domain, such as /path/to/cert.pem. If cert or certkey is empty, a certificate will be issued automatically
@@ -468,31 +538,27 @@ Run as brook quicserver, both TCP and UDP
- **--domainaddress**="": Such as: domain.com:443. If you choose to automatically issue certificates, the domain must have been resolved to the server IP and 80 port also will be used
+- **--example**: Show a minimal example of usage
+
- **--password, -p**="": Server password
- **--tcpTimeout**="": time (s) (default: 0)
- **--udpTimeout**="": time (s) (default: 0)
-- **--updateListInterval**="": Update list interval, second. default 0, only read one time on start (default: 0)
+- **--updateListInterval**="": This option will be removed in a future version, please use the global option instead (default: 0)
- **--withoutBrookProtocol**: The data will not be encrypted with brook protocol
## quicclient
-Run as brook quicclient, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook quicclient <-> $ brook quicserver <-> dst]. (Note that the global dial parameter is ignored now)
+Start a brook quicclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook quicclient <-> $ brook quicserver <-> dst]. (The global-dial-parameter is ignored)
-- **--address**="": Specify address instead of resolving addresses from host, such as 1.2.3.4:443
-
-- **--ca**="": Specify ca instead of insecure, such as /path/to/ca.pem
+- **--example**: Show a minimal example of usage
- **--http**="": Where to listen for HTTP proxy connections
-- **--insecure**: Client do not verify the server's certificate chain and host name
-
-- **--password, -p**="": Brook quicserver password
-
-- **--quicserver, -s**="": Brook quicserver address, like: quic://google.com:443. Do not omit the port under any circumstances
+- **--link**="": brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored
- **--socks5**="": Where to listen for SOCKS5 connections (default: 127.0.0.1:1080)
@@ -502,11 +568,11 @@ Run as brook quicclient, both TCP and UDP, to start a socks5 proxy, [src <-> soc
- **--udpTimeout**="": time (s) (default: 0)
-- **--withoutBrookProtocol**: The data will not be encrypted with brook protocol
-
## relayoverbrook
-Run as relay over brook, both TCP and UDP, this means access [from address] is equal to [to address], [src <-> from address <-> $ brook server/wsserver/wssserver/quicserver <-> to address]
+Relay network traffic over brook, which supports TCP and UDP. Accessing [from address] is equal to accessing [to address], [src <-> from address <-> $ brook server/wsserver/wssserver/quicserver <-> to address]
+
+- **--example**: Show a minimal example of usage
- **--from, -f, -l**="": Listen address: like ':9999'
@@ -524,7 +590,7 @@ Run as relay over brook, both TCP and UDP, this means access [from address] is e
## dnsserveroverbrook
-Run as dns server over brook, both TCP and UDP, [src <-> $ brook dnserversoverbrook <-> $ brook server/wsserver/wssserver/quicserver <-> dns] or [src <-> $ brook dnsserveroverbrook <-> dnsForBypass]
+Run a dns server over brook, which supports TCP and UDP, [src <-> $ brook dnserversoverbrook <-> $ brook server/wsserver/wssserver/quicserver <-> dns] or [src <-> $ brook dnsserveroverbrook <-> dnsForBypass]
- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local absolute file path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
@@ -538,6 +604,8 @@ Run as dns server over brook, both TCP and UDP, [src <-> $ brook dnserversoverbr
- **--dnsForBypass**="": DNS server for resolving domains in bypass list. Such as 223.5.5.5:53 or https://dns.alidns.com/dns-query?address=223.5.5.5:443, the address is required (default: 223.5.5.5:53)
+- **--example**: Show a minimal example of usage
+
- **--link**="": brook link, you can get it via $ brook link. The server and password parameters will be ignored
- **--listen, -l**="": Listen address, like: 127.0.0.1:53
@@ -552,7 +620,7 @@ Run as dns server over brook, both TCP and UDP, [src <-> $ brook dnserversoverbr
## link
-Generate brook link
+Generate a brook link
- **--address**="": When server is brook wsserver or brook wssserver or brook quicserver, specify address instead of resolving addresses from host, such as 1.2.3.4:443
@@ -560,7 +628,9 @@ Generate brook link
- **--clientHKDFInfo**="": client HKDF info, most time you don't need to change this, read brook protocol if you don't know what this is
-- **--fragment**="": When server is brook wssserver, split the ClientHello into multiple fragments and then send them one by one with delays (millisecond). The format is min_length:max_length:min_delay:max_delay, cannot be zero, such as 50:100:10:50, Note that: This is an experimental feature, currently only supported by the brook CLI and tun2brook.
+- **--example**: Show a minimal example of usage
+
+- **--fragment**="": When server is brook wssserver, split the ClientHello into multiple fragments and then send them one by one with delays (millisecond). The format is min_length:max_length:min_delay:max_delay, cannot be zero, such as 50:100:10:50
- **--insecure**: When server is brook wssserver or brook quicserver, client do not verify the server's certificate chain and host name
@@ -574,6 +644,10 @@ Generate brook link
- **--tlsfingerprint**="": When server is brook wssserver, select tls fingerprint, value can be: chrome
+- **--token**="": A token represents a user's identity. A string encoded in hexadecimal. Server needs to have --userAPI enabled. Note that: Only supported by the brook GUI(except for OpenWrt) and tun2brook
+
+- **--udpoverstream**: When server is brook quicserver, UDP over Stream. Under normal circumstances, you need this parameter because the max datagram size for QUIC is very small. Note: only brook CLI and tun2brook suppport for now
+
- **--udpovertcp**: When server is brook server, UDP over TCP
- **--username, -u**="": Username, when server is socks5 server
@@ -582,7 +656,9 @@ Generate brook link
## connect
-Run as client and connect to brook link, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook connect <-> $ brook server/wsserver/wssserver/quicserver <-> dst]
+Run a client and connect with a brook link, which supports TCP and UDP. It can start a socks5 proxy, [src <-> socks5 <-> $ brook connect <-> $ brook server/wsserver/wssserver/quicserver <-> dst]
+
+- **--example**: Show a minimal example of usage
- **--http**="": Where to listen for HTTP proxy connections
@@ -598,7 +674,9 @@ Run as client and connect to brook link, both TCP and UDP, to start a socks5 pro
## relay
-Run as standalone relay, both TCP and UDP, this means access [from address] is equal to access [to address], [src <-> from address <-> to address]
+Run a standalone relay, which supports TCP and UDP. Accessing [from address] is equal to accessing [to address], [src <-> from address <-> to address]
+
+- **--example**: Show a minimal example of usage
- **--from, -f, -l**="": Listen address: like ':9999'
@@ -610,7 +688,7 @@ Run as standalone relay, both TCP and UDP, this means access [from address] is e
## dnsserver
-Run as standalone dns server
+Run a standalone dns server
- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local absolute file path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
@@ -620,6 +698,8 @@ Run as standalone dns server
- **--dns**="": DNS server which forward to. Such as 8.8.8.8:53 or https://dns.google/dns-query?address=8.8.8.8%3A443, the address is required (default: 8.8.8.8:53)
+- **--example**: Show a minimal example of usage
+
- **--listen, -l**="": Listen address, like: 127.0.0.1:53
- **--tcpTimeout**="": time (s) (default: 0)
@@ -634,13 +714,15 @@ Send a dns query
- **--domain, -d**="": Domain
+- **--example**: Show a minimal example of usage
+
- **--short**: Short for A/AAAA
- **--type, -t**="": Type, such as A (default: A)
## dohserver
-Run as standalone doh server
+Run a standalone doh server
- **--blockDomainList**="": One domain per line, suffix match mode. https://, http:// or local absolute file path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
@@ -656,6 +738,8 @@ Run as standalone doh server
- **--domainaddress**="": Such as: domain.com:443, if you want to create a https server. If you choose to automatically issue certificates, the domain must have been resolved to the server IP and 80 port also will be used
+- **--example**: Show a minimal example of usage
+
- **--listen**="": listen address, if you want to create a http server behind nico
- **--path**="": URL path (default: /dns-query)
@@ -672,13 +756,15 @@ Send a dns query
- **--domain, -d**="": Domain
+- **--example**: Show a minimal example of usage
+
- **--short**: Short for A/AAAA
- **--type, -t**="": Type, such as A (default: A)
## dhcpserver
-Run as standalone dhcp server. Note that you need to stop other dhcp servers, if there are.
+Run a standalone dhcp server. Other running dhcp servers need to be stopped.
- **--cache**="": Cache file, local absolute file path, default is $HOME/.brook.dhcpserver
@@ -686,6 +772,8 @@ Run as standalone dhcp server. Note that you need to stop other dhcp servers, if
- **--dnsserver**="": The dns server which you want to assign to clients, such as: 192.168.1.1 or 8.8.8.8
+- **--example**: Show a minimal example of usage
+
- **--gateway**="": The router gateway which you want to assign to clients, such as: 192.168.1.1
- **--interface**="": Select interface on multi interface device. Linux only
@@ -698,7 +786,9 @@ Run as standalone dhcp server. Note that you need to stop other dhcp servers, if
## socks5
-Run as standalone standard socks5 server, both TCP and UDP
+Run a standalone standard socks5 server, which supports TCP and UDP
+
+- **--example**: Show a minimal example of usage
- **--limitUDP**: The server MAY use this information to limit access to the UDP association. This usually causes connection failures in a NAT environment, where most clients are.
@@ -716,7 +806,9 @@ Run as standalone standard socks5 server, both TCP and UDP
## socks5tohttp
-Convert socks5 to http proxy, [src <-> listen address(http proxy) <-> socks5 address <-> dst]
+Convert a socks5 proxy to a http proxy, [src <-> listen address(http proxy) <-> socks5 address <-> dst]
+
+- **--example**: Show a minimal example of usage
- **--listen, -l**="": HTTP proxy which will be create: like: 127.0.0.1:8010
@@ -730,10 +822,12 @@ Convert socks5 to http proxy, [src <-> listen address(http proxy) <-> socks5 add
## pac
-Run as PAC server or save PAC to file
+Run a PAC server or save PAC to a file
- **--bypassDomainList, -b**="": One domain per line, suffix match mode. http(s):// or local absolute file path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+- **--example**: Show a minimal example of usage
+
- **--file, -f**="": Save PAC to file, this will ignore listen address
- **--listen, -l**="": Listen address, like: 127.0.0.1:1980
@@ -742,12 +836,14 @@ Run as PAC server or save PAC to file
## testsocks5
-Test UDP and TCP of socks5 server
+Test a socks5 server to see if it works properly
- **--dns**="": DNS server for connecting (default: 8.8.8.8:53)
- **--domain**="": Domain for query (default: http3.ooo)
+- **--example**: Show a minimal example of usage
+
- **--password, -p**="": Socks5 password
- **--socks5, -s**="": Like: 127.0.0.1:1080
@@ -758,12 +854,14 @@ Test UDP and TCP of socks5 server
## testbrook
-Test UDP and TCP of brook server/wsserver/wssserver/quicserver. (Note that the global dial parameter is ignored now)
+Test UDP and TCP of a brook server/wsserver/wssserver/quicserver connection. (The global-dial-parameter is ignored)
- **--dns**="": DNS server for connecting (default: 8.8.8.8:53)
- **--domain**="": Domain for query (default: http3.ooo)
+- **--example**: Show a minimal example of usage
+
- **--link, -l**="": brook link. Get it via $ brook link
- **--socks5**="": Temporarily listening socks5 (default: 127.0.0.1:11080)
@@ -774,12 +872,16 @@ Test UDP and TCP of brook server/wsserver/wssserver/quicserver. (Note that the g
Echo server, echo UDP and TCP address of routes
+- **--example**: Show a minimal example of usage
+
- **--listen, -l**="": Listen address, like: ':7777'
## echoclient
Connect to echoserver, echo UDP and TCP address of routes
+- **--example**: Show a minimal example of usage
+
- **--server, -s**="": Echo server address, such as 1.2.3.4:7777
- **--times**="": Times of interactions (default: 0)
@@ -788,18 +890,24 @@ Connect to echoserver, echo UDP and TCP address of routes
Get country of IP
+- **--example**: Show a minimal example of usage
+
- **--ip**="": 1.1.1.1
## completion
Generate shell completions
+- **--example**: Show a minimal example of usage
+
- **--file, -f**="": Write to file (default: brook_autocomplete)
## mdpage
Generate markdown page
+- **--example**: Show a minimal example of usage
+
- **--file, -f**="": Write to file, default print to stdout
- **--help, -h**: show help
@@ -812,6 +920,8 @@ Shows a list of commands or help for one command
Generate man.1 page
+- **--example**: Show a minimal example of usage
+
- **--file, -f**="": Write to file, default print to stdout. You should put to /path/to/man/man1/brook.1 on linux or /usr/local/share/man/man1/brook.1 on macos
## help, h
@@ -1094,43 +1204,3 @@ brook pac --file proxy.pac --proxy 'SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080;
```
## There are countless examples; for more feature suggestions, it's best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...
-# Diagram
-
-> Maybe outdated
-
-## overview
-
-
-
-## withoutBrookProtocol
-
-
-
-## relayoverbrook
-
-
-
-## dnsserveroverbrook
-
-
-
-## relay
-
-
-
-## dnsserver
-
-
-
-## tproxy
-
-
-
-## gui
-
-
-
-## script
-
-
-
diff --git a/brook/cli/brook/main.go b/brook/cli/brook/main.go
index f4968ac8c9..dfae01426e 100644
--- a/brook/cli/brook/main.go
+++ b/brook/cli/brook/main.go
@@ -158,7 +158,7 @@ func main() {
},
&cli.StringFlag{
Name: "pid",
- Usage: "A file path used to store pid",
+ Usage: "A file path used to store pid. Send SIGUSR1 to me to reset the --serverLog file on unix system",
},
}
app.Before = func(c *cli.Context) error {
@@ -1192,16 +1192,6 @@ func main() {
}
},
Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "quicserver",
- Aliases: []string{"s"},
- Usage: "Brook quicserver address, like: quic://google.com:443. Do not omit the port under any circumstances",
- },
- &cli.StringFlag{
- Name: "password",
- Aliases: []string{"p"},
- Usage: "Brook quicserver password",
- },
&cli.StringFlag{
Name: "link",
Usage: "brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored",
@@ -1236,21 +1226,13 @@ func main() {
},
Action: func(c *cli.Context) error {
if c.Bool("example") {
- fmt.Println("brook quicclient --quicserver quic://domain.com:9999 --password hello --socks5 127.0.0.1:1080")
+ fmt.Println("brook quicclient --link 'brook://...' --socks5 127.0.0.1:1080")
return nil
}
- if c.String("quicserver") == "" && c.String("link") == "" {
+ if c.String("link") == "" {
return cli.ShowSubcommandHelp(c)
}
- var link = ""
- if c.String("quicserver") != "" {
- v := url.Values{}
- v.Set("password", c.String("password"))
- link = brook.Link("quicserver", c.String("quicserver"), v)
- }
- if c.String("link") != "" {
- link = c.String("link")
- }
+ link := c.String("link")
h, p, err := net.SplitHostPort(c.String("socks5"))
if err != nil {
return err
@@ -1376,6 +1358,9 @@ func main() {
if strings.HasPrefix(c.String("server"), "quic://") {
kind = "quicserver"
}
+ if kind == "quicserver" {
+ return errors.New("It is recommended to use brook link and specify --udpoverstream")
+ }
v := url.Values{}
v.Set("password", c.String("password"))
link = brook.Link(kind, c.String("server"), v)
@@ -1514,6 +1499,9 @@ func main() {
if strings.HasPrefix(c.String("server"), "quic://") {
kind = "quicserver"
}
+ if kind == "quicserver" {
+ return errors.New("It is recommended to use brook link and specify --udpoverstream")
+ }
v := url.Values{}
v.Set("password", c.String("password"))
link = brook.Link(kind, c.String("server"), v)
@@ -1585,7 +1573,7 @@ func main() {
},
&cli.BoolFlag{
Name: "udpoverstream",
- Usage: "When server is brook quicserver, UDP over Stream. Note: only brook CLI and tun2brook suppport for now",
+ Usage: "When server is brook quicserver, UDP over Stream. Under normal circumstances, you need this parameter because the max datagram size for QUIC is very small. Note: only brook CLI and tun2brook suppport for now",
},
&cli.StringFlag{
Name: "address",
diff --git a/brook/docs/getting-started.md b/brook/docs/getting-started.md
index 98ac923896..cb23136950 100644
--- a/brook/docs/getting-started.md
+++ b/brook/docs/getting-started.md
@@ -21,8 +21,4 @@ brook server -l :9999 -p hello
| [](https://apps.apple.com/us/app/brook-network-tool/id1216002642) | [](https://github.com/txthinking/brook/releases/latest/download/Brook.apk) | [](https://apps.apple.com/us/app/brook-network-tool/id1216002642) | [](https://github.com/txthinking/brook/releases/latest/download/Brook.msix) | [](https://github.com/txthinking/brook/releases/latest/download/Brook.bin) | [](https://github.com/txthinking/brook/releases) |
| / | / | [App Mode](https://www.txthinking.com/talks/articles/macos-app-mode-en.article) | [How](https://www.txthinking.com/talks/articles/msix-brook-en.article) | [How](https://www.txthinking.com/talks/articles/linux-app-brook-en.article) | [How](https://www.txthinking.com/talks/articles/brook-openwrt-en.article) |
-## CLI Client
-
-```
-brook client -s 1.2.3.4:9999 -p hello --socks5 127.0.0.1:1080
-```
+> You may want to use `brook link` to customize some parameters
diff --git a/brook/docs/gui.md b/brook/docs/gui.md
index b95fbf5f12..d0fa4f3c00 100644
--- a/brook/docs/gui.md
+++ b/brook/docs/gui.md
@@ -8,11 +8,12 @@
## Programmable
-```
-Brook GUI will pass different global variables to the script at different times, and the script only needs to assign the processing result to the global variable out
-```
+Brook GUI will pass different _global variables_ to the script at different times, and the script only needs to assign the processing result to the global variable `out`
-### Introduction to incoming variables
+- address: We call it address which includes both host and port. For example, an ip address contains an ip and a port; a domain address contains a domain and a port.
+- Fake DNS: Fake DNS can allow you to obtain domain address on `in_address` step. [How Fake DNS works](https://www.txthinking.com/talks/articles/brook-fakedns-en.article)
+
+### Variables
| variable | type | condition | timing | description | out type |
| ------------------------------ | ---- | ----------- | --------------------------------- | ------------------------------------------------- | -------- |
@@ -104,7 +105,53 @@ Brook GUI will pass different global variables to the script at different times,
`out`, must be set to a response
-## Write script
+## Module
+
+There are already some modules: https://github.com/txthinking/brook/blob/master/programmable/modules/
+
+### Brook GUI
+
+In Brook GUI, scripts are abstracted into modules, and it will automatically combine [_header.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo) and [_footer.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo), so you only need to write the module itself.
+
+```
+modules = append(modules, {
+ // If you want to predefine multiple brook links, and then programmatically specify which one to connect to, then define `brooklinks` key a function
+ brooklinks: func(m) {
+ // Please refer to the example in `brooklinks.tengo`
+ },
+ // If you want to intercept and handle a DNS query, then define `dnsquery` key a function, `m` is the `in_dnsquery`
+ dnsquery: func(m) {
+ // Please refer to the example in `block_aaaa.tengo`
+ },
+ // If you want to intercept and handle an address, then define `address` key a function, `m` is the `in_address`
+ address: func(m) {
+ // Please refer to the example in `block_google_secure_dns.tengo`
+ },
+ // If you want to intercept and handle a http request, then define `httprequest` key a function, `request` is the `in_httprequest`
+ httprequest: func(request) {
+ // Please refer to the example in `ios_app_downgrade.tengo` or `redirect_google_cn.tengo`
+ },
+ // If you want to intercept and handle a http response, then define `httpresponse` key a function, `request` is the `in_httprequest`, `response` is the `in_httpresponse`
+ httpresponse: func(request, response) {
+ // Please refer to the example in `response_sample.tengo`
+ }
+})
+```
+
+### tun2brook
+
+If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:
+
+```
+cat _header.tengo > my.tengo
+
+cat block_google_secure_dns.tengo >> my.tengo
+cat block_aaaa.tengo >> my.tengo
+
+cat _footer.tengo >> my.tengo
+```
+
+## Syntax
[Tengo Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
@@ -151,9 +198,9 @@ Library
* hexencode(s string) => string/error: returns the hexadecimal encoding of src
```
-## Debug script
+## Debug
-It is recommended to use [tun2brook](https://github.com/txthinking/tun2brook) on desktop to debug with `fmt.println`
+If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use [tun2brook](https://github.com/txthinking/tun2brook) on desktop to debug with `fmt.println`
## Install CA
diff --git a/brook/docs/index.html b/brook/docs/index.html
index 84569007a5..59bf4dc251 100644
--- a/brook/docs/index.html
+++ b/brook/docs/index.html
@@ -1158,13 +1158,12 @@
Getting Started
GUI Documentation
@@ -1243,18 +1247,6 @@
There are countless examples; for more feature suggestions, it's best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...
-Diagram
-
@@ -1268,13 +1260,12 @@
Getting Started
GUI Documentation
@@ -1353,18 +1349,6 @@
There are countless examples; for more feature suggestions, it's best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...
-Diagram
-
@@ -1372,7 +1356,7 @@
A cross-platform programmable network tool.
-❤️ Shiliew - China Optimized Network App
+❤️ Shiliew - A network app designed for those who value their time
Getting Started
Server
bash <(curl https://bash.ooo/nami.sh)
@@ -1410,9 +1394,9 @@
| How |
-CLI Client
-brook client -s 1.2.3.4:9999 -p hello --socks5 127.0.0.1:1080
-
+
+You may want to use brook link to customize some parameters
+
GUI Documentation
Software for which this article applies
Programmable
-Brook GUI will pass different global variables to the script at different times, and the script only needs to assign the processing result to the global variable out
-
-Introduction to incoming variables
+Brook GUI will pass different global variables to the script at different times, and the script only needs to assign the processing result to the global variable out
+
+- address: We call it address which includes both host and port. For example, an ip address contains an ip and a port; a domain address contains a domain and a port.
+- Fake DNS: Fake DNS can allow you to obtain domain address on
in_address step. How Fake DNS works
+
+Variables
out, must be set to a response
-Write script
+Module
+There are already some modules: https://github.com/txthinking/brook/blob/master/programmable/modules/
+Brook GUI
+In Brook GUI, scripts are abstracted into modules, and it will automatically combine _header.tengo and _footer.tengo, so you only need to write the module itself.
+modules = append(modules, {
+ // If you want to predefine multiple brook links, and then programmatically specify which one to connect to, then define `brooklinks` key a function
+ brooklinks: func(m) {
+ // Please refer to the example in `brooklinks.tengo`
+ },
+ // If you want to intercept and handle a DNS query, then define `dnsquery` key a function, `m` is the `in_dnsquery`
+ dnsquery: func(m) {
+ // Please refer to the example in `block_aaaa.tengo`
+ },
+ // If you want to intercept and handle an address, then define `address` key a function, `m` is the `in_address`
+ address: func(m) {
+ // Please refer to the example in `block_google_secure_dns.tengo`
+ },
+ // If you want to intercept and handle a http request, then define `httprequest` key a function, `request` is the `in_httprequest`
+ httprequest: func(request) {
+ // Please refer to the example in `ios_app_downgrade.tengo` or `redirect_google_cn.tengo`
+ },
+ // If you want to intercept and handle a http response, then define `httpresponse` key a function, `request` is the `in_httprequest`, `response` is the `in_httpresponse`
+ httpresponse: func(request, response) {
+ // Please refer to the example in `response_sample.tengo`
+ }
+})
+
+tun2brook
+If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:
+cat _header.tengo > my.tengo
+
+cat block_google_secure_dns.tengo >> my.tengo
+cat block_aaaa.tengo >> my.tengo
+
+cat _footer.tengo >> my.tengo
+
+Syntax
Tengo Language Syntax
Library
@@ -1847,8 +1870,8 @@ Functions
-Debug script
-It is recommended to use tun2brook on desktop to debug with fmt.println
+Debug
+If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use tun2brook on desktop to debug with fmt.println
Install CA
https://txthinking.github.io/ca/ca.pem
@@ -1983,12 +2006,8 @@ Functions
| A SSH Terminal |
-| Brook Deploy |
-Deploy brook with GUI |
-
-
-| brook-manager |
-Brook Manager is a Brook management system for medium to large merchants |
+brook-user-system |
+A Brook User System |
| TxThinking |
@@ -2007,6 +2026,16 @@ Functions
GLOBAL OPTIONS
+--blockCIDR4List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt. Works with server/wsserver/wssserver/quicserver
+
+--blockCIDR6List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt. Works with server/wsserver/wssserver/quicserver
+
+--blockDomainList="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt. Works with server/wsserver/wssserver/quicserver
+
+--blockGeoIP="": Block IP by Geo country code, such as US. Works with server/wsserver/wssserver/quicserver
+
+--blockListUpdateInterval="": Update list --blockDomainList,--blockCIDR4List,--blockCIDR6List interval, second. default 0, only read one time on start (default: 0)
+
--clientHKDFInfo="": client HKDF info, most time you don't need to change this, if changed, all and each brook links in client side must be same, I mean each (default: "brook")
--dialWithDNS="": When a domain name needs to be resolved, use the specified DNS. Such as 8.8.8.8:53 or https://dns.google/dns-query?address=8.8.8.8%3A443, the address is required. Note that for client-side commands, this does not affect the client passing the domain address to the server
@@ -2037,7 +2066,9 @@ Functions
--ipLimitWait="": How long (s) to wait for recovery after exceeding ipLimitMax (default: 0)
---log="": Enable log. A valid value is file path or 'console'. If you want to debug SOCKS5 lib, set env SOCKS5_DEBUG=true
+--log="": Enable log. A valid value is file path or 'console'. Send SIGUSR1 to me to reset the log file on unix system. If you want to debug SOCKS5 lib, set env SOCKS5_DEBUG=true
+
+--pid="": A file path used to store pid. Send SIGUSR1 to me to reset the --serverLog file on unix system
--pprof="": go http pprof listen addr, such as :6060
@@ -2047,26 +2078,34 @@ Functions
--serverHKDFInfo="": server HKDF info, most time you don't need to change this, if changed, all and each brook links in client side must be same, I mean each (default: "brook")
---serverLog="": Enable server log, traffic and more. A valid value is file path or 'console'. Mutually exclusive with the --log parameter. Works with server/wsserver/wssserver/quicserver
+--serverLog="": Enable server log, traffic and more. A valid value is file path or 'console'. Send SIGUSR1 to me to reset the log file on unix system. Mutually exclusive with the --log parameter. Works with server/wsserver/wssserver/quicserver with brook protocol
---speedLimit="": Limit speed (b), such as 500kb/s: 500000, works with server/wsserver/wssserver/quicserver (default: 0)
+--speedLimit="": Limit speed (b), 500kb/s such as: 500000, works with server/wsserver/wssserver/quicserver (default: 0)
---tag="": Tag can be used to the process, will be append into log or serverLog, such as: 'key1:value1'
+--tag="": Tag can be used to the process, will be append into log or serverLog, such as: 'key1:value1'. All tags will also be appended as query parameters one by one to the userAPI
+
+--userAPI="": When you build your own user system, Brook Server will send GET request to your userAPI to check if token is valid, for example: https://your-api-server.com/a_unpredictable_path. Yes, it is recommended to add an unpredictable path to your https API, of course, you can also use the http api for internal network communication. The request format is https://your-api-server.com/a_unpredictable_path?token=xxx. When the response is 200, the body should be the user's unique identifier, such as user ID; all other status codes are considered to represent an illegitimate user, and in these cases, the body should be a string describing the error. It should be used with --serverLog and server/wsserver/wssserver/quicserver with brook protocol. For more information, please read https://github.com/txthinking/brook/blob/master/protocol/user.md
+
+--userAPIInvalidCacheTime="": Once a token is checked and invalid, the userAPI will not be requested to validate again for a certain period (s). A reasonable value must be set, otherwise it will affect the performance of each incoming connection. Note that this may affect the user experience, when you change the user status from invalid to valid in your user system (default: 1800)
+
+--userAPIValidCacheTime="": Once a token is checked and valid, the userAPI will not be requested to validate again for a certain period (s). A reasonable value must be set, otherwise it will affect the performance of each incoming connection (default: 3600)
--version, -v: print the version
COMMANDS
server
-Run as brook server, both TCP and UDP
+Start a brook server that supports tcp and udp
---blockCIDR4List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+--blockCIDR4List="": This option will be removed in a future version, please use the global option instead
---blockCIDR6List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+--blockCIDR6List="": This option will be removed in a future version, please use the global option instead
---blockDomainList="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+--blockDomainList="": This option will be removed in a future version, please use the global option instead
---blockGeoIP="": Block IP by Geo country code, such as US
+--blockGeoIP="": This option will be removed in a future version, please use the global option instead
+
+--example: Show a minimal example of usage
--listen, -l="": Listen address, like: ':9999'
@@ -2076,14 +2115,18 @@ Functions
--udpTimeout="": time (s) (default: 0)
---updateListInterval="": Update list interval, second. default 0, only read one time on start (default: 0)
+--updateListInterval="": This option will be removed in a future version, please use the global option instead (default: 0)
client
-Run as brook client, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook client <-> $ brook server <-> dst]
+Start a brook client that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook client <-> $ brook server <-> dst]
+--example: Show a minimal example of usage
+
--http="": Where to listen for HTTP proxy connections
+--link="": brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored
+
--password, -p="": Brook server password
--server, -s="": Brook server address, like: 1.2.3.4:9999
@@ -2096,19 +2139,19 @@ Functions
--udpTimeout="": time (s) (default: 0)
---udpovertcp: UDP over TCP
-
wsserver
-Run as brook wsserver, both TCP and UDP, it will start a standard http server and websocket server
+Start a brook wsserver that supports tcp and udp. It opens a standard http server and a websocket server
---blockCIDR4List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+--blockCIDR4List="": This option will be removed in a future version, please use the global option instead
---blockCIDR6List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+--blockCIDR6List="": This option will be removed in a future version, please use the global option instead
---blockDomainList="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+--blockDomainList="": This option will be removed in a future version, please use the global option instead
---blockGeoIP="": Block IP by Geo country code, such as US
+--blockGeoIP="": This option will be removed in a future version, please use the global option instead
+
+--example: Show a minimal example of usage
--listen, -l="": Listen address, like: ':80'
@@ -2120,7 +2163,7 @@ Functions
--udpTimeout="": time (s) (default: 0)
---updateListInterval="": Update list interval, second. default 0, only read one time on start (default: 0)
+--updateListInterval="": This option will be removed in a future version, please use the global option instead (default: 0)
--withoutBrookProtocol: The data will not be encrypted with brook protocol
@@ -2128,12 +2171,14 @@ Functions
wsclient
-Run as brook wsclient, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook wsclient <-> $ brook wsserver <-> dst]
+Start a brook wsclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook wsclient <-> $ brook wsserver <-> dst]
---address="": Specify address instead of resolving addresses from host, such as 1.2.3.4:443
+--example: Show a minimal example of usage
--http="": Where to listen for HTTP proxy connections
+--link="": brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored
+
--password, -p="": Brook wsserver password
--socks5="": Where to listen for SOCKS5 connections (default: 127.0.0.1:1080)
@@ -2144,21 +2189,19 @@ Functions
--udpTimeout="": time (s) (default: 0)
---withoutBrookProtocol: The data will not be encrypted with brook protocol
-
--wsserver, -s="": Brook wsserver address, like: ws://1.2.3.4:80, if no path then /ws will be used. Do not omit the port under any circumstances
wssserver
-Run as brook wssserver, both TCP and UDP, it will start a standard https server and websocket server
+Start a brook wssserver that supports tcp and udp. It opens a standard https server and a websocket server
---blockCIDR4List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+--blockCIDR4List="": This option will be removed in a future version, please use the global option instead
---blockCIDR6List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+--blockCIDR6List="": This option will be removed in a future version, please use the global option instead
---blockDomainList="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+--blockDomainList="": This option will be removed in a future version, please use the global option instead
---blockGeoIP="": Block IP by Geo country code, such as US
+--blockGeoIP="": This option will be removed in a future version, please use the global option instead
--cert="": The cert file absolute path for the domain, such as /path/to/cert.pem. If cert or certkey is empty, a certificate will be issued automatically
@@ -2166,6 +2209,8 @@ Functions
--domainaddress="": Such as: domain.com:443. If you choose to automatically issue certificates, the domain must have been resolved to the server IP and 80 port also will be used
+--example: Show a minimal example of usage
+
--password, -p="": Server password
--path="": URL path (default: /ws)
@@ -2174,14 +2219,16 @@ Functions
--udpTimeout="": time (s) (default: 0)
---updateListInterval="": Update list interval, second. default 0, only read one time on start (default: 0)
+--updateListInterval="": This option will be removed in a future version, please use the global option instead (default: 0)
--withoutBrookProtocol: The data will not be encrypted with brook protocol
wssclient
-Run as brook wssclient, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook wssclient <-> $ brook wssserver <-> dst]
+Start a brook wssclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook wssclient <-> $ brook wssserver <-> dst]
+--example: Show a minimal example of usage
+
--http="": Where to listen for HTTP proxy connections
--link="": brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored
@@ -2200,15 +2247,15 @@ Functions
quicserver
-Run as brook quicserver, both TCP and UDP
+Start a brook quicserver that supports tcp and udp.
---blockCIDR4List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr4.txt
+--blockCIDR4List="": This option will be removed in a future version, please use the global option instead
---blockCIDR6List="": One CIDR per line, https://, http:// or local file absolute path, like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_cidr6.txt
+--blockCIDR6List="": This option will be removed in a future version, please use the global option instead
---blockDomainList="": One domain per line, suffix match mode. https://, http:// or local file absolute path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
+--blockDomainList="": This option will be removed in a future version, please use the global option instead
---blockGeoIP="": Block IP by Geo country code, such as US
+--blockGeoIP="": This option will be removed in a future version, please use the global option instead
--cert="": The cert file absolute path for the domain, such as /path/to/cert.pem. If cert or certkey is empty, a certificate will be issued automatically
@@ -2216,31 +2263,27 @@ Functions
--domainaddress="": Such as: domain.com:443. If you choose to automatically issue certificates, the domain must have been resolved to the server IP and 80 port also will be used
+--example: Show a minimal example of usage
+
--password, -p="": Server password
--tcpTimeout="": time (s) (default: 0)
--udpTimeout="": time (s) (default: 0)
---updateListInterval="": Update list interval, second. default 0, only read one time on start (default: 0)
+--updateListInterval="": This option will be removed in a future version, please use the global option instead (default: 0)
--withoutBrookProtocol: The data will not be encrypted with brook protocol
quicclient
-Run as brook quicclient, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook quicclient <-> $ brook quicserver <-> dst]. (Note that the global dial parameter is ignored now)
+Start a brook quicclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook quicclient <-> $ brook quicserver <-> dst]. (The global-dial-parameter is ignored)
---address="": Specify address instead of resolving addresses from host, such as 1.2.3.4:443
-
---ca="": Specify ca instead of insecure, such as /path/to/ca.pem
+--example: Show a minimal example of usage
--http="": Where to listen for HTTP proxy connections
---insecure: Client do not verify the server's certificate chain and host name
-
---password, -p="": Brook quicserver password
-
---quicserver, -s="": Brook quicserver address, like: quic://google.com:443. Do not omit the port under any circumstances
+--link="": brook link, you can get it via $ brook link. The wssserver and password parameters will be ignored
--socks5="": Where to listen for SOCKS5 connections (default: 127.0.0.1:1080)
@@ -2250,12 +2293,12 @@ Functions
--udpTimeout="": time (s) (default: 0)
---withoutBrookProtocol: The data will not be encrypted with brook protocol
-
relayoverbrook
-Run as relay over brook, both TCP and UDP, this means access [from address] is equal to [to address], [src <-> from address <-> $ brook server/wsserver/wssserver/quicserver <-> to address]
+Relay network traffic over brook, which supports TCP and UDP. Accessing [from address] is equal to accessing [to address], [src <-> from address <-> $ brook server/wsserver/wssserver/quicserver <-> to address]
+--example: Show a minimal example of usage
+
--from, -f, -l="": Listen address: like ':9999'
--link="": brook link, you can get it via $ brook link. The server and password parameters will be ignored
@@ -2272,7 +2315,7 @@ Functions
dnsserveroverbrook
-Run as dns server over brook, both TCP and UDP, [src <-> $ brook dnserversoverbrook <-> $ brook server/wsserver/wssserver/quicserver <-> dns] or [src <-> $ brook dnsserveroverbrook <-> dnsForBypass]
+Run a dns server over brook, which supports TCP and UDP, [src <-> $ brook dnserversoverbrook <-> $ brook server/wsserver/wssserver/quicserver <-> dns] or [src <-> $ brook dnsserveroverbrook <-> dnsForBypass]
--blockDomainList="": One domain per line, suffix match mode. https://, http:// or local absolute file path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
@@ -2286,6 +2329,8 @@ Functions
--dnsForBypass="": DNS server for resolving domains in bypass list. Such as 223.5.5.5:53 or https://dns.alidns.com/dns-query?address=223.5.5.5:443, the address is required (default: 223.5.5.5:53)
+--example: Show a minimal example of usage
+
--link="": brook link, you can get it via $ brook link. The server and password parameters will be ignored
--listen, -l="": Listen address, like: 127.0.0.1:53
@@ -2300,7 +2345,7 @@ Functions
link
-Generate brook link
+Generate a brook link
--address="": When server is brook wsserver or brook wssserver or brook quicserver, specify address instead of resolving addresses from host, such as 1.2.3.4:443
@@ -2308,7 +2353,9 @@ Functions
--clientHKDFInfo="": client HKDF info, most time you don't need to change this, read brook protocol if you don't know what this is
---fragment="": When server is brook wssserver, split the ClientHello into multiple fragments and then send them one by one with delays (millisecond). The format is min_length:max_length:min_delay:max_delay, cannot be zero, such as 50:100:10:50, Note that: This is an experimental feature, currently only supported by the brook CLI and tun2brook.
+--example: Show a minimal example of usage
+
+--fragment="": When server is brook wssserver, split the ClientHello into multiple fragments and then send them one by one with delays (millisecond). The format is min_length:max_length:min_delay:max_delay, cannot be zero, such as 50:100:10:50
--insecure: When server is brook wssserver or brook quicserver, client do not verify the server's certificate chain and host name
@@ -2322,6 +2369,10 @@ Functions
--tlsfingerprint="": When server is brook wssserver, select tls fingerprint, value can be: chrome
+--token="": A token represents a user's identity. A string encoded in hexadecimal. Server needs to have --userAPI enabled. Note that: Only supported by the brook GUI(except for OpenWrt) and tun2brook
+
+--udpoverstream: When server is brook quicserver, UDP over Stream. Under normal circumstances, you need this parameter because the max datagram size for QUIC is very small. Note: only brook CLI and tun2brook suppport for now
+
--udpovertcp: When server is brook server, UDP over TCP
--username, -u="": Username, when server is socks5 server
@@ -2330,8 +2381,10 @@ Functions
connect
-Run as client and connect to brook link, both TCP and UDP, to start a socks5 proxy, [src <-> socks5 <-> $ brook connect <-> $ brook server/wsserver/wssserver/quicserver <-> dst]
+Run a client and connect with a brook link, which supports TCP and UDP. It can start a socks5 proxy, [src <-> socks5 <-> $ brook connect <-> $ brook server/wsserver/wssserver/quicserver <-> dst]
+--example: Show a minimal example of usage
+
--http="": Where to listen for HTTP proxy connections
--link, -l="": brook link, you can get it via $ brook link
@@ -2346,8 +2399,10 @@ Functions
relay
-Run as standalone relay, both TCP and UDP, this means access [from address] is equal to access [to address], [src <-> from address <-> to address]
+Run a standalone relay, which supports TCP and UDP. Accessing [from address] is equal to accessing [to address], [src <-> from address <-> to address]
+--example: Show a minimal example of usage
+
--from, -f, -l="": Listen address: like ':9999'
--tcpTimeout="": time (s) (default: 0)
@@ -2358,7 +2413,7 @@ Functions
dnsserver
-Run as standalone dns server
+Run a standalone dns server
--blockDomainList="": One domain per line, suffix match mode. https://, http:// or local absolute file path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
@@ -2368,6 +2423,8 @@ Functions
--dns="": DNS server which forward to. Such as 8.8.8.8:53 or https://dns.google/dns-query?address=8.8.8.8%3A443, the address is required (default: 8.8.8.8:53)
+--example: Show a minimal example of usage
+
--listen, -l="": Listen address, like: 127.0.0.1:53
--tcpTimeout="": time (s) (default: 0)
@@ -2382,13 +2439,15 @@ Functions
--domain, -d="": Domain
+--example: Show a minimal example of usage
+
--short: Short for A/AAAA
--type, -t="": Type, such as A (default: A)
dohserver
-Run as standalone doh server
+Run a standalone doh server
--blockDomainList="": One domain per line, suffix match mode. https://, http:// or local absolute file path. Like: https://raw.githubusercontent.com/txthinking/brook/master/programmable/list/example_domain.txt
@@ -2404,6 +2463,8 @@ Functions
--domainaddress="": Such as: domain.com:443, if you want to create a https server. If you choose to automatically issue certificates, the domain must have been resolved to the server IP and 80 port also will be used
+--example: Show a minimal example of usage
+
--listen="": listen address, if you want to create a http server behind nico
--path="": URL path (default: /dns-query)
@@ -2420,13 +2481,15 @@ Functions
--domain, -d="": Domain
+--example: Show a minimal example of usage
+
--short: Short for A/AAAA
--type, -t="": Type, such as A (default: A)
dhcpserver
-Run as standalone dhcp server. Note that you need to stop other dhcp servers, if there are.
+Run a standalone dhcp server. Other running dhcp servers need to be stopped.
--cache="": Cache file, local absolute file path, default is $HOME/.brook.dhcpserver
@@ -2434,6 +2497,8 @@ Functions
--dnsserver="": The dns server which you want to assign to clients, such as: 192.168.1.1 or 8.8.8.8
+--example: Show a minimal example of usage
+
--gateway="": The router gateway which you want to assign to clients, such as: 192.168.1.1
--interface="": Select interface on multi interface device. Linux only
@@ -2446,8 +2511,10 @@ Functions
socks5
-Run as standalone standard socks5 server, both TCP and UDP
+Run a standalone standard socks5 server, which supports TCP and UDP
+--example: Show a minimal example of usage
+
--limitUDP: The server MAY use this information to limit access to the UDP association. This usually causes connection failures in a NAT environment, where most clients are.
--listen, -l="": Socks5 server listen address, like: :1080 or 1.2.3.4:1080
@@ -2464,8 +2531,10 @@ Functions
socks5tohttp
-Convert socks5 to http proxy, [src <-> listen address(http proxy) <-> socks5 address <-> dst]
+Convert a socks5 proxy to a http proxy, [src <-> listen address(http proxy) <-> socks5 address <-> dst]
+--example: Show a minimal example of usage
+
--listen, -l="": HTTP proxy which will be create: like: 127.0.0.1:8010
--socks5, -s="": Socks5 server address, like: 127.0.0.1:1080
@@ -2478,10 +2547,12 @@ Functions
pac
-Run as PAC server or save PAC to file
+Run a PAC server or save PAC to a file
testsocks5
-Test UDP and TCP of socks5 server
+Test a socks5 server to see if it works properly
--dns="": DNS server for connecting (default: 8.8.8.8:53)
--domain="": Domain for query (default: http3.ooo)
+--example: Show a minimal example of usage
+
--password, -p="": Socks5 password
--socks5, -s="": Like: 127.0.0.1:1080
@@ -2506,12 +2579,14 @@ Functions
testbrook
-Test UDP and TCP of brook server/wsserver/wssserver/quicserver. (Note that the global dial parameter is ignored now)
+Test UDP and TCP of a brook server/wsserver/wssserver/quicserver connection. (The global-dial-parameter is ignored)
--dns="": DNS server for connecting (default: 8.8.8.8:53)
--domain="": Domain for query (default: http3.ooo)
+--example: Show a minimal example of usage
+
--link, -l="": brook link. Get it via $ brook link
--socks5="": Temporarily listening socks5 (default: 127.0.0.1:11080)
@@ -2522,11 +2597,16 @@ Functions
echoserver
Echo server, echo UDP and TCP address of routes
-- --listen, -l="": Listen address, like: ':7777'
+--example: Show a minimal example of usage
+
+--listen, -l="": Listen address, like: ':7777'
+
echoclient
Connect to echoserver, echo UDP and TCP address of routes
+--example: Show a minimal example of usage
+
--server, -s="": Echo server address, such as 1.2.3.4:7777
--times="": Times of interactions (default: 0)
@@ -2535,16 +2615,24 @@ Functions
ipcountry
Get country of IP
completion
Generate shell completions
-- --file, -f="": Write to file (default: brook_autocomplete)
+--example: Show a minimal example of usage
+
+--file, -f="": Write to file (default: brook_autocomplete)
+
mdpage
Generate markdown page
+--example: Show a minimal example of usage
+
--file, -f="": Write to file, default print to stdout
--help, -h: show help
@@ -2555,7 +2643,10 @@ Functions
manpage
Generate man.1 page
-- --file, -f="": Write to file, default print to stdout. You should put to /path/to/man/man1/brook.1 on linux or /usr/local/share/man/man1/brook.1 on macos
+--example: Show a minimal example of usage
+
+--file, -f="": Write to file, default print to stdout. You should put to /path/to/man/man1/brook.1 on linux or /usr/local/share/man/man1/brook.1 on macos
+
help, h
Shows a list of commands or help for one command
@@ -2721,28 +2812,6 @@ Functions
brook pac --file proxy.pac --proxy 'SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT' --bypassDomainList ...
There are countless examples; for more feature suggestions, it's best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...
-Diagram
-
-Maybe outdated
-
-overview
-
-withoutBrookProtocol
-
-relayoverbrook
-
-dnsserveroverbrook
-
-relay
-
-dnsserver
-
-tproxy
-
-gui
-
-script
-
diff --git a/brook/docs/resources.md b/brook/docs/resources.md
index 5eff98e2a2..a10282e616 100644
--- a/brook/docs/resources.md
+++ b/brook/docs/resources.md
@@ -27,6 +27,6 @@
| [Socks5 Configurator](https://chromewebstore.google.com/detail/socks5-configurator/hnpgnjkeaobghpjjhaiemlahikgmnghb) | If you prefer CLI brook client |
| [IPvBar](https://chromewebstore.google.com/detail/ipvbar/nepjlegfiihpkcdhlmaebfdfppckonlj) | See domain, IP and country in browser |
| [TxThinking SSH](https://www.txthinking.com/ssh.html) | A SSH Terminal |
-| [brook-dashboard](https://github.com/txthinkinginc/brook-dashboard) | A Brook User System |
+| [brook-user-system](https://github.com/txthinkinginc/brook-user-system) | A Brook User System |
| [TxThinking](https://www.txthinking.com) | Everything |
diff --git a/brook/ping/ping.json b/brook/ping/ping.json
index 745babb0a6..10124dcf16 100644
--- a/brook/ping/ping.json
+++ b/brook/ping/ping.json
@@ -1,5 +1,5 @@
{
- "version": "20240404",
+ "version": "20240606",
"text": "Clean the web with Brook",
"link": "https://www.txthinking.com/talks/articles/brook-clean-the-web-en.article",
"text_zh": "使用 Brook 净化互联网",
diff --git a/brook/programmable/example_script.tengo b/brook/programmable/example_script.tengo
deleted file mode 100644
index ec5d41958a..0000000000
--- a/brook/programmable/example_script.tengo
+++ /dev/null
@@ -1,199 +0,0 @@
-text := import("text")
-brook := import("brook")
-json := import("json")
-
-dnsquery_handler := func(m){
- // local dev example
- if m.domain == "myapi.local" {
- if m.type == "A" {
- return {ip: "10.211.1.76"}
- }
- if m.type == "AAAA" {
- return {"block": true}
- }
- }
- // block secure dns
- if m.domain == "dns.google" {
- return {"block": true}
- }
- // block ipv6
- if m.type == "AAAA" {
- return {"block": true}
- }
- // do not use fake dns, instagram 90% ?
- l := [
- "facebook.com",
- "fbcdn.net",
- "facebook.net",
- "akamaihd.net",
- "thefacebook.com",
- "tfbnw.net",
- "messenger.com",
- "fb.me",
- "fbsbx.com",
- "fb.com",
- "whatsapp.net",
- "whatsapp.com",
- "instagram.com",
- "akamai.net",
- "aaplimg.com",
- "alibabadns.com",
- "akamaiedge.net",
- "apple-dns.net",
- "akadns.net",
- "cdninstagram.com"
- ]
- for v in l {
- if text.has_suffix(m.domain, v) {
- return {"system": true}
- }
- }
- // use bypass dns to resolve ip, apple push
- l = [
- "apple.com",
- "icloud.com",
- "cdn-apple.com",
- "mzstatic.com",
- "entrust.net",
- "digicert.com",
- "verisign.net",
- "apple",
- "itunes-apple.com.akadns.net",
- "cdn-apple.com.akadns.net",
- "ks-cdn.com",
- "ksyuncdn.com",
- "cdn-apple.com.edgekey.net",
- "e2885.e9.akamaiedge.net",
- "apple.com.edgekey.net",
- "e2490.dscb.akamaiedge.net",
- "idms-apple.com.akadns.net",
- "apple.com.edgekey.net.globalredir.akadns.net",
- "e6858.dscx.akamaiedge.net",
- "ioshost.qtlcdn.com"
- ]
- for v in l {
- if text.has_suffix(m.domain, v) {
- return {"bypass": true}
- }
- }
-}
-
-address_handler := func(m) {
- if m.ipaddress {
- // block secure dns
- if m.ipaddress == "8.8.8.8:853" || m.ipaddress == "8.8.8.8:443" || m.ipaddress == "8.8.4.4:853" || m.ipaddress == "8.8.4.4:443" || m.ipaddress == "[2001:4860:4860::8888]:853" || m.ipaddress == "[2001:4860:4860::8888]:443" || m.ipaddress == "[2001:4860:4860::8844]:853" || m.ipaddress == "[2001:4860:4860::8844]:443" {
- return { "block": true }
- }
- // extract ip
- r := brook.splithostport(m.ipaddress)
- if is_error(r) {
- return r
- }
- // block an ip
- if r.host == "1.2.4.8" {
- return { "block": true }
- }
- // bypass zz and cn ip
- s := brook.country(r.host)
- if s == "ZZ" || s == "CN" {
- return { "bypass": true }
- }
- // bypass apple push
- l := [
- "17.0.0.0/8",
- "103.81.148.0/22",
- "103.81.148.0/24",
- "103.81.149.0/24",
- "2620:149:a44::/48",
- "2403:300:a42::/48",
- "2403:300:a51::/48",
- "2a01:b740:a42::/48"
- ]
- for v in l {
- if brook.cidrcontainsip(v, r.host) {
- return {"bypass": true}
- }
- }
- }
- if m.domainaddress {
- // block secure dns
- if text.has_prefix(m.domainaddress, "dns.google:") {
- return { "block": true }
- }
- if m.network == "tcp" {
- // Packet Capture and Modify
- if m.domainaddress == "httpbin.org:80" {
- return {"mitm": true, "mitmprotocol": "http"}
- }
- if m.domainaddress == "httpbin.org:443" {
- return {"mitm": true, "mitmprotocol": "https", "mitmwithbody": true, "mitmautohandlecompress": true}
- }
- // connect this ip and bypass it
- if m.domainaddress == "myapi2.local:80" {
- return {"ipaddress": "10.211.1.76:8080", "bypass": true, "mitm": true, "mitmprotocol": "http", "mitmwithbody": true, "mitmautohandlecompress": true}
- }
- // get A via bypass dns, then connect it and bypass it
- if m.domainaddress == "myip.ipip.net:443" {
- return {"ipaddressfrombypassdns": "A", "bypass": true, "mitm": true, "mitmprotocol": "https", "mitmwithbody": true, "mitmautohandlecompress": true}
- }
- }
- if m.network == "udp" {
- // block http3
- if m.domainaddress == "httpbin.org:443" {
- return { "block": true }
- }
- }
- }
-}
-
-httprequest_handler := func(request){
- // redirect
- if text.has_prefix(request["URL"], "http://httpbin.org") {
- response := {
- "StatusCode": 301,
- "Location": text.replace(request["URL"], "http://", "https://", 1)
- }
- return response
- }
- // Packet Modify request header and body
- if request["URL"] == "https://httpbin.org/post" && request["Method"] == "POST" && request["Content-Type"] == "application/x-www-form-urlencoded" {
- request["User-Agent"] = "curl/7.79.1"
- request["Body"] = bytes("hello=world")
- return request
- }
- return request
-}
-
-httpresponse_handler := func(request, response){
- delete(response, "Alt-Svc") // Avoid upgrading to http3 from http1 or http2
- // Packet Modify response body
- if text.has_prefix(request["URL"], "https://httpbin.org") && !text.has_prefix(request["URL"], "https://httpbin.org/stream/") && response["Content-Type"] == "application/json" {
- j := json.decode(response["Body"])
- j.origin = "M.A.R.S"
- response["Body"] = json.encode(j)
- return response
- }
- // Packet Modify response body
- if text.has_prefix(request["URL"], "https://myip.ipip.net") {
- response["Body"] = bytes(text.split(string(response["Body"]), "IP")[0] + "来自: 火星")
- return response
- }
- return response
-}
-
-handler := func(){
- if in_dnsquery {
- return dnsquery_handler(in_dnsquery)
- }
- if in_address {
- return address_handler(in_address)
- }
- if in_httprequest && !in_httpresponse {
- return httprequest_handler(in_httprequest)
- }
- if in_httprequest && in_httpresponse {
- return httpresponse_handler(in_httprequest, in_httpresponse)
- }
-}
-
-out := handler()
diff --git a/brook/programmable/modules/bypass_geo.tengo b/brook/programmable/modules/bypass_geo.tengo
index 932d43be15..4bf24823ff 100644
--- a/brook/programmable/modules/bypass_geo.tengo
+++ b/brook/programmable/modules/bypass_geo.tengo
@@ -8,7 +8,7 @@ modules = append(modules, {
return r
}
s := brook.country(r.host)
- if s == "ZZ" || s == "CN" {
+ if s == "ZZ" || s == "CN" { // All private IPs are ZZ
return { bypass: true }
}
}
diff --git a/brook/programmable/modules/readme.md b/brook/programmable/modules/readme.md
index 749688de39..a8e7f95dd8 100644
--- a/brook/programmable/modules/readme.md
+++ b/brook/programmable/modules/readme.md
@@ -1,3 +1,36 @@
+## Brook GUI
+
+In Brook GUI, scripts are abstracted into modules, and it will automatically combine `_header.tengo` and `_footer.tengo`, so you only need to write the module itself.
+
+```
+modules = append(modules, {
+ // If you want to predefine multiple brook links, and then programmatically specify which one to connect to, then define `brooklinks` key a function
+ brooklinks: func(m) {
+ // Please refer to the example in `brooklinks.tengo`
+ },
+ // If you want to intercept and handle a DNS query, then define `dnsquery` key a function, `m` is the `in_dnsquery`
+ dnsquery: func(m) {
+ // Please refer to the example in `block_aaaa.tengo`
+ },
+ // If you want to intercept and handle an address, then define `address` key a function, `m` is the `in_address`
+ address: func(m) {
+ // Please refer to the example in `block_google_secure_dns.tengo`
+ },
+ // If you want to intercept and handle a http request, then define `httprequest` key a function, `request` is the `in_httprequest`
+ httprequest: func(request) {
+ // Please refer to the example in `ios_app_downgrade.tengo` or `redirect_google_cn.tengo`
+ },
+ // If you want to intercept and handle a http response, then define `httpresponse` key a function, `request` is the `in_httprequest`, `response` is the `in_httpresponse`
+ httpresponse: func(request, response) {
+ // Please refer to the example in `response_sample.tengo`
+ }
+})
+```
+
+## tun2brook
+
+If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:
+
```
cat _header.tengo > my.tengo
diff --git a/brook/programmable/modules/xbox.tengo b/brook/programmable/modules/xbox.tengo
new file mode 100644
index 0000000000..5fede34bd8
--- /dev/null
+++ b/brook/programmable/modules/xbox.tengo
@@ -0,0 +1,25 @@
+// Unlock Xbox country limit
+// [CA]
+
+modules = append(modules, {
+ address: func(m) {
+ if m.domainaddress {
+ if m.domainaddress == "www.xbox.com:443" || m.domainaddress == "xgpuweb.gssv-play-prod.xboxlive.com:443" {
+ if m.network == "tcp" {
+ return {"mitm": true, "mitmprotocol": "https"}
+ }
+ if m.network == "udp" {
+ return { "block": true }
+ }
+ }
+ }
+ },
+ httprequest: func(request) {
+ text := import("text")
+ if text.has_prefix(request["URL"], "https://www.xbox.com") || text.has_prefix(request["URL"], "https://xgpuweb.gssv-play-prod.xboxlive.com") {
+ request["X-Forwarded-For"] = "4.2.2.2" // Any country IP you want
+ return request
+ }
+ }
+})
+
diff --git a/clash-meta-android/core/src/foss/golang/clash/README.md b/clash-meta-android/core/src/foss/golang/clash/README.md
index 975f1268e0..d38fbedd8a 100644
--- a/clash-meta-android/core/src/foss/golang/clash/README.md
+++ b/clash-meta-android/core/src/foss/golang/clash/README.md
@@ -98,4 +98,3 @@ API.
This software is released under the GPL-3.0 license.
-[](https://app.fossa.io/projects/git%2Bgithub.com%2FMetaCubeX%2Fmihomo?ref=badge_large)
diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go
index 98932f0c41..714c4a7d68 100644
--- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go
+++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go
@@ -166,12 +166,6 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta
// ListenPacketWithDialer implements C.ProxyAdapter
func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
- if len(ss.option.DialerProxy) > 0 {
- dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer)
- if err != nil {
- return nil, err
- }
- }
if ss.option.UDPOverTCP {
tcpConn, err := ss.DialContextWithDialer(ctx, dialer, metadata)
if err != nil {
@@ -179,6 +173,12 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial
}
return ss.ListenPacketOnStreamConn(ctx, tcpConn, metadata)
}
+ if len(ss.option.DialerProxy) > 0 {
+ dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer)
+ if err != nil {
+ return nil, err
+ }
+ }
addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer)
if err != nil {
return nil, err
diff --git a/clash-meta-android/core/src/foss/golang/clash/component/resolver/host.go b/clash-meta-android/core/src/foss/golang/clash/component/resolver/host.go
index 4a42962903..7e299a099d 100644
--- a/clash-meta-android/core/src/foss/golang/clash/component/resolver/host.go
+++ b/clash-meta-android/core/src/foss/golang/clash/component/resolver/host.go
@@ -13,7 +13,10 @@ import (
"github.com/zhangyunhao116/fastrand"
)
-var DisableSystemHosts, _ = strconv.ParseBool(os.Getenv("DISABLE_SYSTEM_HOSTS"))
+var (
+ DisableSystemHosts, _ = strconv.ParseBool(os.Getenv("DISABLE_SYSTEM_HOSTS"))
+ UseSystemHosts bool
+)
type Hosts struct {
*trie.DomainTrie[HostValue]
@@ -51,7 +54,8 @@ func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) {
return &hostValue, false
}
- if !isDomain && !DisableSystemHosts {
+
+ if !isDomain && !DisableSystemHosts && UseSystemHosts {
addr, _ := lookupStaticHost(domain)
if hostValue, err := NewHostValue(addr); err == nil {
return &hostValue, true
diff --git a/clash-meta-android/core/src/foss/golang/clash/config/config.go b/clash-meta-android/core/src/foss/golang/clash/config/config.go
index f425092ac3..b76c40ff8c 100644
--- a/clash-meta-android/core/src/foss/golang/clash/config/config.go
+++ b/clash-meta-android/core/src/foss/golang/clash/config/config.go
@@ -114,6 +114,7 @@ type DNS struct {
PreferH3 bool `yaml:"prefer-h3"`
IPv6 bool `yaml:"ipv6"`
IPv6Timeout uint `yaml:"ipv6-timeout"`
+ UseSystemHosts bool `yaml:"use-system-hosts"`
NameServer []dns.NameServer `yaml:"nameserver"`
Fallback []dns.NameServer `yaml:"fallback"`
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
@@ -209,6 +210,7 @@ type RawDNS struct {
IPv6 bool `yaml:"ipv6" json:"ipv6"`
IPv6Timeout uint `yaml:"ipv6-timeout" json:"ipv6-timeout"`
UseHosts bool `yaml:"use-hosts" json:"use-hosts"`
+ UseSystemHosts bool `yaml:"use-system-hosts" json:"use-system-hosts"`
NameServer []string `yaml:"nameserver" json:"nameserver"`
Fallback []string `yaml:"fallback" json:"fallback"`
FallbackFilter RawFallbackFilter `yaml:"fallback-filter" json:"fallback-filter"`
@@ -456,12 +458,13 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
Interval: 30,
},
DNS: RawDNS{
- Enable: false,
- IPv6: false,
- UseHosts: true,
- IPv6Timeout: 100,
- EnhancedMode: C.DNSMapping,
- FakeIPRange: "198.18.0.1/16",
+ Enable: false,
+ IPv6: false,
+ UseHosts: true,
+ UseSystemHosts: true,
+ IPv6Timeout: 100,
+ EnhancedMode: C.DNSMapping,
+ FakeIPRange: "198.18.0.1/16",
FallbackFilter: RawFallbackFilter{
GeoIP: true,
GeoIPCode: "CN",
@@ -1285,12 +1288,13 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
}
dnsCfg := &DNS{
- Enable: cfg.Enable,
- Listen: cfg.Listen,
- PreferH3: cfg.PreferH3,
- IPv6Timeout: cfg.IPv6Timeout,
- IPv6: cfg.IPv6,
- EnhancedMode: cfg.EnhancedMode,
+ Enable: cfg.Enable,
+ Listen: cfg.Listen,
+ PreferH3: cfg.PreferH3,
+ IPv6Timeout: cfg.IPv6Timeout,
+ IPv6: cfg.IPv6,
+ UseSystemHosts: cfg.UseSystemHosts,
+ EnhancedMode: cfg.EnhancedMode,
FallbackFilter: FallbackFilter{
IPCIDR: []netip.Prefix{},
GeoSite: []router.DomainMatcher{},
diff --git a/clash-meta-android/core/src/foss/golang/clash/go.mod b/clash-meta-android/core/src/foss/golang/clash/go.mod
index dad18d9e87..0769a21230 100644
--- a/clash-meta-android/core/src/foss/golang/clash/go.mod
+++ b/clash-meta-android/core/src/foss/golang/clash/go.mod
@@ -20,7 +20,7 @@ require (
github.com/mdlayher/netlink v1.7.2
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759
github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6
- github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e
+ github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f
github.com/metacubex/sing-shadowsocks v0.2.6
github.com/metacubex/sing-shadowsocks2 v0.2.0
github.com/metacubex/sing-tun v0.2.6
diff --git a/clash-meta-android/core/src/foss/golang/clash/go.sum b/clash-meta-android/core/src/foss/golang/clash/go.sum
index 8c4836b2b9..a4d90759fb 100644
--- a/clash-meta-android/core/src/foss/golang/clash/go.sum
+++ b/clash-meta-android/core/src/foss/golang/clash/go.sum
@@ -108,8 +108,8 @@ github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxV
github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk=
github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 h1:+czGKoynxYA90YaL3NlCAIJHnlqwoUlLWgmOhdm5ZU8=
github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI=
-github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e h1:UW+yfzoLzjEhAoJ6A4mVnov3Aergi7uFM/h7ReNekKI=
-github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4=
+github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f h1:Xyd8SHaPHS3iX3xXPnus9PsYhJIo/2e7sJ6vTKLKUm8=
+github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4=
github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ=
github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg=
github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A=
diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go b/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go
index c23eb9f3ba..56e716326b 100644
--- a/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go
+++ b/clash-meta-android/core/src/foss/golang/clash/hub/executor/executor.go
@@ -253,6 +253,7 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen
resolver.DefaultResolver = r
resolver.DefaultHostMapper = m
resolver.DefaultLocalServer = dns.NewLocalServer(r, m)
+ resolver.UseSystemHosts = c.UseSystemHosts
if pr.Invalid() {
resolver.ProxyServerHostResolver = pr
diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/updater/updater.go b/clash-meta-android/core/src/foss/golang/clash/hub/updater/updater.go
index 02ff07ba26..df5da3f4d1 100644
--- a/clash-meta-android/core/src/foss/golang/clash/hub/updater/updater.go
+++ b/clash-meta-android/core/src/foss/golang/clash/hub/updater/updater.go
@@ -16,7 +16,6 @@ import (
"time"
mihomoHttp "github.com/metacubex/mihomo/component/http"
- "github.com/metacubex/mihomo/constant"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"
@@ -52,6 +51,10 @@ func init() {
if runtime.GOARCH == "amd64" && cpuid.CPU.X64Level() < 3 {
amd64Compatible = "-compatible"
}
+ if !strings.HasPrefix(C.Version, "alpha") {
+ baseURL = "https://github.com/MetaCubeX/mihomo/releases/latest/download/mihomo"
+ versionURL = "https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt"
+ }
}
type updateError struct {
@@ -73,9 +76,9 @@ func Update(execPath string) (err error) {
return err
}
- log.Infoln("current version %s, latest version %s", constant.Version, latestVersion)
+ log.Infoln("current version %s, latest version %s", C.Version, latestVersion)
- if latestVersion == constant.Version {
+ if latestVersion == C.Version {
err := &updateError{Message: "already using latest version"}
return err
}
diff --git a/clash-meta-android/core/src/foss/golang/go.mod b/clash-meta-android/core/src/foss/golang/go.mod
index e652ea92ad..aa605bbc3e 100644
--- a/clash-meta-android/core/src/foss/golang/go.mod
+++ b/clash-meta-android/core/src/foss/golang/go.mod
@@ -48,7 +48,7 @@ require (
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect
github.com/metacubex/mihomo v1.7.0 // indirect
github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 // indirect
- github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e // indirect
+ github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f // indirect
github.com/metacubex/sing-shadowsocks v0.2.6 // indirect
github.com/metacubex/sing-shadowsocks2 v0.2.0 // indirect
github.com/metacubex/sing-tun v0.2.6 // indirect
diff --git a/clash-meta-android/core/src/foss/golang/go.sum b/clash-meta-android/core/src/foss/golang/go.sum
index c187d06f08..7e08513769 100644
--- a/clash-meta-android/core/src/foss/golang/go.sum
+++ b/clash-meta-android/core/src/foss/golang/go.sum
@@ -102,8 +102,8 @@ github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxV
github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk=
github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2 h1:upEO8dt9WDBavhgcgkXB3hRcwVNbkTbnd+xyzy6ZQZo=
github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
-github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e h1:UW+yfzoLzjEhAoJ6A4mVnov3Aergi7uFM/h7ReNekKI=
-github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4=
+github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f h1:Xyd8SHaPHS3iX3xXPnus9PsYhJIo/2e7sJ6vTKLKUm8=
+github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4=
github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ=
github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg=
github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A=
diff --git a/clash-meta-android/core/src/main/golang/go.mod b/clash-meta-android/core/src/main/golang/go.mod
index c4afc6ea0f..8f72bf3fd7 100644
--- a/clash-meta-android/core/src/main/golang/go.mod
+++ b/clash-meta-android/core/src/main/golang/go.mod
@@ -55,7 +55,7 @@ require (
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect
github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 // indirect
- github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e // indirect
+ github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f // indirect
github.com/metacubex/sing-shadowsocks v0.2.6 // indirect
github.com/metacubex/sing-shadowsocks2 v0.2.0 // indirect
github.com/metacubex/sing-tun v0.2.6 // indirect
diff --git a/clash-meta-android/core/src/main/golang/go.sum b/clash-meta-android/core/src/main/golang/go.sum
index c187d06f08..7e08513769 100644
--- a/clash-meta-android/core/src/main/golang/go.sum
+++ b/clash-meta-android/core/src/main/golang/go.sum
@@ -102,8 +102,8 @@ github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxV
github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk=
github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2 h1:upEO8dt9WDBavhgcgkXB3hRcwVNbkTbnd+xyzy6ZQZo=
github.com/metacubex/sing v0.0.0-20240111014253-f1818b6a82b2/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
-github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e h1:UW+yfzoLzjEhAoJ6A4mVnov3Aergi7uFM/h7ReNekKI=
-github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4=
+github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f h1:Xyd8SHaPHS3iX3xXPnus9PsYhJIo/2e7sJ6vTKLKUm8=
+github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4=
github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ=
github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg=
github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A=
diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock
index 18bac70b5f..b60e87e385 100644
--- a/clash-nyanpasu/backend/Cargo.lock
+++ b/clash-nyanpasu/backend/Cargo.lock
@@ -2486,7 +2486,7 @@ dependencies = [
"httpdate",
"itoa 1.0.11",
"pin-project-lite",
- "socket2 0.5.7",
+ "socket2 0.4.10",
"tokio",
"tower-service",
"tracing",
@@ -5672,9 +5672,9 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
[[package]]
name = "tauri"
-version = "1.6.3"
+version = "1.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a4fab012dcf1e72762561cef2c08a6538aec2ca44d282158128117f79eb9d39"
+checksum = "13ce04f77bcd40bb57ec7061725c9c415d30b2bf80257637b857ee067f2fa198"
dependencies = [
"anyhow",
"base64 0.21.7",
@@ -5830,9 +5830,9 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
-version = "0.14.6"
+version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a777eaa0d88ae47d8081cdc667eba8941b3a18af0f0ccb22640d8f0c3431d6d1"
+checksum = "ef2af45aeb15b1cadb4ca91248423f4438a0864b836298cecb436892afbfdff4"
dependencies = [
"cocoa 0.24.1",
"gtk",
diff --git a/clash-nyanpasu/backend/tauri/tauri.conf.json b/clash-nyanpasu/backend/tauri/tauri.conf.json
index 5a3cb8765b..a2de6ab7ef 100644
--- a/clash-nyanpasu/backend/tauri/tauri.conf.json
+++ b/clash-nyanpasu/backend/tauri/tauri.conf.json
@@ -102,7 +102,7 @@
},
"windows": [],
"security": {
- "csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src data: 'self';"
+ "csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src data: 'self' https:;"
}
}
}
diff --git a/clash-nyanpasu/frontend/interface/package.json b/clash-nyanpasu/frontend/interface/package.json
index 4e5339cf10..11baa390b4 100644
--- a/clash-nyanpasu/frontend/interface/package.json
+++ b/clash-nyanpasu/frontend/interface/package.json
@@ -4,7 +4,7 @@
"main": "index.ts",
"module": "index.ts",
"dependencies": {
- "@tauri-apps/api": "1.5.4",
+ "@tauri-apps/api": "1.5.5",
"ofetch": "1.3.4",
"react": "18.3.1",
"swr": "2.2.5"
diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json
index 16c33091c0..e34c80f27a 100644
--- a/clash-nyanpasu/frontend/nyanpasu/package.json
+++ b/clash-nyanpasu/frontend/nyanpasu/package.json
@@ -22,12 +22,12 @@
"@mui/x-data-grid": "7.3.2",
"@nyanpasu/interface": "workspace:^",
"@nyanpasu/ui": "workspace:^",
- "@tauri-apps/api": "1.5.4",
+ "@tauri-apps/api": "1.5.5",
"ahooks": "3.7.11",
"axios": "1.6.8",
"dayjs": "1.11.11",
"framer-motion": "11.1.9",
- "i18next": "23.11.3",
+ "i18next": "23.11.4",
"jotai": "2.8.0",
"monaco-editor": "0.48.0",
"mui-color-input": "2.0.3",
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.ts
deleted file mode 100644
index 294cc480ae..0000000000
--- a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { useEffect, useMemo } from "react";
-import { alpha, Theme } from "@mui/material";
-import { appWindow } from "@tauri-apps/api/window";
-import { defaultTheme, defaultDarkTheme } from "@/pages/_theme";
-import { useNyanpasu } from "@nyanpasu/interface";
-import { createMDYTheme } from "@nyanpasu/ui";
-import { useAtom } from "jotai";
-import { themeMode } from "@/store";
-
-const applyRootStyleVar = (mode: "light" | "dark", theme: Theme) => {
- const root = document.documentElement;
-
- root.style.setProperty(
- "--background-color",
- mode === "light" ? "#ffffff" : "#121212",
- );
-
- root.style.setProperty(
- "--selection-color",
- mode === "light" ? "#f5f5f5" : "#d5d5d5",
- );
-
- root.style.setProperty(
- "--scroller-color",
- mode === "light" ? "#90939980" : "#54545480",
- );
-
- root.style.setProperty("--primary-main", theme.palette.primary.main);
-
- root.style.setProperty(
- "--background-color-alpha",
- alpha(theme.palette.primary.main, 0.1),
- );
-};
-
-/**
- * custom theme
- */
-export const useCustomTheme = () => {
- const { nyanpasuConfig } = useNyanpasu();
-
- const [mode, setMode] = useAtom(themeMode);
-
- useEffect(() => {
- if (nyanpasuConfig?.theme_mode === "system") {
- appWindow.theme().then((m) => m && setMode(m));
-
- const unlisten = appWindow.onThemeChanged((e) => setMode(e.payload));
-
- return () => {
- unlisten.then((fn) => fn());
- };
- }
-
- if (nyanpasuConfig?.theme_mode) {
- setMode(nyanpasuConfig?.theme_mode);
- } else {
- setMode("light");
- }
- }, [nyanpasuConfig?.theme_mode]);
-
- const theme = useMemo(() => {
- const dt = mode === "light" ? defaultTheme : defaultDarkTheme;
-
- const theme = createMDYTheme(
- {
- ...dt,
- ...nyanpasuConfig?.theme_setting,
- },
- mode,
- );
-
- applyRootStyleVar(mode, theme);
-
- return theme;
- }, [mode, nyanpasuConfig?.theme_setting]);
-
- return { theme };
-};
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.tsx
new file mode 100644
index 0000000000..d4137b9318
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.tsx
@@ -0,0 +1,83 @@
+import { useEffect, useMemo } from "react";
+import { alpha, Theme, useColorScheme } from "@mui/material";
+import { appWindow } from "@tauri-apps/api/window";
+import { defaultTheme } from "@/pages/_theme";
+import { useNyanpasu } from "@nyanpasu/interface";
+import { createMDYTheme } from "@nyanpasu/ui";
+import { useAtomValue, useSetAtom } from "jotai";
+import { themeMode as themeModeAtom } from "@/store";
+
+const applyRootStyleVar = (mode: "light" | "dark", theme: Theme) => {
+ const root = document.documentElement;
+ const palette = theme.colorSchemes[mode].palette;
+
+ const isLightMode = mode !== "light";
+
+ const backgroundColor = isLightMode ? "#121212" : "#ffffff";
+ const selectionColor = isLightMode ? "#d5d5d5" : "#f5f5f5";
+ const scrollerColor = isLightMode ? "#54545480" : "#90939980";
+
+ root.style.setProperty("--background-color", backgroundColor);
+ root.style.setProperty("--selection-color", selectionColor);
+ root.style.setProperty("--scroller-color", scrollerColor);
+ root.style.setProperty("--primary-main", palette.primary.main);
+ root.style.setProperty(
+ "--background-color-alpha",
+ alpha(palette.primary.main, 0.1),
+ );
+};
+
+/**
+ * custom theme
+ */
+export const useCustomTheme = () => {
+ const { nyanpasuConfig } = useNyanpasu();
+ const themeMode = useAtomValue(themeModeAtom);
+
+ const theme = useMemo(() => {
+ const mergedTheme = createMDYTheme({
+ ...defaultTheme,
+ ...nyanpasuConfig?.theme_setting,
+ });
+
+ applyRootStyleVar(themeMode, mergedTheme);
+
+ return mergedTheme;
+ }, [nyanpasuConfig?.theme_setting, themeMode]);
+
+ return { theme };
+};
+
+export const ThemeModeProvider = () => {
+ const { nyanpasuConfig } = useNyanpasu();
+
+ const setThemeMode = useSetAtom(themeModeAtom);
+
+ const { setMode } = useColorScheme();
+
+ useEffect(() => {
+ if (nyanpasuConfig?.theme_mode === "system") {
+ appWindow.theme().then((m) => {
+ if (m) {
+ setThemeMode(m);
+ setMode(m);
+ }
+ });
+
+ const unlisten = appWindow.onThemeChanged((e) => {
+ setThemeMode(e.payload);
+ setMode(e.payload);
+ });
+
+ return () => {
+ unlisten.then((fn) => fn());
+ };
+ }
+
+ const chosenThemeMode = nyanpasuConfig?.theme_mode || "light";
+ setThemeMode(chosenThemeMode);
+ setMode(chosenThemeMode);
+ }, [nyanpasuConfig?.theme_mode]);
+
+ return null;
+};
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/_app.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/_app.tsx
index 07d148e48c..f6f436ad67 100644
--- a/clash-nyanpasu/frontend/nyanpasu/src/pages/_app.tsx
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/_app.tsx
@@ -1,6 +1,9 @@
import { LayoutControl } from "@/components/layout/layout-control";
import { LayoutTraffic } from "@/components/layout/layout-traffic";
-import { useCustomTheme } from "@/components/layout/use-custom-theme";
+import {
+ ThemeModeProvider,
+ useCustomTheme,
+} from "@/components/layout/use-custom-theme";
import { NotificationType, useNotification } from "@/hooks/use-notification";
import { useVerge } from "@/hooks/use-verge";
import { getAxios } from "@/services/api";
@@ -26,6 +29,7 @@ import { classNames } from "@/utils";
import AnimatedLogo from "@/components/layout/animated-logo";
import { FallbackProps } from "react-error-boundary";
import styles from "./_app.module.scss";
+import { Experimental_CssVarsProvider as CssVarsProvider } from "@mui/material/styles";
dayjs.extend(relativeTime);
@@ -142,7 +146,8 @@ export default function App() {
return (
-
+
+
-
+
);
}
@@ -216,7 +221,7 @@ export const Catch = ({ error }: FallbackProps) => {
>
Oops!
Something went wrong... Caught at _app error boundary.
- {error.message}
+ {error}
);
};
diff --git a/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts b/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts
index a01b46490f..6abbff3bdb 100644
--- a/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts
+++ b/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts
@@ -1,4 +1,4 @@
-import createTheme from "@mui/material/styles/createTheme";
+import extendTheme from "@mui/material/styles/experimental_extendTheme";
import createPalette from "@mui/material/styles/createPalette";
import {
argbFromHex,
@@ -30,33 +30,41 @@ interface ThemeSchema {
font_family?: string;
}
-export const createMDYTheme = (
- themeSchema: ThemeSchema,
- mode: "light" | "dark",
-) => {
+export const createMDYTheme = (themeSchema: ThemeSchema) => {
const materialColor = themeFromSourceColor(
argbFromHex(themeSchema.primary_color),
);
- const palette = createPalette({
- mode,
- primary: {
- main: hexFromArgb(materialColor.schemes[mode].primary),
- },
- secondary: {
- main: hexFromArgb(materialColor.schemes[mode].secondary),
- },
- error: {
- main: hexFromArgb(materialColor.schemes[mode].error),
- },
- text: {
- primary: hexFromArgb(materialColor.schemes[mode].onPrimaryContainer),
- secondary: hexFromArgb(materialColor.schemes[mode].onSecondaryContainer),
- },
- });
+ const generatePalette = (mode: "light" | "dark") => {
+ return createPalette({
+ mode,
+ primary: {
+ main: hexFromArgb(materialColor.schemes[mode].primary),
+ },
+ secondary: {
+ main: hexFromArgb(materialColor.schemes[mode].secondary),
+ },
+ error: {
+ main: hexFromArgb(materialColor.schemes[mode].error),
+ },
+ text: {
+ primary: hexFromArgb(materialColor.schemes[mode].onPrimaryContainer),
+ secondary: hexFromArgb(
+ materialColor.schemes[mode].onSecondaryContainer,
+ ),
+ },
+ });
+ };
- return createTheme({
- palette,
+ const theme = extendTheme({
+ colorSchemes: {
+ light: {
+ palette: generatePalette("light"),
+ },
+ dark: {
+ palette: generatePalette("dark"),
+ },
+ },
typography: {
fontFamily: themeSchema?.font_family,
},
@@ -70,7 +78,7 @@ export const createMDYTheme = (
MuiDialogContent,
MuiDialogTitle,
// MuiPaper,
- MuiSwitch: MuiSwitch(palette),
+ MuiSwitch,
},
breakpoints: {
values: {
@@ -82,4 +90,8 @@ export const createMDYTheme = (
},
},
});
+
+ console.log(theme);
+
+ return theme;
};
diff --git a/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiSwitch.ts b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiSwitch.ts
index 3caf90bf45..75a56946ce 100644
--- a/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiSwitch.ts
+++ b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiSwitch.ts
@@ -1,116 +1,123 @@
import { Theme } from "@mui/material";
import { Components } from "@mui/material/styles/components";
-import { Palette } from "@mui/material/styles/createPalette";
+import type {} from "@mui/material/themeCssVarsAugmentation";
-export const MuiSwitch = (palette: Palette): Components["MuiSwitch"] => {
- const isDark = palette.mode === "dark";
+export const MuiSwitch: Components["MuiSwitch"] = {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ padding: 0,
+ margin: 0,
- return {
- styleOverrides: {
- root: {
- padding: 0,
- margin: 0,
+ "& .Mui-checked": {
+ "& .MuiSwitch-thumb": {
+ color: theme.palette.grey.A100,
+ },
+ },
+
+ "&:has(.Mui-checked) .MuiSwitch-track::before": {
+ opacity: 0,
+ },
+
+ "&:has(.Mui-disabled) .MuiSwitch-track": {
+ opacity: "0.5 !important",
+ cursor: "not-allowed",
+ },
+ }),
+
+ track: ({ theme }) => ({
+ borderRadius: "48px",
+ backgroundColor: theme.palette.grey.A200,
+ opacity: `1 !important`,
+
+ [theme.getColorSchemeSelector("dark")]: {
+ backgroundColor: theme.palette.grey.A700,
+ opacity: `0.7 !important`,
+ },
+
+ "&::before": {
+ content: '""',
+ border: `solid 2px ${theme.palette.grey.A700}`,
+ width: "100%",
+ height: "100%",
+ opacity: 1,
+ position: "absolute",
+ borderRadius: "inherit",
+ boxSizing: "border-box",
+ transitionProperty: "opacity, background-color",
+ transitionTimingFunction: "linear",
+ transitionDuration: "100ms",
+ },
+ }),
+
+ thumb: ({ theme }) => ({
+ boxShadow: "none",
+ color: theme.palette.grey.A700,
+
+ [theme.getColorSchemeSelector("dark")]: {
+ backgroundColor: theme.palette.grey.A200,
+ },
+ }),
+ },
+ variants: [
+ {
+ props: {
+ size: "medium",
+ },
+ style: {
+ height: 32,
+
+ "& .MuiSwitch-switchBase": {
+ padding: "6px",
+ },
+
+ "& .MuiSwitch-thumb": {
+ width: 14,
+ height: 14,
+ margin: 3,
+ },
"& .Mui-checked": {
+ "&.MuiSwitch-switchBase": {
+ marginLeft: "6px",
+ },
+
"& .MuiSwitch-thumb": {
- color: palette.grey.A100,
+ width: 24,
+ height: 24,
+ margin: -2,
},
},
-
- "&:has(.Mui-checked) .MuiSwitch-track::before": {
- opacity: 0,
- },
-
- "&:has(.Mui-disabled) .MuiSwitch-track": {
- opacity: "0.5 !important",
- cursor: "not-allowed",
- },
- },
- track: {
- borderRadius: "48px",
- backgroundColor: isDark ? palette.grey.A700 : palette.grey.A200,
- opacity: `${isDark ? 0.7 : 1} !important`,
-
- "&::before": {
- content: '""',
- border: `solid 2px ${palette.grey.A700}`,
- width: "100%",
- height: "100%",
- opacity: 1,
- position: "absolute",
- borderRadius: "inherit",
- boxSizing: "border-box",
- transitionProperty: "opacity, background-color",
- transitionTimingFunction: "linear",
- transitionDuration: "100ms",
- },
- },
- thumb: {
- boxShadow: "none",
- color: isDark ? palette.grey.A200 : palette.grey.A700,
},
},
- variants: [
- {
- props: {
- size: "medium",
- },
- style: {
- height: 32,
+ {
+ props: {
+ size: "small",
+ },
+ style: {
+ height: 24,
- "& .MuiSwitch-switchBase": {
- padding: "6px",
+ "& .MuiSwitch-switchBase": {
+ padding: "3px",
+ },
+
+ "& .MuiSwitch-thumb": {
+ width: 12,
+ height: 12,
+ margin: 3,
+ },
+
+ "& .Mui-checked": {
+ "&.MuiSwitch-switchBase": {
+ marginLeft: "1px",
},
"& .MuiSwitch-thumb": {
- width: 14,
- height: 14,
- margin: 3,
- },
-
- "& .Mui-checked": {
- "&.MuiSwitch-switchBase": {
- marginLeft: "6px",
- },
-
- "& .MuiSwitch-thumb": {
- width: 24,
- height: 24,
- margin: -2,
- },
+ width: 17,
+ height: 17,
+ margin: 0,
},
},
},
- {
- props: {
- size: "small",
- },
- style: {
- height: 24,
-
- "& .MuiSwitch-switchBase": {
- padding: "3px",
- },
-
- "& .MuiSwitch-thumb": {
- width: 12,
- height: 12,
- margin: 3,
- },
-
- "& .Mui-checked": {
- "&.MuiSwitch-switchBase": {
- marginLeft: "1px",
- },
-
- "& .MuiSwitch-thumb": {
- width: 17,
- height: 17,
- margin: 0,
- },
- },
- },
- },
- ],
- };
+ },
+ ],
};
diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml
index dd1005d19a..24be8037d0 100644
--- a/clash-nyanpasu/pnpm-lock.yaml
+++ b/clash-nyanpasu/pnpm-lock.yaml
@@ -143,8 +143,8 @@ importers:
frontend/interface:
dependencies:
'@tauri-apps/api':
- specifier: 1.5.4
- version: 1.5.4
+ specifier: 1.5.5
+ version: 1.5.5
ofetch:
specifier: 1.3.4
version: 1.3.4
@@ -201,8 +201,8 @@ importers:
specifier: workspace:^
version: link:../ui
'@tauri-apps/api':
- specifier: 1.5.4
- version: 1.5.4
+ specifier: 1.5.5
+ version: 1.5.5
ahooks:
specifier: 3.7.11
version: 3.7.11(react@19.0.0-beta-e7d213dfb0-20240507)
@@ -216,8 +216,8 @@ importers:
specifier: 11.1.9
version: 11.1.9(@emotion/is-prop-valid@1.2.2)(react-dom@19.0.0-beta-e7d213dfb0-20240507(react@19.0.0-beta-e7d213dfb0-20240507))(react@19.0.0-beta-e7d213dfb0-20240507)
i18next:
- specifier: 23.11.3
- version: 23.11.3
+ specifier: 23.11.4
+ version: 23.11.4
jotai:
specifier: 2.8.0
version: 2.8.0(react@19.0.0-beta-e7d213dfb0-20240507)(types-react@19.0.0-beta.1)
@@ -244,7 +244,7 @@ importers:
version: 7.51.4(react@19.0.0-beta-e7d213dfb0-20240507)
react-i18next:
specifier: 14.1.1
- version: 14.1.1(i18next@23.11.3)(react-dom@19.0.0-beta-e7d213dfb0-20240507(react@19.0.0-beta-e7d213dfb0-20240507))(react@19.0.0-beta-e7d213dfb0-20240507)
+ version: 14.1.1(i18next@23.11.4)(react-dom@19.0.0-beta-e7d213dfb0-20240507(react@19.0.0-beta-e7d213dfb0-20240507))(react@19.0.0-beta-e7d213dfb0-20240507)
react-markdown:
specifier: 9.0.1
version: 9.0.1(react@19.0.0-beta-e7d213dfb0-20240507)(types-react@19.0.0-beta.1)
@@ -1453,8 +1453,8 @@ packages:
'@taplo/lib@0.4.0-alpha.2':
resolution: {integrity: sha512-DV/Re3DPVY+BhBtLZ3dmP4mP6YMLSsgq9qGLXwOV38lvNF/fBlgvQswzlXmzCEefL/3q2eMoefZpOI/+GLuCNA==}
- '@tauri-apps/api@1.5.4':
- resolution: {integrity: sha512-LKYae9URbdEdbHrOXBeXb/lZgVyWTX0E98rSFBuQlmkLr8OeG+akuE41PfLjBVyk1Q+fq7wxo4ieenLSMUAUhA==}
+ '@tauri-apps/api@1.5.5':
+ resolution: {integrity: sha512-Jgwj8BK/9YXZNzcqVDk1Al7+u5V9sWrZ8MhV41A1AKgJaicHuqlkc/qdx06sNDXvc+qprTPpBAaqnt891qOUIQ==}
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
'@tauri-apps/cli-darwin-arm64@1.5.13':
@@ -2864,8 +2864,8 @@ packages:
resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==}
engines: {node: '>=18'}
- i18next@23.11.3:
- resolution: {integrity: sha512-Pq/aSKowir7JM0rj+Wa23Kb6KKDUGno/HjG+wRQu0PxoTbpQ4N89MAT0rFGvXmLkRLNMb1BbBOKGozl01dabzg==}
+ i18next@23.11.4:
+ resolution: {integrity: sha512-CCUjtd5TfaCl+mLUzAA0uPSN+AVn4fP/kWCYt/hocPUwusTpMVczdrRyOBUwk6N05iH40qiKx6q1DoNJtBIwdg==}
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
@@ -5875,7 +5875,7 @@ snapshots:
dependencies:
'@taplo/core': 0.1.1
- '@tauri-apps/api@1.5.4': {}
+ '@tauri-apps/api@1.5.5': {}
'@tauri-apps/cli-darwin-arm64@1.5.13':
optional: true
@@ -7558,7 +7558,7 @@ snapshots:
husky@9.0.11: {}
- i18next@23.11.3:
+ i18next@23.11.4:
dependencies:
'@babel/runtime': 7.24.5
@@ -8698,11 +8698,11 @@ snapshots:
dependencies:
react: 19.0.0-beta-e7d213dfb0-20240507
- react-i18next@14.1.1(i18next@23.11.3)(react-dom@19.0.0-beta-e7d213dfb0-20240507(react@19.0.0-beta-e7d213dfb0-20240507))(react@19.0.0-beta-e7d213dfb0-20240507):
+ react-i18next@14.1.1(i18next@23.11.4)(react-dom@19.0.0-beta-e7d213dfb0-20240507(react@19.0.0-beta-e7d213dfb0-20240507))(react@19.0.0-beta-e7d213dfb0-20240507):
dependencies:
'@babel/runtime': 7.24.5
html-parse-stringify: 3.0.1
- i18next: 23.11.3
+ i18next: 23.11.4
react: 19.0.0-beta-e7d213dfb0-20240507
optionalDependencies:
react-dom: 19.0.0-beta-e7d213dfb0-20240507(react@19.0.0-beta-e7d213dfb0-20240507)
diff --git a/echo/hack/get-ehco.sh b/echo/hack/get-ehco.sh
index c87e2ad58d..d031622fdd 100755
--- a/echo/hack/get-ehco.sh
+++ b/echo/hack/get-ehco.sh
@@ -17,7 +17,7 @@ SYSTEMD_SERVICES_DIR="/etc/systemd/system"
# curl command line flags.
# To using a proxy, please specify ALL_PROXY in the environ variable, such like:
# export ALL_PROXY=socks5h://192.0.2.1:1080
-CURL_FLAGS=(-L -f -q --retry 5 --retry-delay 10 --retry-max-time 60)
+CURL_FLAGS=(-L --retry 5 --retry-delay 10 --retry-max-time 60)
###
# ARGUMENTS
@@ -66,12 +66,12 @@ function _check_install_required() {
# check jq and curl
if ! command -v jq &>/dev/null; then
- _print_error_msg "jq is required to parse JSON data."
+ _print_error_msg "jq is required to parse JSON data. please use apt/yum to install jq."
exit 1
fi
if ! command -v curl &>/dev/null; then
- _print_error_msg "curl is required to download files."
+ _print_error_msg "curl is required to download files. please use apt/yum to install curl."
exit 1
fi
}
@@ -97,6 +97,7 @@ function _detect_arch() {
echo "Unsupported architecture: $arch" >&2
;;
esac
+ _print_warning_msg "Detected architecture: $TARGET_ARCH"
}
function _print_error_msg() {
@@ -119,9 +120,10 @@ function _set_default_version() {
# TODO check the checksum and current bin file, if the same, skip download
function _download_bin() {
+ printf "Downloading Ehco version: %s\n" "$VERSION"
local api_url="https://api.github.com/repos/Ehco1996/ehco/releases/tags/$VERSION"
local _assets_json
- _assets_json=$(curl -s "${CURL_FLAGS[@]}" "$api_url")
+ _assets_json=$(curl "${CURL_FLAGS[@]}" "$api_url")
# Extract the download URL for the target architecture using jq
download_url=$(echo "$_assets_json" | jq -r --arg TARGET_ARCH "$TARGET_ARCH" '.assets[] | select(.name | contains("ehco_" + $TARGET_ARCH)) | .browser_download_url')
@@ -135,6 +137,11 @@ function _download_bin() {
chmod +x "$EXECUTABLE_INSTALL_PATH"
}
+function _update_bin() {
+ rm -f "$EXECUTABLE_INSTALL_PATH"
+ _download_bin
+}
+
function _install_systemd_service() {
local _service_name="ehco.service"
local _service_path="$SYSTEMD_SERVICES_DIR/$_service_name"
@@ -144,6 +151,11 @@ function _install_systemd_service() {
systemctl start "$_service_name"
}
+function _reload_systemd_service() {
+ systemctl daemon-reload
+ systemctl restart ehco.service
+}
+
function _remove_systemd_service_and_delete_bin() {
local _service_name="ehco.service"
local _service_path="$SYSTEMD_SERVICES_DIR/$_service_name"
@@ -155,6 +167,15 @@ function _remove_systemd_service_and_delete_bin() {
rm -f "$EXECUTABLE_INSTALL_PATH"
}
+function _check_systemd_service() {
+ local _service_name="ehco.service"
+ local _service_path="$SYSTEMD_SERVICES_DIR/$_service_name"
+ if [ ! -f "$_service_path" ]; then
+ _print_error_msg "Ehco service not found. please install it first."
+ exit 1
+ fi
+}
+
function print_help() {
echo "Usage: $SCRIPT_NAME [options]"
echo
@@ -164,7 +185,7 @@ function print_help() {
echo " -i, --install Install the Ehco."
echo " -c, --config Specify the configuration file path or api endpoint."
echo " -r, --remove Remove the Ehco."
- # echo " -u, --check-update Check if an update is available."
+ echo " -u, --check-update Check And Update if an update is available."
}
function parse_arguments() {
@@ -188,9 +209,9 @@ function parse_arguments() {
-r | --remove)
OPERATION="remove"
;;
- # -u | --check-update)
- # OPERATION="check_update"
- # ;;
+ -u | --check-update)
+ OPERATION="check-update"
+ ;;
*)
_print_error_msg "Unknown argument: $1"
exit 1
@@ -220,6 +241,16 @@ function perform_remove() {
_print_warning_msg "Ehco has been removed."
}
+function perform_check_update() {
+ _check_systemd_service
+ _set_default_version
+ _detect_arch
+
+ _update_bin
+ _reload_systemd_service
+ _print_warning_msg "Ehco has been Updated."
+}
+
###
# Entrypoint
###
@@ -232,8 +263,8 @@ function main() {
"remove")
perform_remove
;;
- "check_update")
- # perform_check_update
+ "check-update")
+ perform_check_update
;;
*)
_print_error_msg "Unknown operation: '$OPERATION'."
diff --git a/mieru/pkg/metrics/system_metrics.go b/mieru/pkg/metrics/system_metrics.go
index b7f96ff4cd..d7c96b1e3b 100644
--- a/mieru/pkg/metrics/system_metrics.go
+++ b/mieru/pkg/metrics/system_metrics.go
@@ -19,8 +19,8 @@ const (
// MetricGroup name format for each user.
UserMetricGroupFormat = "user - %s"
- UserMetricReadBytes = "ReadBytes"
- UserMetricWriteBytes = "WriteBytes"
+ UserMetricUploadBytes = "UploadBytes"
+ UserMetricDownloadBytes = "DownloadBytes"
)
var (
@@ -36,12 +36,12 @@ var (
// Current number of established connections.
CurrEstablished = RegisterMetric("connections", "CurrEstablished", GAUGE)
- // Number of bytes receive from proxy connections.
- InBytes = RegisterMetric("traffic", "InBytes", COUNTER)
+ // Number of bytes from client to server.
+ UploadBytes = RegisterMetric("traffic", "UploadBytes", COUNTER)
- // Number of bytes send to proxy connections.
- OutBytes = RegisterMetric("traffic", "OutBytes", COUNTER)
+ // Number of bytes from server to client.
+ DownloadBytes = RegisterMetric("traffic", "DownloadBytes", COUNTER)
// Number of padding bytes send to proxy connections.
- OutPaddingBytes = RegisterMetric("traffic", "OutPaddingBytes", COUNTER)
+ OutputPaddingBytes = RegisterMetric("traffic", "OutputPaddingBytes", COUNTER)
)
diff --git a/mieru/pkg/protocolv2/session.go b/mieru/pkg/protocolv2/session.go
index 1df9f7fc8a..a9e3aa3f0b 100644
--- a/mieru/pkg/protocolv2/session.go
+++ b/mieru/pkg/protocolv2/session.go
@@ -106,8 +106,8 @@ type Session struct {
ackOnDataRecv atomic.Bool // whether ack should be sent due to receive of new data
unreadBuf []byte // payload removed from the recvQueue that haven't been read by application
- readBytes metrics.Metric // number of bytes delivered to the application
- writeBytes metrics.Metric // number of bytes sent from the application
+ uploadBytes metrics.Metric // number of bytes from client to server, only used by server
+ downloadBytes metrics.Metric // number of bytes from server to client, only used by server
rttStat *congestion.RTTStats
sendAlgorithm *congestion.CubicSendAlgorithm
@@ -190,8 +190,8 @@ func (s *Session) Read(b []byte) (n int, err error) {
if log.IsLevelEnabled(log.TraceLevel) {
log.Tracef("%v read %d bytes", s, n)
}
- if s.readBytes != nil {
- s.readBytes.Add(int64(n))
+ if !s.isClient && s.uploadBytes != nil {
+ s.uploadBytes.Add(int64(n))
}
return n, nil
}
@@ -245,8 +245,8 @@ func (s *Session) Read(b []byte) (n int, err error) {
if log.IsLevelEnabled(log.TraceLevel) {
log.Tracef("%v read %d bytes", s, n)
}
- if s.readBytes != nil {
- s.readBytes.Add(int64(n))
+ if !s.isClient && s.uploadBytes != nil {
+ s.uploadBytes.Add(int64(n))
}
return n, nil
}
@@ -307,8 +307,8 @@ func (s *Session) Write(b []byte) (n int, err error) {
if log.IsLevelEnabled(log.TraceLevel) {
log.Tracef("%v wrote %d bytes", s, n)
}
- if s.writeBytes != nil {
- s.writeBytes.Add(int64(n))
+ if !s.isClient && s.downloadBytes != nil {
+ s.downloadBytes.Add(int64(n))
}
return n, nil
}
@@ -724,11 +724,13 @@ func (s *Session) input(seg *segment) error {
}
if seg.block != nil {
s.block = seg.block
- if s.readBytes == nil && s.block.BlockContext().UserName != "" {
- s.readBytes = metrics.RegisterMetric(fmt.Sprintf(metrics.UserMetricGroupFormat, s.block.BlockContext().UserName), metrics.UserMetricReadBytes, metrics.COUNTER_TIME_SERIES)
- }
- if s.writeBytes == nil && s.block.BlockContext().UserName != "" {
- s.writeBytes = metrics.RegisterMetric(fmt.Sprintf(metrics.UserMetricGroupFormat, s.block.BlockContext().UserName), metrics.UserMetricWriteBytes, metrics.COUNTER_TIME_SERIES)
+ if !s.isClient {
+ if s.uploadBytes == nil && s.block.BlockContext().UserName != "" {
+ s.uploadBytes = metrics.RegisterMetric(fmt.Sprintf(metrics.UserMetricGroupFormat, s.block.BlockContext().UserName), metrics.UserMetricUploadBytes, metrics.COUNTER_TIME_SERIES)
+ }
+ if s.downloadBytes == nil && s.block.BlockContext().UserName != "" {
+ s.downloadBytes = metrics.RegisterMetric(fmt.Sprintf(metrics.UserMetricGroupFormat, s.block.BlockContext().UserName), metrics.UserMetricDownloadBytes, metrics.COUNTER_TIME_SERIES)
+ }
}
}
s.lastRXTime = time.Now()
@@ -958,19 +960,19 @@ func (s *Session) checkQuota(userName string) (ok bool, err error) {
if metricGroup == nil {
return true, fmt.Errorf("metric group %s is not found", metricGroupName)
}
- readBytes, found := metricGroup.GetMetric(metrics.UserMetricReadBytes)
+ uploadBytes, found := metricGroup.GetMetric(metrics.UserMetricUploadBytes)
if !found {
- return true, fmt.Errorf("metric %s in group %s is not found", metrics.UserMetricReadBytes, metricGroupName)
+ return true, fmt.Errorf("metric %s in group %s is not found", metrics.UserMetricUploadBytes, metricGroupName)
}
- writeBytes, found := metricGroup.GetMetric(metrics.UserMetricWriteBytes)
+ downloadBytes, found := metricGroup.GetMetric(metrics.UserMetricDownloadBytes)
if !found {
- return true, fmt.Errorf("metric %s in group %s is not found", metrics.UserMetricWriteBytes, metricGroupName)
+ return true, fmt.Errorf("metric %s in group %s is not found", metrics.UserMetricDownloadBytes, metricGroupName)
}
for _, quota := range user.GetQuotas() {
now := time.Now()
then := now.Add(-time.Duration(quota.GetDays()) * 24 * time.Hour)
- totalBytes := readBytes.(*metrics.Counter).DeltaBetween(then, now)
- totalBytes += writeBytes.(*metrics.Counter).DeltaBetween(then, now)
+ totalBytes := uploadBytes.(*metrics.Counter).DeltaBetween(then, now)
+ totalBytes += downloadBytes.(*metrics.Counter).DeltaBetween(then, now)
if totalBytes/1048576 > int64(quota.GetMegabytes()) {
return false, nil
}
diff --git a/mieru/pkg/protocolv2/underlay_tcp.go b/mieru/pkg/protocolv2/underlay_tcp.go
index 36764640af..3e5cc3886b 100644
--- a/mieru/pkg/protocolv2/underlay_tcp.go
+++ b/mieru/pkg/protocolv2/underlay_tcp.go
@@ -303,7 +303,11 @@ func (t *TCPUnderlay) readOneSegment() (*segment, error, stderror.ErrorType) {
if _, err := io.ReadFull(t.conn, encryptedMeta); err != nil {
return nil, fmt.Errorf("metadata: read %d bytes from TCPUnderlay failed: %w", readLen, err), stderror.NETWORK_ERROR
}
- metrics.InBytes.Add(int64(len(encryptedMeta)))
+ if t.isClient {
+ metrics.DownloadBytes.Add(int64(len(encryptedMeta)))
+ } else {
+ metrics.UploadBytes.Add(int64(len(encryptedMeta)))
+ }
if tcpReplayCache.IsDuplicate(encryptedMeta[:cipher.DefaultOverhead], replay.EmptyTag) {
if firstRead {
replay.NewSession.Add(1)
@@ -374,7 +378,11 @@ func (t *TCPUnderlay) readSessionSegment(ss *sessionStruct) (*segment, error, st
if _, err := io.ReadFull(t.conn, encryptedPayload); err != nil {
return nil, fmt.Errorf("payload: read %d bytes from TCPUnderlay failed: %w", ss.payloadLen+cipher.DefaultOverhead, err), stderror.NETWORK_ERROR
}
- metrics.InBytes.Add(int64(len(encryptedPayload)))
+ if t.isClient {
+ metrics.DownloadBytes.Add(int64(len(encryptedPayload)))
+ } else {
+ metrics.UploadBytes.Add(int64(len(encryptedPayload)))
+ }
if tcpReplayCache.IsDuplicate(encryptedPayload[:cipher.DefaultOverhead], replay.EmptyTag) {
replay.KnownSession.Add(1)
}
@@ -398,7 +406,11 @@ func (t *TCPUnderlay) readSessionSegment(ss *sessionStruct) (*segment, error, st
if _, err := io.ReadFull(t.conn, padding); err != nil {
return nil, fmt.Errorf("padding: read %d bytes from TCPUnderlay failed: %w", ss.suffixLen, err), stderror.NETWORK_ERROR
}
- metrics.InBytes.Add(int64(len(padding)))
+ if t.isClient {
+ metrics.DownloadBytes.Add(int64(len(padding)))
+ } else {
+ metrics.UploadBytes.Add(int64(len(padding)))
+ }
}
return &segment{
@@ -418,14 +430,22 @@ func (t *TCPUnderlay) readDataAckSegment(das *dataAckStruct) (*segment, error, s
if _, err := io.ReadFull(t.conn, padding1); err != nil {
return nil, fmt.Errorf("padding: read %d bytes from TCPUnderlay failed: %w", das.prefixLen, err), stderror.NETWORK_ERROR
}
- metrics.InBytes.Add(int64(len(padding1)))
+ if t.isClient {
+ metrics.DownloadBytes.Add(int64(len(padding1)))
+ } else {
+ metrics.UploadBytes.Add(int64(len(padding1)))
+ }
}
if das.payloadLen > 0 {
encryptedPayload := make([]byte, das.payloadLen+cipher.DefaultOverhead)
if _, err := io.ReadFull(t.conn, encryptedPayload); err != nil {
return nil, fmt.Errorf("payload: read %d bytes from TCPUnderlay failed: %w", das.payloadLen+cipher.DefaultOverhead, err), stderror.NETWORK_ERROR
}
- metrics.InBytes.Add(int64(len(encryptedPayload)))
+ if t.isClient {
+ metrics.DownloadBytes.Add(int64(len(encryptedPayload)))
+ } else {
+ metrics.UploadBytes.Add(int64(len(encryptedPayload)))
+ }
if tcpReplayCache.IsDuplicate(encryptedPayload[:cipher.DefaultOverhead], replay.EmptyTag) {
replay.KnownSession.Add(1)
}
@@ -449,7 +469,11 @@ func (t *TCPUnderlay) readDataAckSegment(das *dataAckStruct) (*segment, error, s
if _, err := io.ReadFull(t.conn, padding2); err != nil {
return nil, fmt.Errorf("padding: read %d bytes from TCPUnderlay failed: %w", das.suffixLen, err), stderror.NETWORK_ERROR
}
- metrics.InBytes.Add(int64(len(padding2)))
+ if t.isClient {
+ metrics.DownloadBytes.Add(int64(len(padding2)))
+ } else {
+ metrics.UploadBytes.Add(int64(len(padding2)))
+ }
}
return &segment{
@@ -499,8 +523,12 @@ func (t *TCPUnderlay) writeOneSegment(seg *segment) error {
if _, err := t.conn.Write(dataToSend); err != nil {
return fmt.Errorf("Write() failed: %w", err)
}
- metrics.OutBytes.Add(int64(len(dataToSend)))
- metrics.OutPaddingBytes.Add(int64(len(padding)))
+ if t.isClient {
+ metrics.UploadBytes.Add(int64(len(dataToSend)))
+ } else {
+ metrics.DownloadBytes.Add(int64(len(dataToSend)))
+ }
+ metrics.OutputPaddingBytes.Add(int64(len(padding)))
} else if das, ok := toDataAckStruct(seg.metadata); ok {
padding1 := newPadding(paddingOpts{
maxLen: MaxPaddingSize(t.mtu, t.IPVersion(), t.TransportProtocol(), int(das.payloadLen), 0),
@@ -534,9 +562,13 @@ func (t *TCPUnderlay) writeOneSegment(seg *segment) error {
if _, err := t.conn.Write(dataToSend); err != nil {
return fmt.Errorf("Write() failed: %w", err)
}
- metrics.OutBytes.Add(int64(len(dataToSend)))
- metrics.OutPaddingBytes.Add(int64(len(padding1)))
- metrics.OutPaddingBytes.Add(int64(len(padding2)))
+ if t.isClient {
+ metrics.UploadBytes.Add(int64(len(dataToSend)))
+ } else {
+ metrics.DownloadBytes.Add(int64(len(dataToSend)))
+ }
+ metrics.OutputPaddingBytes.Add(int64(len(padding1)))
+ metrics.OutputPaddingBytes.Add(int64(len(padding2)))
} else {
return stderror.ErrInvalidArgument
}
diff --git a/mieru/pkg/protocolv2/underlay_udp.go b/mieru/pkg/protocolv2/underlay_udp.go
index 1fe7b13697..6342a9c49d 100644
--- a/mieru/pkg/protocolv2/underlay_udp.go
+++ b/mieru/pkg/protocolv2/underlay_udp.go
@@ -365,7 +365,11 @@ func (u *UDPUnderlay) readOneSegment() (*segment, *net.UDPAddr, error) {
continue
}
b = b[:n]
- metrics.InBytes.Add(int64(n))
+ if u.isClient {
+ metrics.DownloadBytes.Add(int64(n))
+ } else {
+ metrics.UploadBytes.Add(int64(n))
+ }
// Read encrypted metadata.
encryptedMeta := b[:udpNonHeaderPosition]
@@ -662,8 +666,12 @@ func (u *UDPUnderlay) writeOneSegment(seg *segment, addr *net.UDPAddr) error {
if _, err := u.conn.WriteToUDP(dataToSend, addr); err != nil {
return fmt.Errorf("WriteToUDP() failed: %w", err)
}
- metrics.OutBytes.Add(int64(len(dataToSend)))
- metrics.OutPaddingBytes.Add(int64(len(padding)))
+ if u.isClient {
+ metrics.UploadBytes.Add(int64(len(dataToSend)))
+ } else {
+ metrics.DownloadBytes.Add(int64(len(dataToSend)))
+ }
+ metrics.OutputPaddingBytes.Add(int64(len(padding)))
} else if das, ok := toDataAckStruct(seg.metadata); ok {
padding1 := newPadding(paddingOpts{
maxLen: MaxPaddingSize(u.mtu, u.IPVersion(), u.TransportProtocol(), int(das.payloadLen), 0),
@@ -695,9 +703,13 @@ func (u *UDPUnderlay) writeOneSegment(seg *segment, addr *net.UDPAddr) error {
if _, err := u.conn.WriteToUDP(dataToSend, addr); err != nil {
return fmt.Errorf("WriteToUDP() failed: %w", err)
}
- metrics.OutBytes.Add(int64(len(dataToSend)))
- metrics.OutPaddingBytes.Add(int64(len(padding1)))
- metrics.OutPaddingBytes.Add(int64(len(padding2)))
+ if u.isClient {
+ metrics.UploadBytes.Add(int64(len(dataToSend)))
+ } else {
+ metrics.DownloadBytes.Add(int64(len(dataToSend)))
+ }
+ metrics.OutputPaddingBytes.Add(int64(len(padding1)))
+ metrics.OutputPaddingBytes.Add(int64(len(padding2)))
} else {
return stderror.ErrInvalidArgument
}
diff --git a/mieru/pkg/socks5/copy.go b/mieru/pkg/socks5/copy.go
index 90aeb7969a..69b0d3e052 100644
--- a/mieru/pkg/socks5/copy.go
+++ b/mieru/pkg/socks5/copy.go
@@ -40,8 +40,8 @@ func BidiCopyUDP(udpConn *net.UDPConn, tunnelConn *UDPAssociateTunnelConn) error
errCh <- fmt.Errorf("ReadFrom UDP connection failed: %w", err)
break
}
- UDPAssociateInPkts.Add(1)
- UDPAssociateInBytes.Add(int64(n))
+ UDPAssociateUploadPackets.Add(1)
+ UDPAssociateUploadBytes.Add(int64(n))
udpAddr := addr.Load()
if udpAddr == nil {
addr.Store(a)
@@ -74,8 +74,8 @@ func BidiCopyUDP(udpConn *net.UDPConn, tunnelConn *UDPAssociateTunnelConn) error
errCh <- fmt.Errorf("WriteTo UDP connetion failed: %w", err)
break
}
- UDPAssociateOutPkts.Add(1)
- UDPAssociateOutBytes.Add(int64(ws))
+ UDPAssociateDownloadPackets.Add(1)
+ UDPAssociateDownloadBytes.Add(int64(ws))
}
}()
diff --git a/mieru/pkg/socks5/request.go b/mieru/pkg/socks5/request.go
index ce70fb2ef4..bdfc1dc481 100644
--- a/mieru/pkg/socks5/request.go
+++ b/mieru/pkg/socks5/request.go
@@ -290,8 +290,8 @@ func (s *Server) handleAssociate(ctx context.Context, req *Request, conn io.Read
log.Debugf("UDP associate [%v - %v] WriteToUDP() failed: %v", udpConn.LocalAddr(), dstAddr, err)
UDPAssociateErrors.Add(1)
} else {
- UDPAssociateInPkts.Add(1)
- UDPAssociateInBytes.Add(int64(ws))
+ UDPAssociateUploadPackets.Add(1)
+ UDPAssociateUploadBytes.Add(int64(ws))
}
case 0x03:
fqdnLen := buf[4]
@@ -308,8 +308,8 @@ func (s *Server) handleAssociate(ctx context.Context, req *Request, conn io.Read
log.Debugf("UDP associate [%v - %v] WriteToUDP() failed: %v", udpConn.LocalAddr(), dstAddr, err)
UDPAssociateErrors.Add(1)
} else {
- UDPAssociateInPkts.Add(1)
- UDPAssociateInBytes.Add(int64(ws))
+ UDPAssociateUploadPackets.Add(1)
+ UDPAssociateUploadBytes.Add(int64(ws))
}
case 0x04:
dstAddr := &net.UDPAddr{
@@ -322,8 +322,8 @@ func (s *Server) handleAssociate(ctx context.Context, req *Request, conn io.Read
log.Debugf("UDP associate [%v - %v] WriteToUDP() failed: %v", udpConn.LocalAddr(), dstAddr, err)
UDPAssociateErrors.Add(1)
} else {
- UDPAssociateInPkts.Add(1)
- UDPAssociateInBytes.Add(int64(ws))
+ UDPAssociateUploadPackets.Add(1)
+ UDPAssociateUploadBytes.Add(int64(ws))
}
}
}
@@ -365,8 +365,8 @@ func (s *Server) handleAssociate(ctx context.Context, req *Request, conn io.Read
}
return
}
- UDPAssociateOutPkts.Add(1)
- UDPAssociateOutBytes.Add(int64(n))
+ UDPAssociateDownloadPackets.Add(1)
+ UDPAssociateDownloadBytes.Add(int64(n))
}
}()
diff --git a/mieru/pkg/socks5/socks5.go b/mieru/pkg/socks5/socks5.go
index f410b235f9..ad380d893b 100644
--- a/mieru/pkg/socks5/socks5.go
+++ b/mieru/pkg/socks5/socks5.go
@@ -35,10 +35,10 @@ var (
ConnectionRefusedErrors = metrics.RegisterMetric("socks5", "ConnectionRefusedErrors", metrics.COUNTER)
UDPAssociateErrors = metrics.RegisterMetric("socks5", "UDPAssociateErrors", metrics.COUNTER)
- UDPAssociateInBytes = metrics.RegisterMetric("socks5 UDP associate", "InBytes", metrics.COUNTER)
- UDPAssociateOutBytes = metrics.RegisterMetric("socks5 UDP associate", "OutBytes", metrics.COUNTER)
- UDPAssociateInPkts = metrics.RegisterMetric("socks5 UDP associate", "InPkts", metrics.COUNTER)
- UDPAssociateOutPkts = metrics.RegisterMetric("socks5 UDP associate", "OutPkts", metrics.COUNTER)
+ UDPAssociateUploadBytes = metrics.RegisterMetric("socks5 UDP associate", "UploadBytes", metrics.COUNTER)
+ UDPAssociateDownloadBytes = metrics.RegisterMetric("socks5 UDP associate", "DownloadBytes", metrics.COUNTER)
+ UDPAssociateUploadPackets = metrics.RegisterMetric("socks5 UDP associate", "UploadPackets", metrics.COUNTER)
+ UDPAssociateDownloadPackets = metrics.RegisterMetric("socks5 UDP associate", "DownloadPackets", metrics.COUNTER)
)
// Config is used to setup and configure a socks5 server.
diff --git a/mieru/pkg/socks5/socks5_test.go b/mieru/pkg/socks5/socks5_test.go
index 7d105376df..2945dd31ba 100644
--- a/mieru/pkg/socks5/socks5_test.go
+++ b/mieru/pkg/socks5/socks5_test.go
@@ -109,8 +109,8 @@ func TestSocks5Connect(t *testing.T) {
}
func TestSocks5UDPAssociation(t *testing.T) {
- udpInPktsCnt := UDPAssociateInPkts.Load()
- udpOutPktsCnt := UDPAssociateOutPkts.Load()
+ udpUploadPktsCnt := UDPAssociateUploadPackets.Load()
+ udpDownloadPktsCnt := UDPAssociateDownloadPackets.Load()
// Create a local listener as the destination target.
udpListenerAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
@@ -235,10 +235,10 @@ func TestSocks5UDPAssociation(t *testing.T) {
}
// Verify metrics are updated.
- if UDPAssociateInPkts.Load() <= udpInPktsCnt {
- t.Errorf("UDPAssociateInPkts value %d is not increased", UDPAssociateInPkts.Load())
+ if UDPAssociateUploadPackets.Load() <= udpUploadPktsCnt {
+ t.Errorf("UDPAssociateUploadPackets value %d is not increased", UDPAssociateUploadPackets.Load())
}
- if UDPAssociateOutPkts.Load() <= udpOutPktsCnt {
- t.Errorf("UDPAssociateOutPkts value %d is not increased", UDPAssociateOutPkts.Load())
+ if UDPAssociateDownloadPackets.Load() <= udpDownloadPktsCnt {
+ t.Errorf("UDPAssociateDownloadPackets value %d is not increased", UDPAssociateDownloadPackets.Load())
}
}
diff --git a/openwrt-packages/quickstart/Makefile b/openwrt-packages/quickstart/Makefile
index af5efe3228..cb6937079b 100644
--- a/openwrt-packages/quickstart/Makefile
+++ b/openwrt-packages/quickstart/Makefile
@@ -10,11 +10,11 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_quickstart:=$(ARCH)
PKG_NAME:=quickstart
-PKG_VERSION:=0.8.13
+PKG_VERSION:=0.8.14
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
-PKG_HASH:=2b1974b75f43bb01d25fb9a7d21695c9e0f5a80297fdcfc51215cc4f6cbfe985
+PKG_HASH:=287d60f90d7df57e325dee417166bf5eb6e05cf6089fd3ef6e1111f2fe896cf6
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_VERSION)
diff --git a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua
index b579b40b44..860f909266 100644
--- a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -767,8 +767,8 @@ function gen_config(var)
end
if node.protocol == "_shunt" then
- local proxy_node_id = node["main_node"]
- local proxy_tag = "main"
+ local proxy_tag = node.preproxy_enabled == "1" and "main" or nil
+ local proxy_node_id = proxy_tag and node["main_node"] or nil
local proxy_balancer_tag
local proxy_nodes
@@ -862,7 +862,6 @@ function gen_config(var)
end
return outbound_tag, nil
elseif _node.protocol == "_balancing" then
-
return nil, gen_balancer(_node, rule_name)
elseif _node.protocol == "_iface" then
if _node.iface then
@@ -884,7 +883,7 @@ function gen_config(var)
end
--proxy_node
- if node.preproxy_enabled == "1" and proxy_node_id then
+ if proxy_tag and proxy_node_id then
local proxy_outbound_tag
proxy_outbound_tag, proxy_balancer_tag = gen_shunt_node(proxy_tag, proxy_node_id)
if proxy_balancer_tag then
diff --git a/sing-box/docs/changelog.md b/sing-box/docs/changelog.md
index 86f4547170..1171d65270 100644
--- a/sing-box/docs/changelog.md
+++ b/sing-box/docs/changelog.md
@@ -2,6 +2,10 @@
icon: material/alert-decagram
---
+#### 1.9.0-rc.17
+
+* Fixes and improvements
+
#### 1.9.0-rc.16
* Mitigating TunnelVision attacks **1**
diff --git a/sing-box/go.mod b/sing-box/go.mod
index 3488255543..65ce0c2ad7 100644
--- a/sing-box/go.mod
+++ b/sing-box/go.mod
@@ -33,7 +33,7 @@ require (
github.com/sagernet/sing-shadowsocks v0.2.6
github.com/sagernet/sing-shadowsocks2 v0.2.0
github.com/sagernet/sing-shadowtls v0.1.4
- github.com/sagernet/sing-tun v0.3.0-beta.1
+ github.com/sagernet/sing-tun v0.3.0-beta.2
github.com/sagernet/sing-vmess v0.1.8
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6
diff --git a/sing-box/go.sum b/sing-box/go.sum
index c6bf82451f..5e8d5118a3 100644
--- a/sing-box/go.sum
+++ b/sing-box/go.sum
@@ -120,8 +120,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
-github.com/sagernet/sing-tun v0.3.0-beta.1 h1:OdVK+/hoD6qWHy/SUwpwqFR+IScI3FIQvBDLR05xWSk=
-github.com/sagernet/sing-tun v0.3.0-beta.1/go.mod h1:xPaOkQhngPMILx+/9DMLCFl4vSxUU2tMnCPSlf05HLo=
+github.com/sagernet/sing-tun v0.3.0-beta.2 h1:sfeHWnBTKGpFUjXpT+O/JEwFP8oVAo3M0Xx94ghesjU=
+github.com/sagernet/sing-tun v0.3.0-beta.2/go.mod h1:xPaOkQhngPMILx+/9DMLCFl4vSxUU2tMnCPSlf05HLo=
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
diff --git a/sing-box/outbound/urltest.go b/sing-box/outbound/urltest.go
index f6366c05b7..aa7cff6c5e 100644
--- a/sing-box/outbound/urltest.go
+++ b/sing-box/outbound/urltest.go
@@ -287,8 +287,23 @@ func (g *URLTestGroup) Close() error {
func (g *URLTestGroup) Select(network string) (adapter.Outbound, bool) {
var minDelay uint16
- var minTime time.Time
var minOutbound adapter.Outbound
+ switch network {
+ case N.NetworkTCP:
+ if g.selectedOutboundTCP != nil {
+ if history := g.history.LoadURLTestHistory(RealTag(g.selectedOutboundTCP)); history != nil {
+ minOutbound = g.selectedOutboundTCP
+ minDelay = history.Delay
+ }
+ }
+ case N.NetworkUDP:
+ if g.selectedOutboundUDP != nil {
+ if history := g.history.LoadURLTestHistory(RealTag(g.selectedOutboundUDP)); history != nil {
+ minOutbound = g.selectedOutboundUDP
+ minDelay = history.Delay
+ }
+ }
+ }
for _, detour := range g.outbounds {
if !common.Contains(detour.Network(), network) {
continue
@@ -297,9 +312,8 @@ func (g *URLTestGroup) Select(network string) (adapter.Outbound, bool) {
if history == nil {
continue
}
- if minDelay == 0 || minDelay > history.Delay+g.tolerance || minDelay > history.Delay-g.tolerance && minTime.Before(history.Time) {
+ if minDelay == 0 || minDelay > history.Delay+g.tolerance {
minDelay = history.Delay
- minTime = history.Time
minOutbound = detour
}
}
diff --git a/sing-box/route/rule_dns.go b/sing-box/route/rule_dns.go
index 85ded9615d..7501349fec 100644
--- a/sing-box/route/rule_dns.go
+++ b/sing-box/route/rule_dns.go
@@ -284,6 +284,7 @@ func NewLogicalDNSRule(router adapter.Router, logger log.ContextLogger, options
},
disableCache: options.DisableCache,
rewriteTTL: options.RewriteTTL,
+ clientSubnet: (*netip.Addr)(options.ClientSubnet),
}
switch options.Mode {
case C.LogicalTypeAnd:
diff --git a/small/brook/Makefile b/small/brook/Makefile
index fbb5b287ce..b46182e9f7 100644
--- a/small/brook/Makefile
+++ b/small/brook/Makefile
@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=brook
-PKG_VERSION:=20240404
+PKG_VERSION:=20240606
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/txthinking/brook/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=6eda9a348f9c3555a1c27711e81c0982ea9999bf2878e73cf2eaaee90e8cc2e7
+PKG_HASH:=eee1c6173daff3199c23396f4661d7f81d701dc0f4eb1662b39041a6ca10703b
PKG_MAINTAINER:=Tianling Shen
PKG_LICENSE:=GPL-3.0
diff --git a/small/luci-app-passwall/luasrc/passwall/util_xray.lua b/small/luci-app-passwall/luasrc/passwall/util_xray.lua
index b579b40b44..860f909266 100644
--- a/small/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/small/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -767,8 +767,8 @@ function gen_config(var)
end
if node.protocol == "_shunt" then
- local proxy_node_id = node["main_node"]
- local proxy_tag = "main"
+ local proxy_tag = node.preproxy_enabled == "1" and "main" or nil
+ local proxy_node_id = proxy_tag and node["main_node"] or nil
local proxy_balancer_tag
local proxy_nodes
@@ -862,7 +862,6 @@ function gen_config(var)
end
return outbound_tag, nil
elseif _node.protocol == "_balancing" then
-
return nil, gen_balancer(_node, rule_name)
elseif _node.protocol == "_iface" then
if _node.iface then
@@ -884,7 +883,7 @@ function gen_config(var)
end
--proxy_node
- if node.preproxy_enabled == "1" and proxy_node_id then
+ if proxy_tag and proxy_node_id then
local proxy_outbound_tag
proxy_outbound_tag, proxy_balancer_tag = gen_shunt_node(proxy_tag, proxy_node_id)
if proxy_balancer_tag then
diff --git a/yass/.github/workflows/clang-tidy.yml b/yass/.github/workflows/clang-tidy.yml
index ca96bcaba9..d259d387ee 100644
--- a/yass/.github/workflows/clang-tidy.yml
+++ b/yass/.github/workflows/clang-tidy.yml
@@ -18,7 +18,7 @@ on:
schedule:
- cron: '0 16 * * *'
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
win-clang-tidy:
diff --git a/yass/.github/workflows/compiler.yml b/yass/.github/workflows/compiler.yml
index d1358b3027..1141cf2092 100644
--- a/yass/.github/workflows/compiler.yml
+++ b/yass/.github/workflows/compiler.yml
@@ -33,7 +33,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
win-compiler-compatible-2022:
diff --git a/yass/.github/workflows/releases-android-binary.yml b/yass/.github/workflows/releases-android-binary.yml
index 2364e55890..eb2a9bfaa9 100644
--- a/yass/.github/workflows/releases-android-binary.yml
+++ b/yass/.github/workflows/releases-android-binary.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
android-binary-release:
@@ -131,6 +131,10 @@ jobs:
run: |
cd tools
go build
+ - name: Replace Android NDK (to latest)
+ run: |
+ echo "ANDROID_NDK_ROOT=${ANDROID_NDK_LATEST_HOME}" >> $GITHUB_ENV
+ echo "ANDROID_NDK_HOME=${ANDROID_NDK_LATEST_HOME}" >> $GITHUB_ENV
- name: "Install dependency: tun2proxy"
run: |
./scripts/setup-android-rust.sh
diff --git a/yass/.github/workflows/releases-deb.yml b/yass/.github/workflows/releases-deb.yml
index b81672d0d4..414f2c8cf3 100644
--- a/yass/.github/workflows/releases-deb.yml
+++ b/yass/.github/workflows/releases-deb.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
DH_QUIET: 1
jobs:
diff --git a/yass/.github/workflows/releases-freebsd-binary.yml b/yass/.github/workflows/releases-freebsd-binary.yml
index eab7117f4d..30827c2076 100644
--- a/yass/.github/workflows/releases-freebsd-binary.yml
+++ b/yass/.github/workflows/releases-freebsd-binary.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
freebsd-binary-release:
diff --git a/yass/.github/workflows/releases-ios.yml b/yass/.github/workflows/releases-ios.yml
index 3a462e2fb8..763c58c078 100644
--- a/yass/.github/workflows/releases-ios.yml
+++ b/yass/.github/workflows/releases-ios.yml
@@ -21,7 +21,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
ios-simulator-release:
diff --git a/yass/.github/workflows/releases-linux-binary.yml b/yass/.github/workflows/releases-linux-binary.yml
index b7029f8573..c5afe3fd66 100644
--- a/yass/.github/workflows/releases-linux-binary.yml
+++ b/yass/.github/workflows/releases-linux-binary.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
linux-binary-release:
diff --git a/yass/.github/workflows/releases-macos.yml b/yass/.github/workflows/releases-macos.yml
index 1806a052ec..c99b220b71 100644
--- a/yass/.github/workflows/releases-macos.yml
+++ b/yass/.github/workflows/releases-macos.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
mac-release:
diff --git a/yass/.github/workflows/releases-mingw-new.yml b/yass/.github/workflows/releases-mingw-new.yml
index 13301d5e13..10a9af28d6 100644
--- a/yass/.github/workflows/releases-mingw-new.yml
+++ b/yass/.github/workflows/releases-mingw-new.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
mingw64-release:
diff --git a/yass/.github/workflows/releases-mingw.yml b/yass/.github/workflows/releases-mingw.yml
index 3c5f73b19b..18ebf8a947 100644
--- a/yass/.github/workflows/releases-mingw.yml
+++ b/yass/.github/workflows/releases-mingw.yml
@@ -18,7 +18,7 @@ on:
schedule:
- cron: '0 16 * * *'
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
mingw64-release:
diff --git a/yass/.github/workflows/releases-openwrt-binary.yml b/yass/.github/workflows/releases-openwrt-binary.yml
index a4fe0f319b..9b4a58902a 100644
--- a/yass/.github/workflows/releases-openwrt-binary.yml
+++ b/yass/.github/workflows/releases-openwrt-binary.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
openwrt-binary-release:
diff --git a/yass/.github/workflows/releases-rpm.yml b/yass/.github/workflows/releases-rpm.yml
index e7b07836e0..d6c666af5b 100644
--- a/yass/.github/workflows/releases-rpm.yml
+++ b/yass/.github/workflows/releases-rpm.yml
@@ -35,7 +35,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
docker_publish:
diff --git a/yass/.github/workflows/releases-windows.yml b/yass/.github/workflows/releases-windows.yml
index f259223fbe..6aa628aa94 100644
--- a/yass/.github/workflows/releases-windows.yml
+++ b/yass/.github/workflows/releases-windows.yml
@@ -24,7 +24,7 @@ defaults:
run:
shell: cmd
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
windows-release:
diff --git a/yass/.github/workflows/sanitizers.yml b/yass/.github/workflows/sanitizers.yml
index e0b0f98ce9..91972d9dc7 100644
--- a/yass/.github/workflows/sanitizers.yml
+++ b/yass/.github/workflows/sanitizers.yml
@@ -18,7 +18,7 @@ on:
schedule:
- cron: '0 16 * * *'
env:
- CACHE_EPOCH: 125-2
+ CACHE_EPOCH: 126-1
GOPROXY: direct
jobs:
sanitizer-linux:
diff --git a/yass/CLANG_REVISION b/yass/CLANG_REVISION
index 34fa27ec62..cb74c04925 100644
--- a/yass/CLANG_REVISION
+++ b/yass/CLANG_REVISION
@@ -1 +1 @@
-llvmorg-19-init-8091-gab037c4f-1
\ No newline at end of file
+llvmorg-19-init-9433-g76ea5feb-1
\ No newline at end of file
diff --git a/yass/CRASHPAD_COMMIT b/yass/CRASHPAD_COMMIT
index c1bdd7f8b6..2606a02c52 100644
--- a/yass/CRASHPAD_COMMIT
+++ b/yass/CRASHPAD_COMMIT
@@ -1 +1 @@
-1cea0473a5a1f3124f0d3a95643c573296a2bac5
\ No newline at end of file
+dc489055ed8ecb1eb3fb8e22a7a4c5c4d9b1459e
\ No newline at end of file
diff --git a/yass/scripts/mini_chromium.BUILD.gn b/yass/scripts/mini_chromium.BUILD.gn
index 9f615a286c..6c5c4e9360 100644
--- a/yass/scripts/mini_chromium.BUILD.gn
+++ b/yass/scripts/mini_chromium.BUILD.gn
@@ -171,7 +171,7 @@ config("default") {
]
cflags_c = [ "-std=c11" ]
- cflags_cc = [ "-std=c++17" ]
+ cflags_cc = [ "-std=c++20" ]
cflags_objc = cflags_c
cflags_objcc = cflags_cc
@@ -274,7 +274,7 @@ config("default") {
]
cflags_cc = [
- "/std:c++17",
+ "/std:c++20",
"/Zc:__cplusplus",
]
diff --git a/yass/scripts/setup-android-rust.sh b/yass/scripts/setup-android-rust.sh
index c1be307cfb..4aa8b2a76a 100755
--- a/yass/scripts/setup-android-rust.sh
+++ b/yass/scripts/setup-android-rust.sh
@@ -26,13 +26,13 @@ rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-andro
echo "Adding rustup android target...done"
mkdir -p ~/.cargo
-HAS_CARGO_ANDROID="$(grep target.aarch64-linux-android ~/.cargo/config || :)"
+HAS_CARGO_ANDROID="$(grep target.aarch64-linux-android ~/.cargo/config.toml || :)"
if [ ! -z "$HAS_CARGO_ANDROID" ]; then
- echo "Skip patching cargo config..."
+ echo "Skip patching cargo config.toml ..."
exit 0
fi
-echo "Patching cargo config..."
+echo "Patching cargo config.toml ..."
ARCH=$(uname -s)
case "$ARCH" in
@@ -51,7 +51,7 @@ case "$ARCH" in
;;
esac
-cat >> ~/.cargo/config << EOF
+cat >> ~/.cargo/config.toml << EOF
[target.aarch64-linux-android]
ar = "$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/${HOST_OS}-x86_64/bin/llvm-ar"
@@ -70,4 +70,4 @@ ar = "$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/${HOST_OS}-x86_64/bin/llvm-ar"
linker = "$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/${HOST_OS}-x86_64/bin/x86_64-linux-android24-clang"
EOF
-echo "Patching cargo config...done"
+echo "Patching cargo config.toml ...done"
diff --git a/yass/scripts/setup-harmony-rust.sh b/yass/scripts/setup-harmony-rust.sh
index 8060d69d83..b0bc979f49 100755
--- a/yass/scripts/setup-harmony-rust.sh
+++ b/yass/scripts/setup-harmony-rust.sh
@@ -24,15 +24,15 @@ fi
echo "Adding rustup toolchain...done"
mkdir -p ~/.cargo
-HAS_CARGO_HARMONY="$(grep target.aarch64-unknown-linux-ohos ~/.cargo/config || :)"
+HAS_CARGO_HARMONY="$(grep target.aarch64-unknown-linux-ohos ~/.cargo/config.toml || :)"
if [ ! -z "$HAS_CARGO_HARMONY" ]; then
- echo "Skip patching cargo config..."
+ echo "Skip patching cargo config.toml ..."
exit 0
fi
-echo "Patching cargo config..."
+echo "Patching cargo config.toml ..."
-cat >> ~/.cargo/config << EOF
+cat >> ~/.cargo/config.toml << EOF
[target.aarch64-unknown-linux-ohos]
ar = "$HARMONY_NDK_ROOT/native/llvm/bin/llvm-ar"
linker = "$PWD/scripts/aarch64-unknown-linux-ohos-clang.sh"
@@ -46,4 +46,4 @@ ar = "$HARMONY_NDK_ROOT/native/llvm/bin/llvm-ar"
linker = "$PWD/scripts/x86_64-unknown-linux-ohos-clang.sh"
EOF
-echo "Patching cargo config...done"
+echo "Patching cargo config.toml ...done"
diff --git a/yass/src/cli/cli_connection.cpp b/yass/src/cli/cli_connection.cpp
index 2b9c763083..3c3be13eae 100644
--- a/yass/src/cli/cli_connection.cpp
+++ b/yass/src/cli/cli_connection.cpp
@@ -13,6 +13,8 @@
#include "net/base64.hpp"
#include "net/http_parser.hpp"
#include "net/padding.hpp"
+#include "net/socks4_request_parser.hpp"
+#include "net/socks5_request_parser.hpp"
#include
@@ -629,9 +631,9 @@ asio::error_code CliConnection::OnReadRedirHandshake(std::shared_ptr buf)
asio::error_code CliConnection::OnReadSocks5MethodSelect(std::shared_ptr buf) {
scoped_refptr self(this);
+ socks5::method_select_request_parser parser;
socks5::method_select_request_parser::result_type result;
- std::tie(result, std::ignore) =
- method_select_request_parser_.parse(method_select_request_, buf->data(), buf->data() + buf->length());
+ std::tie(result, std::ignore) = parser.parse(method_select_request_, buf->data(), buf->data() + buf->length());
if (result == socks5::method_select_request_parser::good) {
DCHECK_LE(method_select_request_.length(), buf->length());
@@ -647,8 +649,9 @@ asio::error_code CliConnection::OnReadSocks5MethodSelect(std::shared_ptr
asio::error_code CliConnection::OnReadSocks5Handshake(std::shared_ptr buf) {
VLOG(2) << "Connection (client) " << connection_id() << " try socks5 handshake";
+ socks5::request_parser parser;
socks5::request_parser::result_type result;
- std::tie(result, std::ignore) = request_parser_.parse(s5_request_, buf->data(), buf->data() + buf->length());
+ std::tie(result, std::ignore) = parser.parse(s5_request_, buf->data(), buf->data() + buf->length());
if (result == socks5::request_parser::good) {
DCHECK_LE(s5_request_.length(), buf->length());
@@ -664,9 +667,9 @@ asio::error_code CliConnection::OnReadSocks5Handshake(std::shared_ptr buf
asio::error_code CliConnection::OnReadSocks4Handshake(std::shared_ptr buf) {
VLOG(2) << "Connection (client) " << connection_id() << " try socks4 handshake";
-
+ socks4::request_parser parser;
socks4::request_parser::result_type result;
- std::tie(result, std::ignore) = s4_request_parser_.parse(s4_request_, buf->data(), buf->data() + buf->length());
+ std::tie(result, std::ignore) = parser.parse(s4_request_, buf->data(), buf->data() + buf->length());
if (result == socks4::request_parser::good) {
DCHECK_LE(s4_request_.length(), buf->length());
buf->trimStart(s4_request_.length());
@@ -1036,196 +1039,26 @@ try_again:
#endif
if (upstream_https_fallback_) {
if (upstream_handshake_) {
- upstream_handshake_ = false;
- HttpResponseParser parser;
-
- bool ok;
- int nparsed = parser.Parse(buf, &ok);
-
- if (nparsed) {
- VLOG(3) << "Connection (client) " << connection_id()
- << " http: " << std::string(reinterpret_cast(buf->data()), nparsed);
- }
- if (ok && parser.status_code() == 200) {
- buf->trimStart(nparsed);
- buf->retreat(nparsed);
- if (buf->empty()) {
- ec = asio::error::try_again;
- return nullptr;
- }
- } else {
- if (!ok) {
- LOG(WARNING) << "Connection (client) " << connection_id()
- << " upstream server unhandled: " << parser.ErrorMessage() << ": "
- << std::string(reinterpret_cast(buf->data()), nparsed);
- } else {
- LOG(WARNING) << "Connection (client) " << connection_id()
- << " upstream server returns: " << parser.status_code();
- }
- ec = asio::error::connection_refused;
- disconnected(ec);
+ ReadUpstreamHttpsHandshake(buf, ec);
+ if (ec) {
return nullptr;
}
}
downstream_.push_back(buf);
} else {
- auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS5(method) && socks5_method_select_handshake_) {
- if (buf->length() < sizeof(socks5::method_select_response)) {
- ec = asio::error::connection_refused;
- disconnected(ec);
+ if (CIPHER_METHOD_IS_SOCKS5(method()) && socks5_method_select_handshake_) {
+ ReadUpstreamMethodSelectHandshake(buf, ec);
+ if (ec) {
return nullptr;
}
- socks5_method_select_handshake_ = false;
- auto response = reinterpret_cast(buf->data());
- if (response->ver != socks5::version && response->method != socks5::no_auth_required) {
- ec = asio::error::connection_refused;
- disconnected(ec);
+ }
+ if (CIPHER_METHOD_IS_SOCKS(method()) && socks_handshake_) {
+ ReadUpstreamSocksHandshake(buf, ec);
+ if (ec) {
return nullptr;
}
- VLOG(2) << "Connection (client) " << connection_id() << " socks5 method select response";
- buf->trimStart(sizeof(socks5::method_select_response));
-
- {
- socks5::request_header header;
- header.version = socks5::version;
- header.command = socks5::cmd_connect;
- header.null_byte = 0;
-
- ByteRange req(reinterpret_cast(&header), sizeof(header));
- std::shared_ptr buf = IOBuf::copyBuffer(req);
-
- absl::Span address;
- std::string domain_name;
-
- uint8_t address_type = socks5::ipv4;
- if (ss_request_->address_type() == ss::domain) {
- address_type = socks5::domain;
- domain_name = ss_request_->domain_name();
- address = absl::Span((uint8_t*)domain_name.c_str(), domain_name.size());
- } else if (ss_request_->address_type() == ss::ipv6) {
- address_type = socks5::ipv6;
- address = absl::Span((uint8_t*)&ss_request_->address6(), sizeof(ss_request_->address6()));
- } else {
- address_type = socks5::ipv4;
- address = absl::Span((uint8_t*)&ss_request_->address4(), sizeof(ss_request_->address4()));
- }
-
- buf->reserve(0, sizeof(address_type));
- memcpy(buf->mutable_tail(), &address_type, sizeof(address_type));
- buf->append(sizeof(address_type));
-
- if (ss_request_->address_type() == ss::domain) {
- uint8_t address_len = address.size();
- buf->reserve(0, sizeof(address_len));
- memcpy(buf->mutable_tail(), &address_len, sizeof(address_len));
- buf->append(sizeof(address_len));
- }
-
- buf->reserve(0, address.size());
- memcpy(buf->mutable_tail(), address.data(), address.size());
- buf->append(address.size());
-
- uint8_t port_high_byte = ss_request_->port_high_byte();
- uint8_t port_low_byte = ss_request_->port_low_byte();
-
- buf->reserve(0, sizeof(uint16_t));
- *buf->mutable_tail() = port_high_byte;
- buf->append(sizeof(port_high_byte));
- *buf->mutable_tail() = port_low_byte;
- buf->append(sizeof(port_low_byte));
- upstream_.replace_front(buf);
- WriteUpstreamInPipe();
- }
-
- if (buf->empty()) {
- ec = asio::error::try_again;
- goto out;
- }
}
- if (CIPHER_METHOD_IS_SOCKS(method) && socks_handshake_) {
- switch (method) {
- case CRYPTO_SOCKS4:
- case CRYPTO_SOCKS4A: {
- if (buf->length() < sizeof(socks4::reply_header)) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- socks_handshake_ = false;
- auto response = reinterpret_cast(buf->data());
- if (response->null_byte != 0 || response->status != socks4::reply::request_granted) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- VLOG(2) << "Connection (client) " << connection_id() << " socks4 handshake response";
- buf->trimStart(sizeof(socks4::reply_header));
- break;
- };
- case CRYPTO_SOCKS5:
- case CRYPTO_SOCKS5H: {
- if (buf->length() < sizeof(socks5::reply_header)) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- socks_handshake_ = false;
- auto response = reinterpret_cast(buf->data());
- if (response->version != socks5::version || response->status != socks5::reply::request_granted ||
- response->null_byte != 0) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- if (response->address_type == socks5::ipv4) {
- uint32_t expected_len =
- sizeof(socks5::reply_header) + sizeof(asio::ip::address_v4::bytes_type) + sizeof(uint16_t);
- if (buf->length() < expected_len) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- buf->trimStart(expected_len);
- } else if (response->address_type == socks5::ipv6) {
- uint32_t expected_len =
- sizeof(socks5::reply_header) + sizeof(asio::ip::address_v6::bytes_type) + sizeof(uint16_t);
- if (buf->length() < expected_len) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- buf->trimStart(expected_len);
- } else if (response->address_type == socks5::domain) {
- uint32_t expected_len = sizeof(socks5::reply_header) + sizeof(uint8_t) + sizeof(uint16_t);
- if (buf->length() < expected_len) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- expected_len += *reinterpret_cast(buf->data() + sizeof(*response));
- if (buf->length() < expected_len) {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- buf->trimStart(expected_len);
- } else {
- ec = asio::error::connection_refused;
- disconnected(ec);
- return nullptr;
- }
- VLOG(2) << "Connection (client) " << connection_id() << " socks5 handshake response";
- break;
- };
- default:
- break;
- }
- if (buf->empty()) {
- goto out;
- }
- }
- if (CIPHER_METHOD_IS_SOCKS(method)) {
+ if (CIPHER_METHOD_IS_SOCKS(method())) {
downstream_.push_back(buf);
} else {
decoder_->process_bytes(buf);
@@ -1252,6 +1085,202 @@ out:
return downstream_.front();
}
+void CliConnection::ReadUpstreamHttpsHandshake(std::shared_ptr buf, asio::error_code& ec) {
+ DCHECK(upstream_handshake_);
+
+ upstream_handshake_ = false;
+ HttpResponseParser parser;
+
+ bool ok;
+ int nparsed = parser.Parse(buf, &ok);
+
+ if (nparsed) {
+ VLOG(3) << "Connection (client) " << connection_id()
+ << " http: " << std::string(reinterpret_cast(buf->data()), nparsed);
+ }
+ if (ok && parser.status_code() == 200) {
+ buf->trimStart(nparsed);
+ buf->retreat(nparsed);
+ } else {
+ if (!ok) {
+ LOG(WARNING) << "Connection (client) " << connection_id()
+ << " upstream server unhandled: " << parser.ErrorMessage() << ": "
+ << std::string(reinterpret_cast(buf->data()), nparsed);
+ } else {
+ LOG(WARNING) << "Connection (client) " << connection_id() << " upstream server returns: " << parser.status_code();
+ }
+ ec = asio::error::connection_refused;
+ disconnected(ec);
+ return;
+ }
+ if (buf->empty()) {
+ ec = asio::error::try_again;
+ return;
+ }
+}
+
+void CliConnection::ReadUpstreamMethodSelectHandshake(std::shared_ptr buf, asio::error_code& ec) {
+ DCHECK(socks5_method_select_handshake_);
+ socks5_method_select_handshake_ = false;
+ auto response = reinterpret_cast(buf->data());
+ if (buf->length() < sizeof(socks5::method_select_response)) {
+ goto err_out;
+ }
+ if (response->ver != socks5::version && response->method != socks5::no_auth_required) {
+ goto err_out;
+ }
+ VLOG(2) << "Connection (client) " << connection_id() << " upstream socks5 method select response";
+ buf->trimStart(sizeof(socks5::method_select_response));
+ buf->retreat(sizeof(socks5::method_select_response));
+
+ WriteUpstreamMethodSelectResponse();
+
+ if (buf->empty()) {
+ ec = asio::error::try_again;
+ return;
+ }
+
+ return;
+
+err_out:
+ LOG(WARNING) << "Connection (client) " << connection_id() << " malformed upstream method select handshake response";
+ ec = asio::error::connection_refused;
+ disconnected(ec);
+ return;
+}
+
+void CliConnection::WriteUpstreamMethodSelectResponse() {
+ socks5::request_header header;
+ header.version = socks5::version;
+ header.command = socks5::cmd_connect;
+ header.null_byte = 0;
+
+ ByteRange req(reinterpret_cast(&header), sizeof(header));
+ std::shared_ptr buf = IOBuf::copyBuffer(req);
+
+ absl::Span address;
+ std::string domain_name;
+
+ uint8_t address_type = socks5::ipv4;
+ if (ss_request_->address_type() == ss::domain) {
+ address_type = socks5::domain;
+ domain_name = ss_request_->domain_name();
+ address = absl::Span((uint8_t*)domain_name.c_str(), domain_name.size());
+ } else if (ss_request_->address_type() == ss::ipv6) {
+ address_type = socks5::ipv6;
+ address = absl::Span((uint8_t*)&ss_request_->address6(), sizeof(ss_request_->address6()));
+ } else {
+ address_type = socks5::ipv4;
+ address = absl::Span((uint8_t*)&ss_request_->address4(), sizeof(ss_request_->address4()));
+ }
+
+ buf->reserve(0, sizeof(address_type));
+ memcpy(buf->mutable_tail(), &address_type, sizeof(address_type));
+ buf->append(sizeof(address_type));
+
+ if (ss_request_->address_type() == ss::domain) {
+ uint8_t address_len = address.size();
+ buf->reserve(0, sizeof(address_len));
+ memcpy(buf->mutable_tail(), &address_len, sizeof(address_len));
+ buf->append(sizeof(address_len));
+ }
+
+ buf->reserve(0, address.size());
+ memcpy(buf->mutable_tail(), address.data(), address.size());
+ buf->append(address.size());
+
+ uint8_t port_high_byte = ss_request_->port_high_byte();
+ uint8_t port_low_byte = ss_request_->port_low_byte();
+
+ buf->reserve(0, sizeof(uint16_t));
+ *buf->mutable_tail() = port_high_byte;
+ buf->append(sizeof(port_high_byte));
+ *buf->mutable_tail() = port_low_byte;
+ buf->append(sizeof(port_low_byte));
+
+ upstream_.replace_front(buf);
+ WriteUpstreamInPipe();
+}
+
+void CliConnection::ReadUpstreamSocksHandshake(std::shared_ptr buf, asio::error_code& ec) {
+ DCHECK(socks_handshake_);
+ socks_handshake_ = false;
+ switch (method()) {
+ case CRYPTO_SOCKS4:
+ case CRYPTO_SOCKS4A: {
+ if (buf->length() < sizeof(socks4::reply_header)) {
+ goto err_out;
+ }
+ auto response = reinterpret_cast(buf->data());
+ if (response->null_byte != 0 || response->status != socks4::reply::request_granted) {
+ goto err_out;
+ }
+ VLOG(2) << "Connection (client) " << connection_id() << " upstream socks4 handshake response";
+ buf->trimStart(sizeof(socks4::reply_header));
+ buf->retreat(sizeof(socks4::reply_header));
+ break;
+ };
+ case CRYPTO_SOCKS5:
+ case CRYPTO_SOCKS5H: {
+ if (buf->length() < sizeof(socks5::reply_header)) {
+ goto err_out;
+ }
+ auto response = reinterpret_cast(buf->data());
+ if (response->version != socks5::version || response->status != socks5::reply::request_granted ||
+ response->null_byte != 0) {
+ goto err_out;
+ }
+ if (response->address_type == socks5::ipv4) {
+ uint32_t expected_len =
+ sizeof(socks5::reply_header) + sizeof(asio::ip::address_v4::bytes_type) + sizeof(uint16_t);
+ if (buf->length() < expected_len) {
+ goto err_out;
+ }
+ buf->trimStart(expected_len);
+ buf->retreat(expected_len);
+ } else if (response->address_type == socks5::ipv6) {
+ uint32_t expected_len =
+ sizeof(socks5::reply_header) + sizeof(asio::ip::address_v6::bytes_type) + sizeof(uint16_t);
+ if (buf->length() < expected_len) {
+ goto err_out;
+ }
+ buf->trimStart(expected_len);
+ buf->retreat(expected_len);
+ } else if (response->address_type == socks5::domain) {
+ uint32_t expected_len = sizeof(socks5::reply_header) + sizeof(uint8_t) + sizeof(uint16_t);
+ if (buf->length() < expected_len) {
+ goto err_out;
+ }
+ expected_len += *reinterpret_cast(buf->data() + sizeof(*response));
+ if (buf->length() < expected_len) {
+ goto err_out;
+ }
+ buf->trimStart(expected_len);
+ buf->retreat(expected_len);
+ } else {
+ goto err_out;
+ return;
+ }
+ VLOG(2) << "Connection (client) " << connection_id() << " upstream socks5 handshake response";
+ break;
+ };
+ default:
+ CHECK(false);
+ break;
+ }
+ if (buf->empty()) {
+ ec = asio::error::try_again;
+ return;
+ }
+ return;
+
+err_out:
+ LOG(WARNING) << "Connection (client) " << connection_id() << " malformed upstream socks handshake response";
+ ec = asio::error::connection_refused;
+ disconnected(ec);
+ return;
+}
+
void CliConnection::WriteUpstreamInPipe() {
asio::error_code ec;
size_t bytes_transferred = 0U, wbytes_transferred = 0U;
@@ -1339,8 +1368,7 @@ void CliConnection::WriteUpstreamInPipe() {
std::shared_ptr CliConnection::GetNextUpstreamBuf(asio::error_code& ec, size_t* bytes_transferred) {
if (!upstream_.empty()) {
// pending on upstream handshake
- auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS5(method) && socks5_method_select_handshake_ && upstream_.front()->empty()) {
+ if (CIPHER_METHOD_IS_SOCKS5(method()) && socks5_method_select_handshake_ && upstream_.front()->empty()) {
ec = asio::error::try_again;
return nullptr;
}
@@ -1404,8 +1432,7 @@ std::shared_ptr CliConnection::GetNextUpstreamBuf(asio::error_code& ec, s
if (upstream_https_fallback_) {
upstream_.push_back(buf);
} else {
- auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS(method)) {
+ if (CIPHER_METHOD_IS_SOCKS(method())) {
upstream_.push_back(buf);
} else {
EncryptData(&upstream_, buf);
@@ -1622,8 +1649,7 @@ void CliConnection::OnCmdConnect(const asio::ip::tcp::endpoint& endpoint) {
void CliConnection::OnCmdConnect(const std::string& domain_name, uint16_t port) {
DCHECK_LE(domain_name.size(), (unsigned int)TLSEXT_MAXLEN_host_name);
- auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS_NON_DOMAIN_NAME(method)) {
+ if (CIPHER_METHOD_IS_SOCKS_NON_DOMAIN_NAME(method())) {
scoped_refptr self(this);
resolver_.AsyncResolve(domain_name, port,
[this, self](const asio::error_code& ec, asio::ip::tcp::resolver::results_type results) {
@@ -1704,8 +1730,7 @@ void CliConnection::OnStreamRead(std::shared_ptr buf) {
if (upstream_https_fallback_) {
upstream_.push_back(buf);
} else {
- auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS(method)) {
+ if (CIPHER_METHOD_IS_SOCKS(method())) {
upstream_.push_back(buf);
} else {
EncryptData(&upstream_, buf);
@@ -1793,8 +1818,7 @@ void CliConnection::connected() {
VLOG(2) << "Connection (client) " << connection_id()
<< " remote: established upstream connection with: " << remote_domain();
- const auto method = absl::GetFlag(FLAGS_method).method;
- bool http2 = CIPHER_METHOD_IS_HTTP2(method);
+ bool http2 = CIPHER_METHOD_IS_HTTP2(method());
if (http2 && channel_->https_fallback()) {
http2 = false;
upstream_https_fallback_ = true;
@@ -1819,11 +1843,9 @@ void CliConnection::connected() {
// padding_support_ = absl::GetFlag(FLAGS_padding_support);
} else {
DCHECK(!http2);
- auto method = absl::GetFlag(FLAGS_method).method;
- if (!CIPHER_METHOD_IS_SOCKS(method)) {
- encoder_ =
- std::make_unique("", absl::GetFlag(FLAGS_password), absl::GetFlag(FLAGS_method).method, this, true);
- decoder_ = std::make_unique("", absl::GetFlag(FLAGS_password), absl::GetFlag(FLAGS_method).method, this);
+ if (!CIPHER_METHOD_IS_SOCKS(method())) {
+ encoder_ = std::make_unique("", absl::GetFlag(FLAGS_password), method(), this, true);
+ decoder_ = std::make_unique("", absl::GetFlag(FLAGS_password), method(), this);
}
}
@@ -1880,7 +1902,7 @@ void CliConnection::connected() {
FillNonindexHeaderValue(RandUint64(), &padding[0], padding.size());
headers.emplace_back("padding"s, padding);
}
- stream_id_ = adapter_->SubmitRequest(GenerateHeaders(headers), std::move(data_frame), nullptr);
+ stream_id_ = adapter_->SubmitRequest(GenerateHeaders(headers), std::move(data_frame), false, nullptr);
data_frame_->set_stream_id(stream_id_);
SendIfNotProcessing();
} else
@@ -1915,9 +1937,8 @@ void CliConnection::connected() {
// write variable address directly as https header
upstream_.push_back(hdr.data(), hdr.size());
} else {
- auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS(method)) {
- switch (method) {
+ if (CIPHER_METHOD_IS_SOCKS(method())) {
+ switch (method()) {
case CRYPTO_SOCKS4: {
socks4::request_header header;
header.version = socks4::version;
diff --git a/yass/src/cli/cli_connection.hpp b/yass/src/cli/cli_connection.hpp
index d243fc27fc..f704369740 100644
--- a/yass/src/cli/cli_connection.hpp
+++ b/yass/src/cli/cli_connection.hpp
@@ -17,10 +17,8 @@
#include "net/resolver.hpp"
#include "net/socks4.hpp"
#include "net/socks4_request.hpp"
-#include "net/socks4_request_parser.hpp"
#include "net/socks5.hpp"
#include "net/socks5_request.hpp"
-#include "net/socks5_request_parser.hpp"
#include "net/ss_request.hpp"
#include "net/ssl_stream.hpp"
#include "net/stream.hpp"
@@ -327,13 +325,10 @@ class CliConnection : public RefCountedThreadSafe,
/// state machine
state state_;
- /// parser of method select request
- socks5::method_select_request_parser method_select_request_parser_;
+ private:
/// copy of method select request
socks5::method_select_request method_select_request_;
- /// parser of handshake request
- socks5::request_parser request_parser_;
/// copy of handshake request
socks5::request s5_request_;
@@ -342,8 +337,6 @@ class CliConnection : public RefCountedThreadSafe,
/// copy of handshake response
socks5::reply s5_reply_;
- /// parser of handshake request
- socks4::request_parser s4_request_parser_;
/// copy of handshake request
socks4::request s4_request_;
@@ -367,6 +360,12 @@ class CliConnection : public RefCountedThreadSafe,
int num_padding_recv_ = 0;
std::shared_ptr padding_in_middle_buf_;
+ private:
+ void ReadUpstreamHttpsHandshake(std::shared_ptr buf, asio::error_code& ec);
+ void ReadUpstreamMethodSelectHandshake(std::shared_ptr buf, asio::error_code& ec);
+ void WriteUpstreamMethodSelectResponse();
+ void ReadUpstreamSocksHandshake(std::shared_ptr buf, asio::error_code& ec);
+
/// the state of https fallback handshake (upstream)
bool upstream_handshake_ = true;
/// the state of socks5 method select handshake (upstream)
diff --git a/yass/src/net/connection.hpp b/yass/src/net/connection.hpp
index c4d4b13b43..63831578e5 100644
--- a/yass/src/net/connection.hpp
+++ b/yass/src/net/connection.hpp
@@ -295,6 +295,12 @@ class Connection {
private:
/// the callback invoked when disconnect event happens
absl::AnyInvocable disconnect_cb_;
+
+ public:
+ cipher_method method() const { return method_; }
+
+ private:
+ cipher_method method_ = absl::GetFlag(FLAGS_method).method;
};
enum ConnectionFactoryType {
diff --git a/yass/src/server/server_connection.cpp b/yass/src/server/server_connection.cpp
index 3f1027cd68..ff0bcd34e8 100644
--- a/yass/src/server/server_connection.cpp
+++ b/yass/src/server/server_connection.cpp
@@ -21,6 +21,7 @@
#include "net/socks5.hpp"
#include "net/socks5_request.hpp"
#include "net/socks5_request_parser.hpp"
+#include "net/ss_request_parser.hpp"
#include "version.h"
ABSL_FLAG(bool, hide_via, true, "If true, the Via heaeder will not be added.");
@@ -206,8 +207,7 @@ void ServerConnection::close() {
}
void ServerConnection::Start() {
- const auto method = absl::GetFlag(FLAGS_method).method;
- bool http2 = CIPHER_METHOD_IS_HTTP2(method);
+ bool http2 = CIPHER_METHOD_IS_HTTP2(method());
if (http2 && downlink_->https_fallback()) {
http2 = false;
}
@@ -245,13 +245,11 @@ void ServerConnection::Start() {
ReadHandshakeViaHttps();
} else {
DCHECK(!http2);
- auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS(method)) {
+ if (CIPHER_METHOD_IS_SOCKS(method())) {
ReadHandshakeViaSocks();
} else {
- encoder_ =
- std::make_unique("", absl::GetFlag(FLAGS_password), absl::GetFlag(FLAGS_method).method, this, true);
- decoder_ = std::make_unique("", absl::GetFlag(FLAGS_password), absl::GetFlag(FLAGS_method).method, this);
+ encoder_ = std::make_unique("", absl::GetFlag(FLAGS_password), method(), this, true);
+ decoder_ = std::make_unique("", absl::GetFlag(FLAGS_password), method(), this);
ReadHandshake();
}
}
@@ -534,8 +532,9 @@ void ServerConnection::ReadHandshake() {
DumpHex("HANDSHAKE->", buf.get());
+ ss::request_parser parser;
ss::request_parser::result_type result;
- std::tie(result, std::ignore) = request_parser_.parse(request_, buf->data(), buf->data() + bytes_transferred);
+ std::tie(result, std::ignore) = parser.parse(request_, buf->data(), buf->data() + bytes_transferred);
if (result == ss::request_parser::good) {
buf->trimStart(request_.length());
@@ -700,8 +699,7 @@ void ServerConnection::OnReadHandshakeViaSocks() {
}
buf->append(bytes_transferred);
- auto method = absl::GetFlag(FLAGS_method).method;
- switch (method) {
+ switch (method()) {
case CRYPTO_SOCKS4:
case CRYPTO_SOCKS4A: {
socks4::request_parser request_parser;
@@ -757,12 +755,14 @@ void ServerConnection::OnReadHandshakeViaSocks() {
break;
};
default:
+ CHECK(false);
break;
}
}
void ServerConnection::WriteHandshakeResponse() {
scoped_refptr self(this);
+ DCHECK(CIPHER_METHOD_IS_SOCKS(method()));
downlink_->async_write_some([this, self](asio::error_code ec) {
if (closed_ || closing_) {
@@ -776,9 +776,8 @@ void ServerConnection::WriteHandshakeResponse() {
return;
}
std::shared_ptr buf;
- auto method = absl::GetFlag(FLAGS_method).method;
- DCHECK(CIPHER_METHOD_IS_SOCKS(method));
- if (method == CRYPTO_SOCKS4 || method == CRYPTO_SOCKS4A) {
+ DCHECK(CIPHER_METHOD_IS_SOCKS(method()));
+ if (method() == CRYPTO_SOCKS4 || method() == CRYPTO_SOCKS4A) {
socks4::reply reply;
asio::ip::tcp::endpoint endpoint{asio::ip::tcp::v4(), 0};
reply.set_endpoint(endpoint);
@@ -895,8 +894,7 @@ void ServerConnection::OnReadHandshakeViaSocks5() {
buf->append(bytes_transferred);
}
- auto method = absl::GetFlag(FLAGS_method).method;
- DCHECK(CIPHER_METHOD_IS_SOCKS5(method));
+ DCHECK(CIPHER_METHOD_IS_SOCKS5(method()));
socks5::request_parser request_parser;
socks5::request request;
@@ -1144,8 +1142,7 @@ std::shared_ptr ServerConnection::GetNextDownstreamBuf(asio::error_code&
if (downlink_->https_fallback()) {
downstream_.push_back(buf);
} else {
- const auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS(method)) {
+ if (CIPHER_METHOD_IS_SOCKS(method())) {
downstream_.push_back(buf);
} else {
EncryptData(&downstream_, buf);
@@ -1316,8 +1313,7 @@ try_again:
if (downlink_->https_fallback()) {
upstream_.push_back(buf);
} else {
- const auto method = absl::GetFlag(FLAGS_method).method;
- if (CIPHER_METHOD_IS_SOCKS(method)) {
+ if (CIPHER_METHOD_IS_SOCKS(method())) {
upstream_.push_back(buf);
} else {
decoder_->process_bytes(buf);
@@ -1465,7 +1461,8 @@ void ServerConnection::OnConnect() {
}
headers.emplace_back("padding"s, padding);
}
- int submit_result = adapter_->SubmitResponse(stream_id_, GenerateHeaders(headers, 200), std::move(data_frame));
+ int submit_result =
+ adapter_->SubmitResponse(stream_id_, GenerateHeaders(headers, 200), std::move(data_frame), false);
SendIfNotProcessing();
if (submit_result != 0) {
OnDisconnect(asio::error::connection_aborted);
diff --git a/yass/src/server/server_connection.hpp b/yass/src/server/server_connection.hpp
index 2b5a089f35..3c3c8c9004 100644
--- a/yass/src/server/server_connection.hpp
+++ b/yass/src/server/server_connection.hpp
@@ -15,7 +15,6 @@
#include "net/protocol.hpp"
#include "net/ss.hpp"
#include "net/ss_request.hpp"
-#include "net/ss_request_parser.hpp"
#include "net/ssl_stream.hpp"
#include "net/stream.hpp"
@@ -285,8 +284,6 @@ class ServerConnection : public RefCountedThreadSafe,
/// state machine
state state_;
- /// parser of handshake request
- ss::request_parser request_parser_;
/// copy of handshake request
ss::request request_;
diff --git a/yass/third_party/abseil-cpp/CMake/AbseilDll.cmake b/yass/third_party/abseil-cpp/CMake/AbseilDll.cmake
index 47f3beebd1..2a40532a43 100644
--- a/yass/third_party/abseil-cpp/CMake/AbseilDll.cmake
+++ b/yass/third_party/abseil-cpp/CMake/AbseilDll.cmake
@@ -66,6 +66,7 @@ set(ABSL_INTERNAL_DLL_FILES
"cleanup/internal/cleanup.h"
"container/btree_map.h"
"container/btree_set.h"
+ "container/hash_container_defaults.h"
"container/fixed_array.h"
"container/flat_hash_map.h"
"container/flat_hash_set.h"
@@ -123,6 +124,8 @@ set(ABSL_INTERNAL_DLL_FILES
"debugging/internal/address_is_readable.h"
"debugging/internal/demangle.cc"
"debugging/internal/demangle.h"
+ "debugging/internal/demangle_rust.cc"
+ "debugging/internal/demangle_rust.h"
"debugging/internal/elf_mem_image.cc"
"debugging/internal/elf_mem_image.h"
"debugging/internal/examine_stack.cc"
@@ -608,6 +611,9 @@ set(ABSL_INTERNAL_TEST_DLL_FILES
"random/internal/mock_overload_set.h"
"random/mocking_bit_gen.h"
"random/mock_distributions.h"
+ "status/status_matchers.h"
+ "status/internal/status_matchers.cc"
+ "status/internal/status_matchers.h"
"strings/cordz_test_helpers.h"
"strings/cord_test_helpers.h"
)
@@ -620,6 +626,7 @@ set(ABSL_INTERNAL_TEST_DLL_TARGETS
"random_internal_distribution_test_util"
"random_internal_mock_overload_set"
"scoped_mock_log"
+ "status_matchers"
)
include(CheckCXXSourceCompiles)
diff --git a/yass/third_party/abseil-cpp/absl/base/attributes.h b/yass/third_party/abseil-cpp/absl/base/attributes.h
index 643a949420..7666a5e23f 100644
--- a/yass/third_party/abseil-cpp/absl/base/attributes.h
+++ b/yass/third_party/abseil-cpp/absl/base/attributes.h
@@ -702,6 +702,11 @@
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \
_Pragma("GCC diagnostic pop")
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \
+ _Pragma("warning(push)") _Pragma("warning(disable: 4996)")
+#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \
+ _Pragma("warning(pop)")
#else
#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
diff --git a/yass/third_party/abseil-cpp/absl/base/internal/spinlock.h b/yass/third_party/abseil-cpp/absl/base/internal/spinlock.h
index 301c3e3b43..1bb260f46b 100644
--- a/yass/third_party/abseil-cpp/absl/base/internal/spinlock.h
+++ b/yass/third_party/abseil-cpp/absl/base/internal/spinlock.h
@@ -89,7 +89,8 @@ class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
// acquisition was successful. If the lock was not acquired, false is
// returned. If this SpinLock is free at the time of the call, TryLock
// will return true with high probability.
- inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ ABSL_MUST_USE_RESULT inline bool TryLock()
+ ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
bool res = TryLockImpl();
ABSL_TSAN_MUTEX_POST_LOCK(
@@ -120,7 +121,7 @@ class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
// Determine if the lock is held. When the lock is held by the invoking
// thread, true will always be returned. Intended to be used as
// CHECK(lock.IsHeld()).
- inline bool IsHeld() const {
+ ABSL_MUST_USE_RESULT inline bool IsHeld() const {
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
}
diff --git a/yass/third_party/abseil-cpp/absl/container/BUILD.bazel b/yass/third_party/abseil-cpp/absl/container/BUILD.bazel
index 12e27c21fd..859163f86f 100644
--- a/yass/third_party/abseil-cpp/absl/container/BUILD.bazel
+++ b/yass/third_party/abseil-cpp/absl/container/BUILD.bazel
@@ -126,6 +126,7 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":compressed_tuple",
+ "//absl/base:base_internal",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/memory",
@@ -247,7 +248,7 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
- ":hash_function_defaults",
+ ":hash_container_defaults",
":raw_hash_map",
"//absl/algorithm:container",
"//absl/base:core_headers",
@@ -284,7 +285,7 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
- ":hash_function_defaults",
+ ":hash_container_defaults",
":raw_hash_set",
"//absl/algorithm:container",
"//absl/base:core_headers",
@@ -323,7 +324,7 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
- ":hash_function_defaults",
+ ":hash_container_defaults",
":node_slot_policy",
":raw_hash_map",
"//absl/algorithm:container",
@@ -358,7 +359,7 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
- ":hash_function_defaults",
+ ":hash_container_defaults",
":node_slot_policy",
":raw_hash_set",
"//absl/algorithm:container",
@@ -432,6 +433,17 @@ cc_library(
],
)
+cc_library(
+ name = "hash_container_defaults",
+ hdrs = ["hash_container_defaults.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":hash_function_defaults",
+ "//absl/base:config",
+ ],
+)
+
cc_test(
name = "hash_function_defaults_test",
srcs = ["internal/hash_function_defaults_test.cc"],
diff --git a/yass/third_party/abseil-cpp/absl/container/CMakeLists.txt b/yass/third_party/abseil-cpp/absl/container/CMakeLists.txt
index 04055816cd..b1f5f9d8a3 100644
--- a/yass/third_party/abseil-cpp/absl/container/CMakeLists.txt
+++ b/yass/third_party/abseil-cpp/absl/container/CMakeLists.txt
@@ -176,6 +176,7 @@ absl_cc_library(
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::base_internal
absl::compressed_tuple
absl::config
absl::core_headers
@@ -288,7 +289,7 @@ absl_cc_library(
DEPS
absl::container_memory
absl::core_headers
- absl::hash_function_defaults
+ absl::hash_container_defaults
absl::raw_hash_map
absl::algorithm_container
absl::memory
@@ -325,7 +326,7 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS}
DEPS
absl::container_memory
- absl::hash_function_defaults
+ absl::hash_container_defaults
absl::raw_hash_set
absl::algorithm_container
absl::core_headers
@@ -367,7 +368,7 @@ absl_cc_library(
DEPS
absl::container_memory
absl::core_headers
- absl::hash_function_defaults
+ absl::hash_container_defaults
absl::node_slot_policy
absl::raw_hash_map
absl::algorithm_container
@@ -403,7 +404,7 @@ absl_cc_library(
DEPS
absl::container_memory
absl::core_headers
- absl::hash_function_defaults
+ absl::hash_container_defaults
absl::node_slot_policy
absl::raw_hash_set
absl::algorithm_container
@@ -429,6 +430,19 @@ absl_cc_test(
GTest::gmock_main
)
+absl_cc_library(
+ NAME
+ hash_container_defaults
+ HDRS
+ "hash_container_defaults.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::hash_function_defaults
+ PUBLIC
+)
+
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
diff --git a/yass/third_party/abseil-cpp/absl/container/flat_hash_map.h b/yass/third_party/abseil-cpp/absl/container/flat_hash_map.h
index a33c794fad..aa2c5c8c0c 100644
--- a/yass/third_party/abseil-cpp/absl/container/flat_hash_map.h
+++ b/yass/third_party/abseil-cpp/absl/container/flat_hash_map.h
@@ -31,16 +31,15 @@
#define ABSL_CONTAINER_FLAT_HASH_MAP_H_
#include
-#include
+#include
#include
#include
#include "absl/algorithm/container.h"
#include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
#include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export
-#include "absl/memory/memory.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -119,9 +118,8 @@ struct FlatHashMapPolicy;
// if (result != ducks.end()) {
// std::cout << "Result: " << result->second << std::endl;
// }
-template ,
- class Eq = absl::container_internal::hash_default_eq,
+template ,
+ class Eq = DefaultHashContainerEq,
class Allocator = std::allocator>>
class flat_hash_map : public absl::container_internal::raw_hash_map<
absl::container_internal::FlatHashMapPolicy,
diff --git a/yass/third_party/abseil-cpp/absl/container/flat_hash_set.h b/yass/third_party/abseil-cpp/absl/container/flat_hash_set.h
index 5f72f9549e..e558b071c3 100644
--- a/yass/third_party/abseil-cpp/absl/container/flat_hash_set.h
+++ b/yass/third_party/abseil-cpp/absl/container/flat_hash_set.h
@@ -36,8 +36,8 @@
#include "absl/algorithm/container.h"
#include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
#include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
#include "absl/memory/memory.h"
@@ -114,8 +114,8 @@ struct FlatHashSetPolicy;
// if (ducks.contains("dewey")) {
// std::cout << "We found dewey!" << std::endl;
// }
-template ,
- class Eq = absl::container_internal::hash_default_eq,
+template ,
+ class Eq = DefaultHashContainerEq,
class Allocator = std::allocator>
class flat_hash_set
: public absl::container_internal::raw_hash_set<
diff --git a/yass/third_party/abseil-cpp/absl/container/hash_container_defaults.h b/yass/third_party/abseil-cpp/absl/container/hash_container_defaults.h
new file mode 100644
index 0000000000..eb944a7c81
--- /dev/null
+++ b/yass/third_party/abseil-cpp/absl/container/hash_container_defaults.h
@@ -0,0 +1,45 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
+#define ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
+
+#include "absl/base/config.h"
+#include "absl/container/internal/hash_function_defaults.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// DefaultHashContainerHash is a convenience alias for the functor that is used
+// by default by Abseil hash-based (unordered) containers for hashing when
+// `Hash` type argument is not explicitly specified.
+//
+// This type alias can be used by generic code that wants to provide more
+// flexibility for defining underlying containers.
+template
+using DefaultHashContainerHash = absl::container_internal::hash_default_hash;
+
+// DefaultHashContainerEq is a convenience alias for the functor that is used by
+// default by Abseil hash-based (unordered) containers for equality check when
+// `Eq` type argument is not explicitly specified.
+//
+// This type alias can be used by generic code that wants to provide more
+// flexibility for defining underlying containers.
+template
+using DefaultHashContainerEq = absl::container_internal::hash_default_eq;
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
diff --git a/yass/third_party/abseil-cpp/absl/container/internal/inlined_vector.h b/yass/third_party/abseil-cpp/absl/container/internal/inlined_vector.h
index a157532813..2f24e4616f 100644
--- a/yass/third_party/abseil-cpp/absl/container/internal/inlined_vector.h
+++ b/yass/third_party/abseil-cpp/absl/container/internal/inlined_vector.h
@@ -27,6 +27,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
+#include "absl/base/internal/identity.h"
#include "absl/base/macros.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/memory/memory.h"
@@ -82,16 +83,6 @@ using IsMoveAssignOk = std::is_move_assignable>;
template
using IsSwapOk = absl::type_traits_internal::IsSwappable>;
-template
-struct TypeIdentity {
- using type = T;
-};
-
-// Used for function arguments in template functions to prevent ADL by forcing
-// callers to explicitly specify the template parameter.
-template
-using NoTypeDeduction = typename TypeIdentity::type;
-
template >::value>
struct DestroyAdapter;
@@ -139,7 +130,7 @@ struct MallocAdapter {
};
template
-void ConstructElements(NoTypeDeduction& allocator,
+void ConstructElements(absl::internal::type_identity_t& allocator,
Pointer construct_first, ValueAdapter& values,
SizeType construct_size) {
for (SizeType i = 0; i < construct_size; ++i) {
diff --git a/yass/third_party/abseil-cpp/absl/container/node_hash_map.h b/yass/third_party/abseil-cpp/absl/container/node_hash_map.h
index cb41543c93..31beb1daa7 100644
--- a/yass/third_party/abseil-cpp/absl/container/node_hash_map.h
+++ b/yass/third_party/abseil-cpp/absl/container/node_hash_map.h
@@ -37,14 +37,13 @@
#define ABSL_CONTAINER_NODE_HASH_MAP_H_
#include
-#include
+#include
#include
#include
#include "absl/algorithm/container.h"
-#include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
#include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/node_slot_policy.h"
#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export
#include "absl/memory/memory.h"
@@ -114,9 +113,8 @@ class NodeHashMapPolicy;
// if (result != ducks.end()) {
// std::cout << "Result: " << result->second << std::endl;
// }
-template ,
- class Eq = absl::container_internal::hash_default_eq,
+template ,
+ class Eq = DefaultHashContainerEq,
class Alloc = std::allocator>>
class node_hash_map
: public absl::container_internal::raw_hash_map<
diff --git a/yass/third_party/abseil-cpp/absl/container/node_hash_set.h b/yass/third_party/abseil-cpp/absl/container/node_hash_set.h
index 8cc4b62407..deeb49ce53 100644
--- a/yass/third_party/abseil-cpp/absl/container/node_hash_set.h
+++ b/yass/third_party/abseil-cpp/absl/container/node_hash_set.h
@@ -36,12 +36,12 @@
#define ABSL_CONTAINER_NODE_HASH_SET_H_
#include
+#include
#include
#include "absl/algorithm/container.h"
-#include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
#include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/node_slot_policy.h"
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
#include "absl/memory/memory.h"
@@ -109,9 +109,8 @@ struct NodeHashSetPolicy;
// if (ducks.contains("dewey")) {
// std::cout << "We found dewey!" << std::endl;
// }
-template ,
- class Eq = absl::container_internal::hash_default_eq,
- class Alloc = std::allocator>
+template ,
+ class Eq = DefaultHashContainerEq, class Alloc = std::allocator>
class node_hash_set
: public absl::container_internal::raw_hash_set<
absl::container_internal::NodeHashSetPolicy, Hash, Eq, Alloc> {
diff --git a/yass/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h b/yass/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h
index aa6a65954f..0f6e3479e6 100644
--- a/yass/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h
+++ b/yass/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h
@@ -123,8 +123,8 @@ uint64_t V128_Extract64(const V128 l);
// Extracts the low 64 bits from V128.
int64_t V128_Low64(const V128 l);
-// Left-shifts packed 64-bit integers in l by r.
-V128 V128_ShiftLeft64(const V128 l, const V128 r);
+// Add packed 64-bit integers in |l| and |r|.
+V128 V128_Add64(const V128 l, const V128 r);
#endif
@@ -193,8 +193,8 @@ inline uint64_t V128_Extract64(const V128 l) {
inline int64_t V128_Low64(const V128 l) { return _mm_cvtsi128_si64(l); }
-inline V128 V128_ShiftLeft64(const V128 l, const V128 r) {
- return _mm_sll_epi64(l, r);
+inline V128 V128_Add64(const V128 l, const V128 r) {
+ return _mm_add_epi64(l, r);
}
#elif defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD)
@@ -289,9 +289,7 @@ inline int64_t V128_Low64(const V128 l) {
return vgetq_lane_s64(vreinterpretq_s64_u64(l), 0);
}
-inline V128 V128_ShiftLeft64(const V128 l, const V128 r) {
- return vshlq_u64(l, vreinterpretq_s64_u64(r));
-}
+inline V128 V128_Add64(const V128 l, const V128 r) { return vaddq_u64(l, r); }
#endif
diff --git a/yass/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_x86_arm_combined.cc b/yass/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_x86_arm_combined.cc
index 24353f2ab6..38f61e9b1f 100644
--- a/yass/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_x86_arm_combined.cc
+++ b/yass/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_x86_arm_combined.cc
@@ -130,8 +130,8 @@ ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED inline void LargeTailCopy(
size_t data_index = i * kIntLoadsPerVec + j;
int_data[data_index] = *(usrc + j);
- crcs[region] = crc32c_t{static_cast(CRC32_u64(
- static_cast(crcs[region]), int_data[data_index]))};
+ crcs[region] = crc32c_t{CRC32_u64(static_cast(crcs[region]),
+ int_data[data_index])};
*(udst + j) = int_data[data_index];
}
@@ -299,8 +299,8 @@ AcceleratedCrcMemcpyEngine::Compute(
// Load and CRC the data.
int_data[data_index] = *(usrc + i * kIntLoadsPerVec + k);
- crcs[region] = crc32c_t{static_cast(CRC32_u64(
- static_cast(crcs[region]), int_data[data_index]))};
+ crcs[region] = crc32c_t{CRC32_u64(static_cast(crcs[region]),
+ int_data[data_index])};
// Store the data.
*(udst + i * kIntLoadsPerVec + k) = int_data[data_index];
diff --git a/yass/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc b/yass/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc
index 20dd3e017a..79dace34f4 100644
--- a/yass/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc
+++ b/yass/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc
@@ -101,13 +101,17 @@ constexpr size_t kMediumCutoff = 2048;
namespace {
uint32_t multiply(uint32_t a, uint32_t b) {
- V128 shifts = V128_From64WithZeroFill(1);
V128 power = V128_From64WithZeroFill(a);
V128 crc = V128_From64WithZeroFill(b);
V128 res = V128_PMulLow(power, crc);
- // Combine crc values
- res = V128_ShiftLeft64(res, shifts);
+ // Combine crc values.
+ //
+ // Adding res to itself is equivalent to multiplying by 2,
+ // or shifting left by 1. Addition is used as not all compilers
+ // are able to generate optimal code without this hint.
+ // https://godbolt.org/z/rr3fMnf39
+ res = V128_Add64(res, res);
return static_cast(V128_Extract32<1>(res)) ^
CRC32_u32(0, static_cast(V128_Low64(res)));
}
diff --git a/yass/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/yass/third_party/abseil-cpp/absl/debugging/BUILD.bazel
index 5baff7a116..22494554c7 100644
--- a/yass/third_party/abseil-cpp/absl/debugging/BUILD.bazel
+++ b/yass/third_party/abseil-cpp/absl/debugging/BUILD.bazel
@@ -219,8 +219,14 @@ cc_library(
cc_library(
name = "demangle_internal",
- srcs = ["internal/demangle.cc"],
- hdrs = ["internal/demangle.h"],
+ srcs = [
+ "internal/demangle.cc",
+ "internal/demangle_rust.cc",
+ ],
+ hdrs = [
+ "internal/demangle.h",
+ "internal/demangle_rust.h",
+ ],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
@@ -234,6 +240,20 @@ cc_library(
],
)
+cc_test(
+ name = "demangle_rust_test",
+ srcs = ["internal/demangle_rust_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":demangle_internal",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "@com_google_googletest//:gtest",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
cc_test(
name = "demangle_test",
srcs = ["internal/demangle_test.cc"],
diff --git a/yass/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/yass/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
index 65e2af8801..027a6be28b 100644
--- a/yass/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
+++ b/yass/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
@@ -196,8 +196,10 @@ absl_cc_library(
demangle_internal
HDRS
"internal/demangle.h"
+ "internal/demangle_rust.h"
SRCS
"internal/demangle.cc"
+ "internal/demangle_rust.cc"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
@@ -206,6 +208,19 @@ absl_cc_library(
PUBLIC
)
+absl_cc_test(
+ NAME
+ demangle_rust_test
+ SRCS
+ "internal/demangle_rust_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::demangle_internal
+ absl::config
+ GTest::gmock_main
+)
+
absl_cc_test(
NAME
demangle_test
diff --git a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.cc b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.cc
index 82420c8b2d..71d4eb0a67 100644
--- a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.cc
+++ b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.cc
@@ -19,6 +19,7 @@
#include "absl/debugging/internal/demangle.h"
+#include
#include
#include
#include
@@ -26,6 +27,7 @@
#include
#include "absl/base/config.h"
+#include "absl/debugging/internal/demangle_rust.h"
#if ABSL_INTERNAL_HAS_CXA_DEMANGLE
#include
@@ -2110,6 +2112,10 @@ static bool Overflowed(const State *state) {
// The demangler entry point.
bool Demangle(const char* mangled, char* out, size_t out_size) {
+ if (mangled[0] == '_' && mangled[1] == 'R') {
+ return DemangleRustSymbolEncoding(mangled, out, out_size);
+ }
+
State state;
InitState(&state, mangled, out, out_size);
return ParseTopLevelMangledName(&state) && !Overflowed(&state) &&
diff --git a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.h b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.h
index 146d1150ef..e75d1473c7 100644
--- a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.h
+++ b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle.h
@@ -56,6 +56,8 @@ namespace debugging_internal {
//
// See the unit test for more examples.
//
+// Support for Rust mangled names is in development; see demangle_rust.h.
+//
// Note: we might want to write demanglers for ABIs other than Itanium
// C++ ABI in the future.
bool Demangle(const char* mangled, char* out, size_t out_size);
diff --git a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust.cc b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust.cc
new file mode 100644
index 0000000000..7086cab243
--- /dev/null
+++ b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust.cc
@@ -0,0 +1,432 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/debugging/internal/demangle_rust.h"
+
+#include
+#include
+#include
+#include
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+namespace {
+
+// Same step limit as the C++ demangler in demangle.cc uses.
+constexpr int kMaxReturns = 1 << 17;
+
+bool IsDigit(char c) { return '0' <= c && c <= '9'; }
+bool IsLower(char c) { return 'a' <= c && c <= 'z'; }
+bool IsUpper(char c) { return 'A' <= c && c <= 'Z'; }
+bool IsAlpha(char c) { return IsLower(c) || IsUpper(c); }
+bool IsIdentifierChar(char c) { return IsAlpha(c) || IsDigit(c) || c == '_'; }
+
+// Parser for Rust symbol mangling v0, whose grammar is defined here:
+//
+// https://doc.rust-lang.org/rustc/symbol-mangling/v0.html#symbol-grammar-summary
+class RustSymbolParser {
+ public:
+ // Prepares to demangle the given encoding, a Rust symbol name starting with
+ // _R, into the output buffer [out, out_end). The caller is expected to
+ // continue by calling the new object's Parse function.
+ RustSymbolParser(const char* encoding, char* out, char* const out_end)
+ : encoding_(encoding), out_(out), out_end_(out_end) {
+ if (out_ != out_end_) *out_ = '\0';
+ }
+
+ // Parses the constructor's encoding argument, writing output into the range
+ // [out, out_end). Returns true on success and false for input whose
+ // structure was not recognized or exceeded implementation limits, such as by
+ // nesting structures too deep. In either case *this should not be used
+ // again.
+ ABSL_MUST_USE_RESULT bool Parse() && {
+ // Recursively parses the grammar production named by callee, then resumes
+ // execution at the next statement.
+ //
+ // Recursive-descent parsing is a beautifully readable translation of a
+ // grammar, but it risks stack overflow if implemented by naive recursion on
+ // the C++ call stack. So we simulate recursion by goto and switch instead,
+ // keeping a bounded stack of "return addresses" in the stack_ member.
+ //
+ // The callee argument is a statement label. We goto that label after
+ // saving the "return address" on stack_. The next continue statement in
+ // the for loop below "returns" from this "call".
+ //
+ // The caller argument names the return point. Each value of caller must
+ // appear in only one ABSL_DEMANGLER_RECURSE call and be listed in the
+ // definition of enum ReturnAddress. The switch implements the control
+ // transfer from the end of a "called" subroutine back to the statement
+ // after the "call".
+ //
+ // Note that not all the grammar productions have to be packed into the
+ // switch, but only those which appear in a cycle in the grammar. Anything
+ // acyclic can be written as ordinary functions and function calls, e.g.,
+ // ParseIdentifier.
+#define ABSL_DEMANGLER_RECURSE(callee, caller) \
+ do { \
+ if (depth_ == data_stack_pointer_) return false; \
+ /* The next continue will switch on this saved value ... */ \
+ stack_[depth_++] = caller; \
+ goto callee; \
+ /* ... and will land here, resuming the suspended code. */ \
+ case caller: {} \
+ } while (0)
+
+ // Parse the encoding, counting completed recursive calls to guard against
+ // excessively complex input and infinite-loop bugs.
+ int iter = 0;
+ goto whole_encoding;
+ for (; iter < kMaxReturns && depth_ > 0; ++iter) {
+ // This switch resumes the code path most recently suspended by
+ // ABSL_DEMANGLER_RECURSE.
+ switch (static_cast(stack_[--depth_])) {
+ //
+ // symbol-name ->
+ // _R decimal-number? path instantiating-crate? vendor-specific-suffix?
+ whole_encoding:
+ if (!Eat('_') || !Eat('R')) return false;
+ // decimal-number? is always empty today, so proceed to path, which
+ // can't start with a decimal digit.
+ ABSL_DEMANGLER_RECURSE(path, kInstantiatingCrate);
+ if (IsAlpha(Peek())) {
+ ++silence_depth_; // Print nothing more from here on.
+ ABSL_DEMANGLER_RECURSE(path, kVendorSpecificSuffix);
+ }
+ switch (Take()) {
+ case '.': case '$': case '\0': return true;
+ }
+ return false; // unexpected trailing content
+
+ // path -> crate-root | inherent-impl | trait-impl | trait-definition |
+ // nested-path | generic-args | backref
+ path:
+ switch (Take()) {
+ case 'C': goto crate_root;
+ case 'M': return false; // inherent-impl not yet implemented
+ case 'X': return false; // trait-impl not yet implemented
+ case 'Y': return false; // trait-definition not yet implemented
+ case 'N': goto nested_path;
+ case 'I': return false; // generic-args not yet implemented
+ case 'B': return false; // backref not yet implemented
+ default: return false;
+ }
+
+ // crate-root -> C identifier (C consumed above)
+ crate_root:
+ if (!ParseIdentifier()) return false;
+ continue;
+
+ // nested-path -> N namespace path identifier (N consumed above)
+ // namespace -> lower | upper
+ nested_path:
+ // Uppercase namespaces must be saved on the stack so we can print
+ // ::{closure#0} or ::{shim:vtable#0} or ::{X:name#0} as needed.
+ if (IsUpper(Peek())) {
+ if (!PushByte(static_cast(Take()))) return false;
+ ABSL_DEMANGLER_RECURSE(path, kIdentifierInUppercaseNamespace);
+ if (!Emit("::")) return false;
+ if (!ParseIdentifier(static_cast(PopByte()))) return false;
+ continue;
+ }
+
+ // Lowercase namespaces, however, are never represented in the output;
+ // they all emit just ::name.
+ if (IsLower(Take())) {
+ ABSL_DEMANGLER_RECURSE(path, kIdentifierInLowercaseNamespace);
+ if (!Emit("::")) return false;
+ if (!ParseIdentifier()) return false;
+ continue;
+ }
+
+ // Neither upper or lower
+ return false;
+ }
+ }
+
+ return false; // hit iteration limit or a bug in our stack handling
+ }
+
+ private:
+ // Enumerates resumption points for ABSL_DEMANGLER_RECURSE calls.
+ enum ReturnAddress : std::uint8_t {
+ kInstantiatingCrate,
+ kVendorSpecificSuffix,
+ kIdentifierInUppercaseNamespace,
+ kIdentifierInLowercaseNamespace,
+ };
+
+ // Element count for the stack_ array. A larger kStackSize accommodates more
+ // deeply nested names at the cost of a larger footprint on the C++ call
+ // stack.
+ enum { kStackSize = 256 };
+
+ // Returns the next input character without consuming it.
+ char Peek() const { return encoding_[pos_]; }
+
+ // Consumes and returns the next input character.
+ char Take() { return encoding_[pos_++]; }
+
+ // If the next input character is the given character, consumes it and returns
+ // true; otherwise returns false without consuming a character.
+ ABSL_MUST_USE_RESULT bool Eat(char want) {
+ if (encoding_[pos_] != want) return false;
+ ++pos_;
+ return true;
+ }
+
+ // Provided there is enough remaining output space, appends c to the output,
+ // writing a fresh NUL terminator afterward, and returns true. Returns false
+ // if the output buffer had less than two bytes free.
+ ABSL_MUST_USE_RESULT bool EmitChar(char c) {
+ if (silence_depth_ > 0) return true;
+ if (out_end_ - out_ < 2) return false;
+ *out_++ = c;
+ *out_ = '\0';
+ return true;
+ }
+
+ // Provided there is enough remaining output space, appends the C string token
+ // to the output, followed by a NUL character, and returns true. Returns
+ // false if not everything fit into the output buffer.
+ ABSL_MUST_USE_RESULT bool Emit(const char* token) {
+ if (silence_depth_ > 0) return true;
+ const std::size_t token_length = std::strlen(token);
+ const std::size_t bytes_to_copy = token_length + 1; // token and final NUL
+ if (static_cast(out_end_ - out_) < bytes_to_copy) return false;
+ std::memcpy(out_, token, bytes_to_copy);
+ out_ += token_length;
+ return true;
+ }
+
+ // Provided there is enough remaining output space, appends the decimal form
+ // of disambiguator (if it's nonnegative) or "?" (if it's negative) to the
+ // output, followed by a NUL character, and returns true. Returns false if
+ // not everything fit into the output buffer.
+ ABSL_MUST_USE_RESULT bool EmitDisambiguator(int disambiguator) {
+ if (disambiguator < 0) return EmitChar('?'); // parsed but too large
+ if (disambiguator == 0) return EmitChar('0');
+ // Convert disambiguator to decimal text. Three digits per byte is enough
+ // because 999 > 256. The bound will remain correct even if future
+ // maintenance changes the type of the disambiguator variable.
+ char digits[3 * sizeof(disambiguator)] = {};
+ std::size_t leading_digit_index = sizeof(digits) - 1;
+ for (; disambiguator > 0; disambiguator /= 10) {
+ digits[--leading_digit_index] =
+ static_cast('0' + disambiguator % 10);
+ }
+ return Emit(digits + leading_digit_index);
+ }
+
+ // Consumes an optional disambiguator (s123_) from the input.
+ //
+ // On success returns true and fills value with the encoded value if it was
+ // not too big, otherwise with -1. If the optional disambiguator was omitted,
+ // value is 0. On parse failure returns false and sets value to -1.
+ ABSL_MUST_USE_RESULT bool ParseDisambiguator(int& value) {
+ value = -1;
+
+ // disambiguator = s base-62-number
+ //
+ // Disambiguators are optional. An omitted disambiguator is zero.
+ if (!Eat('s')) {
+ value = 0;
+ return true;
+ }
+ int base_62_value = 0;
+ if (!ParseBase62Number(base_62_value)) return false;
+ value = base_62_value < 0 ? -1 : base_62_value + 1;
+ return true;
+ }
+
+ // Consumes a base-62 number like _ or 123_ from the input.
+ //
+ // On success returns true and fills value with the encoded value if it was
+ // not too big, otherwise with -1. On parse failure returns false and sets
+ // value to -1.
+ ABSL_MUST_USE_RESULT bool ParseBase62Number(int& value) {
+ value = -1;
+
+ // base-62-number = (digit | lower | upper)* _
+ //
+ // An empty base-62 digit sequence means 0.
+ if (Eat('_')) {
+ value = 0;
+ return true;
+ }
+
+ // A nonempty digit sequence denotes its base-62 value plus 1.
+ int encoded_number = 0;
+ bool overflowed = false;
+ while (IsAlpha(Peek()) || IsDigit(Peek())) {
+ const char c = Take();
+ if (encoded_number >= std::numeric_limits::max()/62) {
+ // If we are close to overflowing an int, keep parsing but stop updating
+ // encoded_number and remember to return -1 at the end. The point is to
+ // avoid undefined behavior while parsing crate-root disambiguators,
+ // which are large in practice but not shown in demangling, while
+ // successfully computing closure and shim disambiguators, which are
+ // typically small and are printed out.
+ overflowed = true;
+ } else {
+ int digit;
+ if (IsDigit(c)) {
+ digit = c - '0';
+ } else if (IsLower(c)) {
+ digit = c - 'a' + 10;
+ } else {
+ digit = c - 'A' + 36;
+ }
+ encoded_number = 62 * encoded_number + digit;
+ }
+ }
+
+ if (!Eat('_')) return false;
+ if (!overflowed) value = encoded_number + 1;
+ return true;
+ }
+
+ // Consumes an identifier from the input, returning true on success.
+ //
+ // A nonzero uppercase_namespace specifies the character after the N in a
+ // nested-identifier, e.g., 'C' for a closure, allowing ParseIdentifier to
+ // write out the name with the conventional decoration for that namespace.
+ ABSL_MUST_USE_RESULT bool ParseIdentifier(char uppercase_namespace = '\0') {
+ // identifier -> disambiguator? undisambiguated-identifier
+ int disambiguator = 0;
+ if (!ParseDisambiguator(disambiguator)) return false;
+
+ // undisambiguated-identifier -> u? decimal-number _? bytes
+ const bool is_punycoded = Eat('u');
+ if (!IsDigit(Peek())) return false;
+ int num_bytes = 0;
+ if (!ParseDecimalNumber(num_bytes)) return false;
+ (void)Eat('_'); // optional separator, needed if a digit follows
+
+ // Emit the beginnings of braced forms like {shim:vtable#0}.
+ if (uppercase_namespace == '\0') {
+ if (is_punycoded && !Emit("{Punycode ")) return false;
+ } else {
+ switch (uppercase_namespace) {
+ case 'C':
+ if (!Emit("{closure")) return false;
+ break;
+ case 'S':
+ if (!Emit("{shim")) return false;
+ break;
+ default:
+ if (!EmitChar('{') || !EmitChar(uppercase_namespace)) return false;
+ break;
+ }
+ if (num_bytes > 0 && !Emit(":")) return false;
+ }
+
+ // Emit the name itself.
+ for (int i = 0; i < num_bytes; ++i) {
+ const char c = Take();
+ if (!IsIdentifierChar(c) &&
+ // The spec gives toolchains the choice of Punycode or raw UTF-8 for
+ // identifiers containing code points above 0x7f, so accept bytes with
+ // the high bit set if this is not a u... encoding.
+ (is_punycoded || (c & 0x80) == 0)) {
+ return false;
+ }
+ if (!EmitChar(c)) return false;
+ }
+
+ // Emit the endings of braced forms: "#42}" or "}".
+ if (uppercase_namespace != '\0') {
+ if (!EmitChar('#')) return false;
+ if (!EmitDisambiguator(disambiguator)) return false;
+ }
+ if (uppercase_namespace != '\0' || is_punycoded) {
+ if (!EmitChar('}')) return false;
+ }
+
+ return true;
+ }
+
+ // Consumes a decimal number like 0 or 123 from the input. On success returns
+ // true and fills value with the encoded value. If the encoded value is too
+ // large or otherwise unparsable, returns false and sets value to -1.
+ ABSL_MUST_USE_RESULT bool ParseDecimalNumber(int& value) {
+ value = -1;
+ if (!IsDigit(Peek())) return false;
+ int encoded_number = Take() - '0';
+ if (encoded_number == 0) {
+ // Decimal numbers are never encoded with extra leading zeroes.
+ value = 0;
+ return true;
+ }
+ while (IsDigit(Peek()) &&
+ // avoid overflow
+ encoded_number < std::numeric_limits::max()/10) {
+ encoded_number = 10 * encoded_number + (Take() - '0');
+ }
+ if (IsDigit(Peek())) return false; // too big
+ value = encoded_number;
+ return true;
+ }
+
+ // Pushes byte onto the data stack (the right side of stack_) and returns
+ // true if stack_ is not full, else returns false.
+ ABSL_MUST_USE_RESULT bool PushByte(std::uint8_t byte) {
+ if (depth_ == data_stack_pointer_) return false;
+ stack_[--data_stack_pointer_] = byte;
+ return true;
+ }
+
+ // Pops the last pushed data byte from stack_. Requires that the data stack
+ // is not empty (data_stack_pointer_ < kStackSize).
+ std::uint8_t PopByte() { return stack_[data_stack_pointer_++]; }
+
+ // Call and data stacks reside in stack_. The leftmost depth_ elements
+ // contain ReturnAddresses pushed by ABSL_DEMANGLER_RECURSE. The elements
+ // from index data_stack_pointer_ to the right edge of stack_ contain bytes
+ // pushed by PushByte.
+ std::uint8_t stack_[kStackSize] = {};
+ int data_stack_pointer_ = kStackSize;
+ int depth_ = 0;
+
+ // Anything parsed while silence_depth_ > 0 contributes nothing to the
+ // demangled output. For constructs omitted from the demangling, such as
+ // impl-path and the contents of generic-args, we will increment
+ // silence_depth_ on the way in and decrement silence_depth_ on the way out.
+ int silence_depth_ = 0;
+
+ // Input: encoding_ points just after the _R in a Rust mangled symbol, and
+ // encoding_[pos_] is the next input character to be scanned.
+ int pos_ = 0;
+ const char* encoding_ = nullptr;
+
+ // Output: *out_ is where the next output character should be written, and
+ // out_end_ points past the last byte of available space.
+ char* out_ = nullptr;
+ char* out_end_ = nullptr;
+};
+
+} // namespace
+
+bool DemangleRustSymbolEncoding(const char* mangled, char* out,
+ std::size_t out_size) {
+ return RustSymbolParser(mangled, out, out + out_size).Parse();
+}
+
+} // namespace debugging_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust.h b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust.h
new file mode 100644
index 0000000000..8e9060b42f
--- /dev/null
+++ b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust.h
@@ -0,0 +1,47 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_RUST_H_
+#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_RUST_H_
+
+#include
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Demangle the Rust encoding `mangled`. On success, return true and write the
+// demangled symbol name to `out`. Otherwise, return false, leaving unspecified
+// contents in `out`. For example, calling DemangleRustSymbolEncoding with
+// `mangled = "_RNvC8my_crate7my_func"` will yield `my_crate::my_func` in `out`,
+// provided `out_size` is large enough for that value and its trailing NUL.
+//
+// DemangleRustSymbolEncoding is async-signal-safe and runs in bounded C++
+// call-stack space. It is suitable for symbolizing stack traces in a signal
+// handler.
+//
+// The demangling logic is under development. In this version of Abseil,
+// DemangleRustSymbolEncoding parses a few simple kinds of symbol names, but
+// nothing having backreferences in the input or angle brackets in the
+// demangling, and it emits raw Punycode instead of the UTF-8 represented by it.
+bool DemangleRustSymbolEncoding(const char* mangled, char* out,
+ std::size_t out_size);
+
+} // namespace debugging_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_DEBUGGING_INTERNAL_DEMANGLE_RUST_H_
diff --git a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust_test.cc b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust_test.cc
new file mode 100644
index 0000000000..2841576ef9
--- /dev/null
+++ b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_rust_test.cc
@@ -0,0 +1,216 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/debugging/internal/demangle_rust.h"
+
+#include
+#include
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+namespace {
+
+// If DemangleRustSymbolEncoding(mangled, , buffer_size) returns true and seems not to have overrun its output
+// buffer, returns the string written by DemangleRustSymbolEncoding; otherwise
+// returns an error message.
+std::string ResultOfDemangling(const char* mangled, std::size_t buffer_size) {
+ // Fill the buffer with something other than NUL so we test whether Demangle
+ // appends trailing NUL as expected.
+ std::string buffer(buffer_size + 1, '~');
+ constexpr char kCanaryCharacter = 0x7f; // arbitrary unlikely value
+ buffer[buffer_size] = kCanaryCharacter;
+ if (!DemangleRustSymbolEncoding(mangled, &buffer[0], buffer_size)) {
+ return "Failed parse";
+ }
+ if (buffer[buffer_size] != kCanaryCharacter) {
+ return "Buffer overrun by output: " + buffer.substr(0, buffer_size + 1)
+ + "...";
+ }
+ return buffer.data(); // Not buffer itself: this trims trailing padding.
+}
+
+// Tests that DemangleRustSymbolEncoding converts mangled into plaintext given
+// enough output buffer space but returns false and avoids overrunning a buffer
+// that is one byte too short.
+//
+// The lambda wrapping allows ASSERT_EQ to branch out the first time an
+// expectation is not satisfied, preventing redundant errors for the same bug.
+//
+// We test first with excess space so that if the algorithm just computes the
+// wrong answer, it will be clear from the error log that the bounds checks are
+// unlikely to be the code at fault.
+#define EXPECT_DEMANGLING(mangled, plaintext) \
+ do { \
+ [] { \
+ constexpr std::size_t plenty_of_space = sizeof(plaintext) + 128; \
+ constexpr std::size_t just_enough_space = sizeof(plaintext); \
+ constexpr std::size_t one_byte_too_few = sizeof(plaintext) - 1; \
+ const char* expected_plaintext = plaintext; \
+ const char* expected_error = "Failed parse"; \
+ ASSERT_EQ(ResultOfDemangling(mangled, plenty_of_space), \
+ expected_plaintext); \
+ ASSERT_EQ(ResultOfDemangling(mangled, just_enough_space), \
+ expected_plaintext); \
+ ASSERT_EQ(ResultOfDemangling(mangled, one_byte_too_few), \
+ expected_error); \
+ }(); \
+ } while (0)
+
+// Tests that DemangleRustSymbolEncoding rejects the given input (typically, a
+// truncation of a real Rust symbol name).
+#define EXPECT_DEMANGLING_FAILS(mangled) \
+ do { \
+ constexpr std::size_t plenty_of_space = 1024; \
+ const char* expected_error = "Failed parse"; \
+ EXPECT_EQ(ResultOfDemangling(mangled, plenty_of_space), expected_error); \
+ } while (0)
+
+// Piping grep -C 1 _R demangle_test.cc into your favorite c++filt
+// implementation allows you to verify that the goldens below are reasonable.
+
+TEST(DemangleRust, EmptyDemangling) {
+ EXPECT_TRUE(DemangleRustSymbolEncoding("_RC0", nullptr, 0));
+}
+
+TEST(DemangleRust, FunctionAtCrateLevel) {
+ EXPECT_DEMANGLING("_RNvC10crate_name9func_name", "crate_name::func_name");
+ EXPECT_DEMANGLING(
+ "_RNvCs09azAZ_10crate_name9func_name", "crate_name::func_name");
+}
+
+TEST(DemangleRust, TruncationsOfFunctionAtCrateLevel) {
+ EXPECT_DEMANGLING_FAILS("_R");
+ EXPECT_DEMANGLING_FAILS("_RN");
+ EXPECT_DEMANGLING_FAILS("_RNvC");
+ EXPECT_DEMANGLING_FAILS("_RNvC10");
+ EXPECT_DEMANGLING_FAILS("_RNvC10crate_nam");
+ EXPECT_DEMANGLING_FAILS("_RNvC10crate_name");
+ EXPECT_DEMANGLING_FAILS("_RNvC10crate_name9");
+ EXPECT_DEMANGLING_FAILS("_RNvC10crate_name9func_nam");
+ EXPECT_DEMANGLING_FAILS("_RNvCs");
+ EXPECT_DEMANGLING_FAILS("_RNvCs09azAZ");
+ EXPECT_DEMANGLING_FAILS("_RNvCs09azAZ_");
+}
+
+TEST(DemangleRust, VendorSuffixes) {
+ EXPECT_DEMANGLING("_RNvC10crate_name9func_name.!@#", "crate_name::func_name");
+ EXPECT_DEMANGLING("_RNvC10crate_name9func_name$!@#", "crate_name::func_name");
+}
+
+TEST(DemangleRust, UnicodeIdentifiers) {
+ EXPECT_DEMANGLING("_RNvC7ice_cap17Eyjafjallajökull",
+ "ice_cap::Eyjafjallajökull");
+ EXPECT_DEMANGLING("_RNvC7ice_caps_u19Eyjafjallajkull_jtb",
+ "ice_cap::{Punycode Eyjafjallajkull_jtb}");
+}
+
+TEST(DemangleRust, FunctionInModule) {
+ EXPECT_DEMANGLING("_RNvNtCs09azAZ_10crate_name11module_name9func_name",
+ "crate_name::module_name::func_name");
+}
+
+TEST(DemangleRust, FunctionInFunction) {
+ EXPECT_DEMANGLING(
+ "_RNvNvCs09azAZ_10crate_name15outer_func_name15inner_func_name",
+ "crate_name::outer_func_name::inner_func_name");
+}
+
+TEST(DemangleRust, ClosureInFunction) {
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_name0",
+ "crate_name::func_name::{closure#0}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_name0Cs123_12client_crate",
+ "crate_name::func_name::{closure#0}");
+}
+
+TEST(DemangleRust, ClosureNumbering) {
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_names_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#1}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_names0_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#2}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_names9_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#11}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_namesa_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#12}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_namesz_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#37}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_namesA_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#38}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_namesZ_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#63}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_names10_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#64}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_namesg6_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#1000}");
+}
+
+TEST(DemangleRust, ClosureNumberOverflowingInt) {
+ EXPECT_DEMANGLING(
+ "_RNCNvCs09azAZ_10crate_name9func_names1234567_0Cs123_12client_crate",
+ "crate_name::func_name::{closure#?}");
+}
+
+TEST(DemangleRust, UnexpectedlyNamedClosure) {
+ EXPECT_DEMANGLING(
+ "_RNCNvCs123_10crate_name9func_name12closure_nameCs456_12client_crate",
+ "crate_name::func_name::{closure:closure_name#0}");
+ EXPECT_DEMANGLING(
+ "_RNCNvCs123_10crate_name9func_names2_12closure_nameCs456_12client_crate",
+ "crate_name::func_name::{closure:closure_name#4}");
+}
+
+TEST(DemangleRust, ItemNestedInsideClosure) {
+ EXPECT_DEMANGLING(
+ "_RNvNCNvCs123_10crate_name9func_name015inner_func_nameCs_12client_crate",
+ "crate_name::func_name::{closure#0}::inner_func_name");
+}
+
+TEST(DemangleRust, Shim) {
+ EXPECT_DEMANGLING(
+ "_RNSNvCs123_10crate_name9func_name6vtableCs456_12client_crate",
+ "crate_name::func_name::{shim:vtable#0}");
+}
+
+TEST(DemangleRust, UnknownUppercaseNamespace) {
+ EXPECT_DEMANGLING(
+ "_RNXNvCs123_10crate_name9func_name14mystery_objectCs456_12client_crate",
+ "crate_name::func_name::{X:mystery_object#0}");
+}
+
+TEST(DemangleRust, NestedUppercaseNamespaces) {
+ EXPECT_DEMANGLING(
+ "_RNCNXNYCs123_10crate_names0_1ys1_1xs2_0Cs456_12client_crate",
+ "crate_name::{Y:y#2}::{X:x#3}::{closure#4}");
+}
+
+
+} // namespace
+} // namespace debugging_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc
index 1adc4fa8a0..0f2411a1d7 100644
--- a/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc
+++ b/yass/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc
@@ -300,6 +300,15 @@ TEST(Demangle, AbiTags) {
EXPECT_STREQ("C[abi:bar][abi:foo]()", tmp);
}
+// Test one Rust symbol to exercise Demangle's delegation path. Rust demangling
+// itself is more thoroughly tested in demangle_rust_test.cc.
+TEST(Demangle, DelegatesToDemangleRustSymbolEncoding) {
+ char tmp[80];
+
+ EXPECT_TRUE(Demangle("_RNvC8my_crate7my_func", tmp, sizeof(tmp)));
+ EXPECT_STREQ("my_crate::my_func", tmp);
+}
+
// Tests that verify that Demangle footprint is within some limit.
// They are not to be run under sanitizers as the sanitizers increase
// stack consumption by about 4x.
diff --git a/yass/third_party/abseil-cpp/absl/functional/any_invocable.h b/yass/third_party/abseil-cpp/absl/functional/any_invocable.h
index 68d882532e..bc980731b4 100644
--- a/yass/third_party/abseil-cpp/absl/functional/any_invocable.h
+++ b/yass/third_party/abseil-cpp/absl/functional/any_invocable.h
@@ -98,9 +98,9 @@ ABSL_NAMESPACE_BEGIN
// `AnyInvocable` also properly respects `const` qualifiers, reference
// qualifiers, and the `noexcept` specification (only in C++ 17 and beyond) as
// part of the user-specified function type (e.g.
-// `AnyInvocable`). These qualifiers will be applied to
-// the `AnyInvocable` object's `operator()`, and the underlying invocable must
-// be compatible with those qualifiers.
+// `AnyInvocable`). These qualifiers will be applied
+// to the `AnyInvocable` object's `operator()`, and the underlying invocable
+// must be compatible with those qualifiers.
//
// Comparison of const and non-const function types:
//
@@ -151,6 +151,12 @@ ABSL_NAMESPACE_BEGIN
//
// Attempting to call `absl::AnyInvocable` multiple times in such a case
// results in undefined behavior.
+//
+// Invoking an empty `absl::AnyInvocable` results in undefined behavior:
+//
+// // Create an empty instance using the default constructor.
+// AnyInvocable empty;
+// empty(); // WARNING: Undefined behavior!
template
class AnyInvocable : private internal_any_invocable::Impl {
private:
@@ -167,6 +173,7 @@ class AnyInvocable : private internal_any_invocable::Impl {
// Constructors
// Constructs the `AnyInvocable` in an empty state.
+ // Invoking it results in undefined behavior.
AnyInvocable() noexcept = default;
AnyInvocable(std::nullptr_t) noexcept {} // NOLINT
@@ -277,6 +284,8 @@ class AnyInvocable : private internal_any_invocable::Impl {
// In other words:
// std::function f; // empty
// absl::AnyInvocable a = std::move(f); // not empty
+ //
+ // Invoking an empty `AnyInvocable` results in undefined behavior.
explicit operator bool() const noexcept { return this->HasValue(); }
// Invokes the target object of `*this`. `*this` must not be empty.
diff --git a/yass/third_party/abseil-cpp/absl/functional/internal/any_invocable.h b/yass/third_party/abseil-cpp/absl/functional/internal/any_invocable.h
index b04436d1d6..ce58fd8cab 100644
--- a/yass/third_party/abseil-cpp/absl/functional/internal/any_invocable.h
+++ b/yass/third_party/abseil-cpp/absl/functional/internal/any_invocable.h
@@ -19,11 +19,11 @@
////////////////////////////////////////////////////////////////////////////////
// //
-// This implementation of the proposed `any_invocable` uses an approach that //
-// chooses between local storage and remote storage for the contained target //
-// object based on the target object's size, alignment requirements, and //
-// whether or not it has a nothrow move constructor. Additional optimizations //
-// are performed when the object is a trivially copyable type [basic.types]. //
+// This implementation chooses between local storage and remote storage for //
+// the contained target object based on the target object's size, alignment //
+// requirements, and whether or not it has a nothrow move constructor. //
+// Additional optimizations are performed when the object is a trivially //
+// copyable type [basic.types]. //
// //
// There are three datamembers per `AnyInvocable` instance //
// //
@@ -39,7 +39,7 @@
// target object, directly returning the result. //
// //
// When in the logically empty state, the manager function is an empty //
-// function and the invoker function is one that would be undefined-behavior //
+// function and the invoker function is one that would be undefined behavior //
// to call. //
// //
// An additional optimization is performed when converting from one //
diff --git a/yass/third_party/abseil-cpp/absl/functional/overload.h b/yass/third_party/abseil-cpp/absl/functional/overload.h
index 732795fc9e..34ffa689a4 100644
--- a/yass/third_party/abseil-cpp/absl/functional/overload.h
+++ b/yass/third_party/abseil-cpp/absl/functional/overload.h
@@ -16,33 +16,26 @@
// File: overload.h
// -----------------------------------------------------------------------------
//
-// `absl::Overload()` returns a functor that provides overloads based on the
-// functors passed to it.
+// `absl::Overload` is a functor that provides overloads based on the functors
+// with which it is created. This can, for example, be used to locally define an
+// anonymous visitor type for `std::visit` inside a function using lambdas.
+//
// Before using this function, consider whether named function overloads would
// be a better design.
-// One use case for this is locally defining visitors for `std::visit` inside a
-// function using lambdas.
-
-// Example: Using `absl::Overload` to define a visitor for `std::variant`.
-//
-// std::variant v(int{1});
-//
-// assert(std::visit(absl::Overload(
-// [](int) -> absl::string_view { return "int"; },
-// [](const std::string&) -> absl::string_view {
-// return "string";
-// },
-// [](double) -> absl::string_view { return "double"; }),
-// v) == "int");
-//
-// One of the lambda may specify overload for several types via generic lambda.
-//
-// absl::variant v(int32_t{1});
-// assert(std::visit(absl::Overload(
-// [](const std::string& s) { return s.size(); },
-// [](const auto& s) { return sizeof(s); }), v) == 4);
//
// Note: absl::Overload requires C++17.
+//
+// Example:
+//
+// std::variant v(int32_t{1});
+// const size_t result =
+// std::visit(absl::Overload{
+// [](const std::string& s) { return s.size(); },
+// [](const auto& s) { return sizeof(s); },
+// },
+// v);
+// assert(result == 4);
+//
#ifndef ABSL_FUNCTIONAL_OVERLOAD_H_
#define ABSL_FUNCTIONAL_OVERLOAD_H_
@@ -56,14 +49,30 @@ ABSL_NAMESPACE_BEGIN
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-template
-auto Overload(T&&... ts) {
- struct OverloadImpl : absl::remove_cvref_t... {
- using absl::remove_cvref_t::operator()...;
- };
- return OverloadImpl{std::forward(ts)...};
-}
+template
+struct Overload final : T... {
+ using T::operator()...;
+
+ // For historical reasons we want to support use that looks like a function
+ // call:
+ //
+ // absl::Overload(lambda_1, lambda_2)
+ //
+ // This works automatically in C++20 because we have support for parenthesized
+ // aggregate initialization. Before then we must provide a constructor that
+ // makes this work.
+ //
+ explicit Overload(T... ts) : T(std::move(ts))... {}
+};
+
+// Before C++20, which added support for CTAD for aggregate types, we must also
+// teach the compiler how to deduce the template arguments for Overload.
+//
+template
+Overload(T...) -> Overload;
+
#else
+
namespace functional_internal {
template
constexpr bool kDependentFalse = false;
@@ -76,6 +85,7 @@ auto Overload(T&&...) {
}
#endif
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/yass/third_party/abseil-cpp/absl/functional/overload_test.cc b/yass/third_party/abseil-cpp/absl/functional/overload_test.cc
index 040bf83fcd..a2e87674c6 100644
--- a/yass/third_party/abseil-cpp/absl/functional/overload_test.cc
+++ b/yass/third_party/abseil-cpp/absl/functional/overload_test.cc
@@ -31,14 +31,15 @@
namespace {
TEST(OverloadTest, DispatchConsidersTypeWithAutoFallback) {
- auto overloaded = absl::Overload(
- [](int v) -> std::string { return absl::StrCat("int ", v); }, //
- [](double v) -> std::string { return absl::StrCat("double ", v); }, //
- [](const char* v) -> std::string { //
- return absl::StrCat("const char* ", v); //
- }, //
- [](auto v) -> std::string { return absl::StrCat("auto ", v); } //
- );
+ auto overloaded = absl::Overload{
+ [](int v) -> std::string { return absl::StrCat("int ", v); },
+ [](double v) -> std::string { return absl::StrCat("double ", v); },
+ [](const char* v) -> std::string {
+ return absl::StrCat("const char* ", v);
+ },
+ [](auto v) -> std::string { return absl::StrCat("auto ", v); },
+ };
+
EXPECT_EQ("int 1", overloaded(1));
EXPECT_EQ("double 2.5", overloaded(2.5));
EXPECT_EQ("const char* hello", overloaded("hello"));
@@ -46,32 +47,34 @@ TEST(OverloadTest, DispatchConsidersTypeWithAutoFallback) {
}
TEST(OverloadTest, DispatchConsidersNumberOfArguments) {
- auto overloaded = absl::Overload( //
- [](int a) { return a + 1; }, //
- [](int a, int b) { return a * b; }, //
- []() -> absl::string_view { return "none"; } //
- );
+ auto overloaded = absl::Overload{
+ [](int a) { return a + 1; },
+ [](int a, int b) { return a * b; },
+ []() -> absl::string_view { return "none"; },
+ };
+
EXPECT_EQ(3, overloaded(2));
EXPECT_EQ(21, overloaded(3, 7));
EXPECT_EQ("none", overloaded());
}
TEST(OverloadTest, SupportsConstantEvaluation) {
- auto overloaded = absl::Overload( //
- [](int a) { return a + 1; }, //
- [](int a, int b) { return a * b; }, //
- []() -> absl::string_view { return "none"; } //
- );
+ auto overloaded = absl::Overload{
+ [](int a) { return a + 1; },
+ [](int a, int b) { return a * b; },
+ []() -> absl::string_view { return "none"; },
+ };
+
static_assert(overloaded() == "none");
static_assert(overloaded(2) == 3);
static_assert(overloaded(3, 7) == 21);
}
TEST(OverloadTest, PropogatesDefaults) {
- auto overloaded = absl::Overload( //
- [](int a, int b = 5) { return a * b; }, //
- [](double c) { return c; } //
- );
+ auto overloaded = absl::Overload{
+ [](int a, int b = 5) { return a * b; },
+ [](double c) { return c; },
+ };
EXPECT_EQ(21, overloaded(3, 7));
EXPECT_EQ(35, overloaded(7));
@@ -79,53 +82,59 @@ TEST(OverloadTest, PropogatesDefaults) {
}
TEST(OverloadTest, AmbiguousWithDefaultsNotInvocable) {
- auto overloaded = absl::Overload( //
- [](int a, int b = 5) { return a * b; }, //
- [](int c) { return c; } //
- );
+ auto overloaded = absl::Overload{
+ [](int a, int b = 5) { return a * b; },
+ [](int c) { return c; },
+ };
+
static_assert(!std::is_invocable_v);
static_assert(std::is_invocable_v);
}
TEST(OverloadTest, AmbiguousDuplicatesNotInvocable) {
- auto overloaded = absl::Overload( //
- [](int a) { return a; }, //
- [](int c) { return c; } //
- );
+ auto overloaded = absl::Overload{
+ [](int a) { return a; },
+ [](int c) { return c; },
+ };
+
static_assert(!std::is_invocable_v);
}
TEST(OverloadTest, AmbiguousConversionNotInvocable) {
- auto overloaded = absl::Overload( //
- [](uint16_t a) { return a; }, //
- [](uint64_t c) { return c; } //
- );
+ auto overloaded = absl::Overload{
+ [](uint16_t a) { return a; },
+ [](uint64_t c) { return c; },
+ };
+
static_assert(!std::is_invocable_v);
}
TEST(OverloadTest, AmbiguousConversionWithAutoNotInvocable) {
- auto overloaded = absl::Overload( //
- [](auto a) { return a; }, //
- [](auto c) { return c; } //
- );
+ auto overloaded = absl::Overload{
+ [](auto a) { return a; },
+ [](auto c) { return c; },
+ };
+
static_assert(!std::is_invocable_v);
}
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
TEST(OverloadTest, AmbiguousConversionWithAutoAndTemplateNotInvocable) {
- auto overloaded = absl::Overload( //
- [](auto a) { return a; }, //
- [](T c) { return c; } //
- );
+ auto overloaded = absl::Overload{
+ [](auto a) { return a; },
+ [](T c) { return c; },
+ };
+
static_assert(!std::is_invocable_v);
}
TEST(OverloadTest, DispatchConsidersTypeWithTemplateFallback) {
- auto overloaded = absl::Overload( //
- [](int a) { return a; }, //
- [](T c) { return c * 2; } //
- );
+ auto overloaded = absl::Overload{
+ [](int a) { return a; },
+ [](T c) { return c * 2; },
+ };
+
EXPECT_EQ(7, overloaded(7));
EXPECT_EQ(14.0, overloaded(7.0));
}
@@ -133,20 +142,22 @@ TEST(OverloadTest, DispatchConsidersTypeWithTemplateFallback) {
#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
TEST(OverloadTest, DispatchConsidersSfinae) {
- auto overloaded = absl::Overload( //
- [](auto a) -> decltype(a + 1) { return a + 1; } //
- );
+ auto overloaded = absl::Overload{
+ [](auto a) -> decltype(a + 1) { return a + 1; },
+ };
+
static_assert(std::is_invocable_v);
static_assert(!std::is_invocable_v);
}
TEST(OverloadTest, VariantVisitDispatchesCorrectly) {
absl::variant v(1);
- auto overloaded = absl::Overload(
- [](int) -> absl::string_view { return "int"; }, //
- [](double) -> absl::string_view { return "double"; }, //
- [](const std::string&) -> absl::string_view { return "string"; } //
- );
+ auto overloaded = absl::Overload{
+ [](int) -> absl::string_view { return "int"; },
+ [](double) -> absl::string_view { return "double"; },
+ [](const std::string&) -> absl::string_view { return "string"; },
+ };
+
EXPECT_EQ("int", absl::visit(overloaded, v));
v = 1.1;
EXPECT_EQ("double", absl::visit(overloaded, v));
@@ -156,10 +167,11 @@ TEST(OverloadTest, VariantVisitDispatchesCorrectly) {
TEST(OverloadTest, VariantVisitWithAutoFallbackDispatchesCorrectly) {
absl::variant v(int32_t{1});
- auto overloaded = absl::Overload(
- [](const std::string& s) { return s.size(); }, //
- [](const auto& s) { return sizeof(s); } //
- );
+ auto overloaded = absl::Overload{
+ [](const std::string& s) { return s.size(); },
+ [](const auto& s) { return sizeof(s); },
+ };
+
EXPECT_EQ(4, absl::visit(overloaded, v));
v = int64_t{1};
EXPECT_EQ(8, absl::visit(overloaded, v));
@@ -167,6 +179,23 @@ TEST(OverloadTest, VariantVisitWithAutoFallbackDispatchesCorrectly) {
EXPECT_EQ(5, absl::visit(overloaded, v));
}
+// This API used to be exported as a function, so it should also work fine to
+// use parantheses when initializing it.
+TEST(OverloadTest, UseWithParentheses) {
+ const auto overloaded =
+ absl::Overload([](const std::string& s) { return s.size(); },
+ [](const auto& s) { return sizeof(s); });
+
+ absl::variant v(int32_t{1});
+ EXPECT_EQ(4, absl::visit(overloaded, v));
+
+ v = int64_t{1};
+ EXPECT_EQ(8, absl::visit(overloaded, v));
+
+ v = std::string("hello");
+ EXPECT_EQ(5, absl::visit(overloaded, v));
+}
+
} // namespace
#endif
diff --git a/yass/third_party/abseil-cpp/absl/log/BUILD.bazel b/yass/third_party/abseil-cpp/absl/log/BUILD.bazel
index 0f17239804..dd192a10ad 100644
--- a/yass/third_party/abseil-cpp/absl/log/BUILD.bazel
+++ b/yass/third_party/abseil-cpp/absl/log/BUILD.bazel
@@ -664,6 +664,7 @@ cc_test(
":log_entry",
":log_sink",
":log_sink_registry",
+ ":vlog_is_on",
"//absl/base:core_headers",
"//absl/base:log_severity",
"//absl/flags:flag",
diff --git a/yass/third_party/abseil-cpp/absl/log/CMakeLists.txt b/yass/third_party/abseil-cpp/absl/log/CMakeLists.txt
index acf89720b1..59aa19f3bd 100644
--- a/yass/third_party/abseil-cpp/absl/log/CMakeLists.txt
+++ b/yass/third_party/abseil-cpp/absl/log/CMakeLists.txt
@@ -290,6 +290,7 @@ absl_cc_library(
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::core_headers
absl::log_internal_message
absl::log_internal_nullstream
absl::log_severity
diff --git a/yass/third_party/abseil-cpp/absl/log/internal/BUILD.bazel b/yass/third_party/abseil-cpp/absl/log/internal/BUILD.bazel
index 21958f7e07..2dbf337a14 100644
--- a/yass/third_party/abseil-cpp/absl/log/internal/BUILD.bazel
+++ b/yass/third_party/abseil-cpp/absl/log/internal/BUILD.bazel
@@ -266,6 +266,7 @@ cc_library(
deps = [
":log_message",
":nullstream",
+ "//absl/base:core_headers",
"//absl/base:log_severity",
],
)
diff --git a/yass/third_party/abseil-cpp/absl/log/internal/check_op.h b/yass/third_party/abseil-cpp/absl/log/internal/check_op.h
index 53760fd527..0d24f4d157 100644
--- a/yass/third_party/abseil-cpp/absl/log/internal/check_op.h
+++ b/yass/third_party/abseil-cpp/absl/log/internal/check_op.h
@@ -58,12 +58,13 @@
#endif
#define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val1_text, val2, val2_text) \
- while (::std::string* absl_log_internal_check_op_result = \
- ::absl::log_internal::name##Impl( \
- ::absl::log_internal::GetReferenceableValue(val1), \
- ::absl::log_internal::GetReferenceableValue(val2), \
- ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \
- val1_text " " #op " " val2_text))) \
+ while (::std::string* absl_log_internal_check_op_result \
+ ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG = \
+ ::absl::log_internal::name##Impl( \
+ ::absl::log_internal::GetReferenceableValue(val1), \
+ ::absl::log_internal::GetReferenceableValue(val2), \
+ ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \
+ val1_text " " #op " " val2_text))) \
ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \
ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_op_result).InternalStream()
#define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \
diff --git a/yass/third_party/abseil-cpp/absl/log/internal/strip.h b/yass/third_party/abseil-cpp/absl/log/internal/strip.h
index dfde578667..3e5501040c 100644
--- a/yass/third_party/abseil-cpp/absl/log/internal/strip.h
+++ b/yass/third_party/abseil-cpp/absl/log/internal/strip.h
@@ -20,6 +20,7 @@
#ifndef ABSL_LOG_INTERNAL_STRIP_H_
#define ABSL_LOG_INTERNAL_STRIP_H_
+#include "absl/base/attributes.h" // IWYU pragma: keep
#include "absl/base/log_severity.h"
#include "absl/log/internal/log_message.h"
#include "absl/log/internal/nullstream.h"
@@ -29,6 +30,16 @@
// of defines comes in three flavors: vanilla, plus two variants that strip some
// logging in subtly different ways for subtly different reasons (see below).
#if defined(STRIP_LOG) && STRIP_LOG
+
+// Attribute for marking variables used in implementation details of logging
+// macros as unused, but only when `STRIP_LOG` is defined.
+// With `STRIP_LOG` on, not marking them triggers `-Wunused-but-set-variable`,
+// With `STRIP_LOG` off, marking them triggers `-Wused-but-marked-unused`.
+//
+// TODO(b/290784225): Replace this macro with attribute [[maybe_unused]] when
+// Abseil stops supporting C++14.
+#define ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG ABSL_ATTRIBUTE_UNUSED
+
#define ABSL_LOGGING_INTERNAL_LOG_INFO ::absl::log_internal::NullStream()
#define ABSL_LOGGING_INTERNAL_LOG_WARNING ::absl::log_internal::NullStream()
#define ABSL_LOGGING_INTERNAL_LOG_ERROR ::absl::log_internal::NullStream()
@@ -48,7 +59,11 @@
#define ABSL_LOG_INTERNAL_CHECK(failure_message) ABSL_LOGGING_INTERNAL_LOG_FATAL
#define ABSL_LOG_INTERNAL_QCHECK(failure_message) \
ABSL_LOGGING_INTERNAL_LOG_QFATAL
+
#else // !defined(STRIP_LOG) || !STRIP_LOG
+
+#define ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG
+
#define ABSL_LOGGING_INTERNAL_LOG_INFO \
::absl::log_internal::LogMessage( \
__FILE__, __LINE__, ::absl::log_internal::LogMessage::InfoTag{})
diff --git a/yass/third_party/abseil-cpp/absl/log/log_benchmark.cc b/yass/third_party/abseil-cpp/absl/log/log_benchmark.cc
index 45d9a5d6fd..60c0fd637e 100644
--- a/yass/third_party/abseil-cpp/absl/log/log_benchmark.cc
+++ b/yass/third_party/abseil-cpp/absl/log/log_benchmark.cc
@@ -17,10 +17,12 @@
#include "absl/flags/flag.h"
#include "absl/log/check.h"
#include "absl/log/globals.h"
+#include "absl/log/internal/flags.h"
#include "absl/log/log.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/log/log_sink_registry.h"
+#include "absl/log/vlog_is_on.h"
#include "benchmark/benchmark.h"
namespace {
@@ -93,5 +95,70 @@ static void BM_EnabledLogOverhead(benchmark::State& state) {
}
BENCHMARK(BM_EnabledLogOverhead);
+static void BM_VlogIsOnOverhead(benchmark::State& state) {
+ // It would make sense to do this only when state.thread_index == 0,
+ // but thread_index is an int on some platforms (e.g. Android) and a
+ // function returning an int on others. So we just do it on all threads.
+ // TODO(b/152609127): set only if thread_index == 0.
+ absl::SetFlag(&FLAGS_v, 0);
+
+ while (state.KeepRunningBatch(10)) {
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 1
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 2
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 3
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 4
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 5
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 6
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 7
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 8
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 9
+ benchmark::DoNotOptimize(VLOG_IS_ON(0)); // 10
+ }
+}
+BENCHMARK(BM_VlogIsOnOverhead)->ThreadRange(1, 64);
+
+static void BM_VlogIsNotOnOverhead(benchmark::State& state) {
+ // It would make sense to do this only when state.thread_index == 0,
+ // but thread_index is an int on some platforms (e.g. Android) and a
+ // function returning an int on others. So we just do it on all threads.
+ // TODO(b/152609127): set only if thread_index == 0.
+ absl::SetFlag(&FLAGS_v, 0);
+
+ while (state.KeepRunningBatch(10)) {
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 1
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 2
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 3
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 4
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 5
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 6
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 7
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 8
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 9
+ benchmark::DoNotOptimize(VLOG_IS_ON(1)); // 10
+ }
+}
+BENCHMARK(BM_VlogIsNotOnOverhead)->ThreadRange(1, 64);
+
+static void BM_LogEveryNOverhead(benchmark::State& state) {
+ absl::ScopedStderrThreshold disable_stderr_logging(
+ absl::LogSeverityAtLeast::kInfinity);
+ absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfinity);
+ ABSL_ATTRIBUTE_UNUSED NullLogSink null_sink;
+
+ while (state.KeepRunningBatch(10)) {
+ LOG_EVERY_N_SEC(INFO, 10);
+ LOG_EVERY_N_SEC(INFO, 20);
+ LOG_EVERY_N_SEC(INFO, 30);
+ LOG_EVERY_N_SEC(INFO, 40);
+ LOG_EVERY_N_SEC(INFO, 50);
+ LOG_EVERY_N_SEC(INFO, 60);
+ LOG_EVERY_N_SEC(INFO, 70);
+ LOG_EVERY_N_SEC(INFO, 80);
+ LOG_EVERY_N_SEC(INFO, 90);
+ LOG_EVERY_N_SEC(INFO, 100);
+ }
+}
+BENCHMARK(BM_LogEveryNOverhead)->ThreadRange(1, 64);
+
} // namespace
diff --git a/yass/third_party/abseil-cpp/absl/numeric/BUILD.bazel b/yass/third_party/abseil-cpp/absl/numeric/BUILD.bazel
index 41c015db89..f202c6e06f 100644
--- a/yass/third_party/abseil-cpp/absl/numeric/BUILD.bazel
+++ b/yass/third_party/abseil-cpp/absl/numeric/BUILD.bazel
@@ -89,6 +89,7 @@ cc_library(
":bits",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/types:compare",
],
)
@@ -107,6 +108,7 @@ cc_test(
"//absl/hash:hash_testing",
"//absl/meta:type_traits",
"//absl/strings",
+ "//absl/types:compare",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
diff --git a/yass/third_party/abseil-cpp/absl/numeric/CMakeLists.txt b/yass/third_party/abseil-cpp/absl/numeric/CMakeLists.txt
index 7181b91ab5..da3b6efe61 100644
--- a/yass/third_party/abseil-cpp/absl/numeric/CMakeLists.txt
+++ b/yass/third_party/abseil-cpp/absl/numeric/CMakeLists.txt
@@ -53,6 +53,7 @@ absl_cc_library(
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::compare
absl::config
absl::core_headers
absl::bits
@@ -70,6 +71,7 @@ absl_cc_test(
DEPS
absl::int128
absl::base
+ absl::compare
absl::hash_testing
absl::type_traits
absl::strings
diff --git a/yass/third_party/abseil-cpp/absl/numeric/int128.h b/yass/third_party/abseil-cpp/absl/numeric/int128.h
index a17d0e1b64..5a067d17b3 100644
--- a/yass/third_party/abseil-cpp/absl/numeric/int128.h
+++ b/yass/third_party/abseil-cpp/absl/numeric/int128.h
@@ -38,6 +38,7 @@
#include "absl/base/config.h"
#include "absl/base/macros.h"
#include "absl/base/port.h"
+#include "absl/types/compare.h"
#if defined(_MSC_VER)
// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is
@@ -269,7 +270,9 @@ class numeric_limits {
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
+ ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
static constexpr float_denorm_style has_denorm = denorm_absent;
+ ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
static constexpr bool has_denorm_loss = false;
static constexpr float_round_style round_style = round_toward_zero;
static constexpr bool is_iec559 = false;
@@ -512,7 +515,9 @@ class numeric_limits {
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
+ ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
static constexpr float_denorm_style has_denorm = denorm_absent;
+ ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
static constexpr bool has_denorm_loss = false;
static constexpr float_round_style round_style = round_toward_zero;
static constexpr bool is_iec559 = false;
@@ -819,6 +824,36 @@ constexpr bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); }
constexpr bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); }
+#ifdef __cpp_impl_three_way_comparison
+constexpr absl::strong_ordering operator<=>(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ if (auto lhs_128 = static_cast(lhs),
+ rhs_128 = static_cast(rhs);
+ lhs_128 < rhs_128) {
+ return absl::strong_ordering::less;
+ } else if (lhs_128 > rhs_128) {
+ return absl::strong_ordering::greater;
+ } else {
+ return absl::strong_ordering::equal;
+ }
+#else
+ if (uint64_t lhs_high = Uint128High64(lhs), rhs_high = Uint128High64(rhs);
+ lhs_high < rhs_high) {
+ return absl::strong_ordering::less;
+ } else if (lhs_high > rhs_high) {
+ return absl::strong_ordering::greater;
+ } else if (uint64_t lhs_low = Uint128Low64(lhs), rhs_low = Uint128Low64(rhs);
+ lhs_low < rhs_low) {
+ return absl::strong_ordering::less;
+ } else if (lhs_low > rhs_low) {
+ return absl::strong_ordering::greater;
+ } else {
+ return absl::strong_ordering::equal;
+ }
+#endif
+}
+#endif
+
// Unary operators.
constexpr inline uint128 operator+(uint128 val) { return val; }
diff --git a/yass/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc b/yass/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc
index 6f1ac64414..51e4b9d485 100644
--- a/yass/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc
+++ b/yass/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc
@@ -220,6 +220,20 @@ constexpr bool operator>=(int128 lhs, int128 rhs) {
return static_cast<__int128>(lhs) >= static_cast<__int128>(rhs);
}
+#ifdef __cpp_impl_three_way_comparison
+constexpr absl::strong_ordering operator<=>(int128 lhs, int128 rhs) {
+ if (auto lhs_128 = static_cast<__int128>(lhs),
+ rhs_128 = static_cast<__int128>(rhs);
+ lhs_128 < rhs_128) {
+ return absl::strong_ordering::less;
+ } else if (lhs_128 > rhs_128) {
+ return absl::strong_ordering::greater;
+ } else {
+ return absl::strong_ordering::equal;
+ }
+}
+#endif
+
// Unary operators.
constexpr int128 operator-(int128 v) { return -static_cast<__int128>(v); }
diff --git a/yass/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc b/yass/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc
index 6f5d83777c..195b7452ea 100644
--- a/yass/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc
+++ b/yass/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc
@@ -186,6 +186,24 @@ constexpr bool operator<=(int128 lhs, int128 rhs) { return !(lhs > rhs); }
constexpr bool operator>=(int128 lhs, int128 rhs) { return !(lhs < rhs); }
+#ifdef __cpp_impl_three_way_comparison
+constexpr absl::strong_ordering operator<=>(int128 lhs, int128 rhs) {
+ if (int64_t lhs_high = Int128High64(lhs), rhs_high = Int128High64(rhs);
+ lhs_high < rhs_high) {
+ return absl::strong_ordering::less;
+ } else if (lhs_high > rhs_high) {
+ return absl::strong_ordering::greater;
+ } else if (uint64_t lhs_low = Uint128Low64(lhs), rhs_low = Uint128Low64(rhs);
+ lhs_low < rhs_low) {
+ return absl::strong_ordering::less;
+ } else if (lhs_low > rhs_low) {
+ return absl::strong_ordering::greater;
+ } else {
+ return absl::strong_ordering::equal;
+ }
+}
+#endif
+
// Unary operators.
constexpr int128 operator-(int128 v) {
diff --git a/yass/third_party/abseil-cpp/absl/numeric/int128_test.cc b/yass/third_party/abseil-cpp/absl/numeric/int128_test.cc
index f17a5f6b29..3f16e054c6 100644
--- a/yass/third_party/abseil-cpp/absl/numeric/int128_test.cc
+++ b/yass/third_party/abseil-cpp/absl/numeric/int128_test.cc
@@ -25,6 +25,7 @@
#include "absl/base/internal/cycleclock.h"
#include "absl/hash/hash_testing.h"
#include "absl/meta/type_traits.h"
+#include "absl/types/compare.h"
#define MAKE_INT128(HI, LO) absl::MakeInt128(static_cast(HI), LO)
@@ -784,6 +785,13 @@ TEST(Int128, ComparisonTest) {
EXPECT_FALSE(pair.smaller >= pair.larger); // NOLINT(readability/check)
EXPECT_TRUE(pair.smaller >= pair.smaller); // NOLINT(readability/check)
EXPECT_TRUE(pair.larger >= pair.larger); // NOLINT(readability/check)
+
+#ifdef __cpp_impl_three_way_comparison
+ EXPECT_EQ(pair.smaller <=> pair.larger, absl::strong_ordering::less);
+ EXPECT_EQ(pair.larger <=> pair.smaller, absl::strong_ordering::greater);
+ EXPECT_EQ(pair.smaller <=> pair.smaller, absl::strong_ordering::equal);
+ EXPECT_EQ(pair.larger <=> pair.larger, absl::strong_ordering::equal);
+#endif
}
}
diff --git a/yass/third_party/abseil-cpp/absl/numeric/internal/bits.h b/yass/third_party/abseil-cpp/absl/numeric/internal/bits.h
index bfef06bce1..0917464d6a 100644
--- a/yass/third_party/abseil-cpp/absl/numeric/internal/bits.h
+++ b/yass/third_party/abseil-cpp/absl/numeric/internal/bits.h
@@ -167,7 +167,9 @@ CountLeadingZeroes32(uint32_t x) {
ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
CountLeadingZeroes16(uint16_t x) {
-#if ABSL_HAVE_BUILTIN(__builtin_clzs)
+#if ABSL_HAVE_BUILTIN(__builtin_clzg)
+ return x == 0 ? 16 : __builtin_clzg(x);
+#elif ABSL_HAVE_BUILTIN(__builtin_clzs)
static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int)
"__builtin_clzs does not take 16-bit arg");
return x == 0 ? 16 : __builtin_clzs(x);
@@ -303,7 +305,9 @@ CountTrailingZeroesNonzero64(uint64_t x) {
ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
CountTrailingZeroesNonzero16(uint16_t x) {
-#if ABSL_HAVE_BUILTIN(__builtin_ctzs)
+#if ABSL_HAVE_BUILTIN(__builtin_ctzg)
+ return __builtin_ctzg(x);
+#elif ABSL_HAVE_BUILTIN(__builtin_ctzs)
static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int)
"__builtin_ctzs does not take 16-bit arg");
return __builtin_ctzs(x);
diff --git a/yass/third_party/abseil-cpp/absl/random/distributions.h b/yass/third_party/abseil-cpp/absl/random/distributions.h
index 16b76eeaaf..d62f7f3b96 100644
--- a/yass/third_party/abseil-cpp/absl/random/distributions.h
+++ b/yass/third_party/abseil-cpp/absl/random/distributions.h
@@ -32,8 +32,8 @@
// continuously and independently at a constant average rate
// * `absl::Gaussian` (also known as "normal distributions") for continuous
// distributions using an associated quadratic function
-// * `absl::LogUniform` for continuous uniform distributions where the log
-// to the given base of all values is uniform
+// * `absl::LogUniform` for discrete distributions where the log to the given
+// base of all values is uniform
// * `absl::Poisson` for discrete probability distributions that express the
// probability of a given number of events occurring within a fixed interval
// * `absl::Zipf` for discrete probability distributions commonly used for
diff --git a/yass/third_party/abseil-cpp/absl/status/BUILD.bazel b/yass/third_party/abseil-cpp/absl/status/BUILD.bazel
index 981b37fda7..8822e0f6e9 100644
--- a/yass/third_party/abseil-cpp/absl/status/BUILD.bazel
+++ b/yass/third_party/abseil-cpp/absl/status/BUILD.bazel
@@ -118,6 +118,7 @@ cc_test(
srcs = ["statusor_test.cc"],
deps = [
":status",
+ ":status_matchers",
":statusor",
"//absl/base",
"//absl/memory",
@@ -129,3 +130,38 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "status_matchers",
+ testonly = 1,
+ srcs = [
+ "internal/status_matchers.cc",
+ "internal/status_matchers.h",
+ ],
+ hdrs = ["status_matchers.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":status",
+ ":statusor",
+ "//absl/base:config",
+ "//absl/strings:string_view",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_test(
+ name = "status_matchers_test",
+ size = "small",
+ srcs = ["status_matchers_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":status",
+ ":status_matchers",
+ ":statusor",
+ "//absl/strings",
+ "@com_google_googletest//:gtest",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/yass/third_party/abseil-cpp/absl/status/CMakeLists.txt b/yass/third_party/abseil-cpp/absl/status/CMakeLists.txt
index 00415ab94d..24c01e7ac9 100644
--- a/yass/third_party/abseil-cpp/absl/status/CMakeLists.txt
+++ b/yass/third_party/abseil-cpp/absl/status/CMakeLists.txt
@@ -98,7 +98,45 @@ absl_cc_test(
${ABSL_TEST_COPTS}
DEPS
absl::status
+ absl::status_matchers
absl::statusor
absl::strings
GTest::gmock_main
)
+
+absl_cc_library(
+ NAME
+ status_matchers
+ HDRS
+ "status_matchers.h"
+ SRCS
+ "internal/status_matchers.h"
+ "internal/status_matchers.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::status
+ absl::statusor
+ absl::strings
+ GTest::gmock
+ GTest::gtest
+ PUBLIC
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ status_matchers_test
+ SRCS
+ "status_matchers_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::status
+ absl::statusor
+ absl::status_matchers
+ GTest::gmock_main
+)
diff --git a/yass/third_party/abseil-cpp/absl/status/internal/status_matchers.cc b/yass/third_party/abseil-cpp/absl/status/internal/status_matchers.cc
new file mode 100644
index 0000000000..908b70bbc4
--- /dev/null
+++ b/yass/third_party/abseil-cpp/absl/status/internal/status_matchers.cc
@@ -0,0 +1,68 @@
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: status_matchers.cc
+// -----------------------------------------------------------------------------
+
+#include "absl/status/internal/status_matchers.h"
+
+#include
+#include
+
+#include "gmock/gmock.h" // gmock_for_status_matchers.h
+#include "absl/base/config.h"
+#include "absl/status/status.h"
+
+namespace absl_testing {
+ABSL_NAMESPACE_BEGIN
+namespace status_internal {
+
+void StatusIsMatcherCommonImpl::DescribeTo(std::ostream* os) const {
+ *os << ", has a status code that ";
+ code_matcher_.DescribeTo(os);
+ *os << ", and has an error message that ";
+ message_matcher_.DescribeTo(os);
+}
+
+void StatusIsMatcherCommonImpl::DescribeNegationTo(std::ostream* os) const {
+ *os << ", or has a status code that ";
+ code_matcher_.DescribeNegationTo(os);
+ *os << ", or has an error message that ";
+ message_matcher_.DescribeNegationTo(os);
+}
+
+bool StatusIsMatcherCommonImpl::MatchAndExplain(
+ const ::absl::Status& status,
+ ::testing::MatchResultListener* result_listener) const {
+ ::testing::StringMatchResultListener inner_listener;
+ if (!code_matcher_.MatchAndExplain(status.code(), &inner_listener)) {
+ *result_listener << (inner_listener.str().empty()
+ ? "whose status code is wrong"
+ : "which has a status code " +
+ inner_listener.str());
+ return false;
+ }
+
+ if (!message_matcher_.Matches(std::string(status.message()))) {
+ *result_listener << "whose error message is wrong";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace status_internal
+ABSL_NAMESPACE_END
+} // namespace absl_testing
diff --git a/yass/third_party/abseil-cpp/absl/status/internal/status_matchers.h b/yass/third_party/abseil-cpp/absl/status/internal/status_matchers.h
new file mode 100644
index 0000000000..d11742b729
--- /dev/null
+++ b/yass/third_party/abseil-cpp/absl/status/internal/status_matchers.h
@@ -0,0 +1,246 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
+#define ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
+
+#include // NOLINT
+#include
+#include
+#include
+
+#include "gmock/gmock.h" // gmock_for_status_matchers.h
+#include "absl/base/config.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+
+namespace absl_testing {
+ABSL_NAMESPACE_BEGIN
+namespace status_internal {
+
+inline const absl::Status& GetStatus(const absl::Status& status) {
+ return status;
+}
+
+template
+inline const absl::Status& GetStatus(const absl::StatusOr& status) {
+ return status.status();
+}
+
+////////////////////////////////////////////////////////////
+// Implementation of IsOkAndHolds().
+
+// Monomorphic implementation of matcher IsOkAndHolds(m). StatusOrType is a
+// reference to StatusOr.
+template
+class IsOkAndHoldsMatcherImpl
+ : public ::testing::MatcherInterface {
+ public:
+ typedef
+ typename std::remove_reference::type::value_type value_type;
+
+ template
+ explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
+ : inner_matcher_(::testing::SafeMatcherCast(
+ std::forward(inner_matcher))) {}
+
+ void DescribeTo(std::ostream* os) const override {
+ *os << "is OK and has a value that ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "isn't OK or has a value that ";
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(
+ StatusOrType actual_value,
+ ::testing::MatchResultListener* result_listener) const override {
+ if (!actual_value.ok()) {
+ *result_listener << "which has status " << actual_value.status();
+ return false;
+ }
+
+ // Call through to the inner matcher.
+ return inner_matcher_.MatchAndExplain(*actual_value, result_listener);
+ }
+
+ private:
+ const ::testing::Matcher inner_matcher_;
+};
+
+// Implements IsOkAndHolds(m) as a polymorphic matcher.
+template
+class IsOkAndHoldsMatcher {
+ public:
+ explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
+ : inner_matcher_(std::forward(inner_matcher)) {}
+
+ // Converts this polymorphic matcher to a monomorphic matcher of the
+ // given type. StatusOrType can be either StatusOr or a
+ // reference to StatusOr.
+ template
+ operator ::testing::Matcher() const { // NOLINT
+ return ::testing::Matcher(
+ new IsOkAndHoldsMatcherImpl(inner_matcher_));
+ }
+
+ private:
+ const InnerMatcher inner_matcher_;
+};
+
+////////////////////////////////////////////////////////////
+// Implementation of StatusIs().
+
+// `StatusCode` is implicitly convertible from `int`, `absl::StatusCode`, and
+// is explicitly convertible to these types as well.
+//
+// We need this class because `absl::StatusCode` (as a scoped enum) is not
+// implicitly convertible to `int`. In order to handle use cases like
+// ```
+// StatusIs(Anyof(absl::StatusCode::kUnknown, absl::StatusCode::kCancelled))
+// ```
+// which uses polymorphic matchers, we need to unify the interfaces into
+// `Matcher`.
+class StatusCode {
+ public:
+ /*implicit*/ StatusCode(int code) // NOLINT
+ : code_(static_cast<::absl::StatusCode>(code)) {}
+ /*implicit*/ StatusCode(::absl::StatusCode code) : code_(code) {} // NOLINT
+
+ explicit operator int() const { return static_cast(code_); }
+
+ friend inline void PrintTo(const StatusCode& code, std::ostream* os) {
+ // TODO(b/321095377): Change this to print the status code as a string.
+ *os << static_cast(code);
+ }
+
+ private:
+ ::absl::StatusCode code_;
+};
+
+// Relational operators to handle matchers like Eq, Lt, etc..
+inline bool operator==(const StatusCode& lhs, const StatusCode& rhs) {
+ return static_cast(lhs) == static_cast(rhs);
+}
+inline bool operator!=(const StatusCode& lhs, const StatusCode& rhs) {
+ return static_cast(lhs) != static_cast(rhs);
+}
+
+// StatusIs() is a polymorphic matcher. This class is the common
+// implementation of it shared by all types T where StatusIs() can be
+// used as a Matcher.
+class StatusIsMatcherCommonImpl {
+ public:
+ StatusIsMatcherCommonImpl(
+ ::testing::Matcher code_matcher,
+ ::testing::Matcher message_matcher)
+ : code_matcher_(std::move(code_matcher)),
+ message_matcher_(std::move(message_matcher)) {}
+
+ void DescribeTo(std::ostream* os) const;
+
+ void DescribeNegationTo(std::ostream* os) const;
+
+ bool MatchAndExplain(const absl::Status& status,
+ ::testing::MatchResultListener* result_listener) const;
+
+ private:
+ const ::testing::Matcher code_matcher_;
+ const ::testing::Matcher message_matcher_;
+};
+
+// Monomorphic implementation of matcher StatusIs() for a given type
+// T. T can be Status, StatusOr<>, or a reference to either of them.
+template
+class MonoStatusIsMatcherImpl : public ::testing::MatcherInterface {
+ public:
+ explicit MonoStatusIsMatcherImpl(StatusIsMatcherCommonImpl common_impl)
+ : common_impl_(std::move(common_impl)) {}
+
+ void DescribeTo(std::ostream* os) const override {
+ common_impl_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const override {
+ common_impl_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(
+ T actual_value,
+ ::testing::MatchResultListener* result_listener) const override {
+ return common_impl_.MatchAndExplain(GetStatus(actual_value),
+ result_listener);
+ }
+
+ private:
+ StatusIsMatcherCommonImpl common_impl_;
+};
+
+// Implements StatusIs() as a polymorphic matcher.
+class StatusIsMatcher {
+ public:
+ template
+ StatusIsMatcher(StatusCodeMatcher&& code_matcher,
+ StatusMessageMatcher&& message_matcher)
+ : common_impl_(::testing::MatcherCast(
+ std::forward(code_matcher)),
+ ::testing::MatcherCast(
+ std::forward(message_matcher))) {
+ }
+
+ // Converts this polymorphic matcher to a monomorphic matcher of the
+ // given type. T can be StatusOr<>, Status, or a reference to
+ // either of them.
+ template
+ /*implicit*/ operator ::testing::Matcher() const { // NOLINT
+ return ::testing::Matcher(
+ new MonoStatusIsMatcherImpl(common_impl_));
+ }
+
+ private:
+ const StatusIsMatcherCommonImpl common_impl_;
+};
+
+// Monomorphic implementation of matcher IsOk() for a given type T.
+// T can be Status, StatusOr<>, or a reference to either of them.
+template
+class MonoIsOkMatcherImpl : public ::testing::MatcherInterface {
+ public:
+ void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "is not OK";
+ }
+ bool MatchAndExplain(T actual_value,
+ ::testing::MatchResultListener*) const override {
+ return GetStatus(actual_value).ok();
+ }
+};
+
+// Implements IsOk() as a polymorphic matcher.
+class IsOkMatcher {
+ public:
+ template
+ /*implicit*/ operator ::testing::Matcher() const { // NOLINT
+ return ::testing::Matcher(new MonoIsOkMatcherImpl());
+ }
+};
+
+} // namespace status_internal
+ABSL_NAMESPACE_END
+} // namespace absl_testing
+
+#endif // ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
diff --git a/yass/third_party/abseil-cpp/absl/status/status_matchers.h b/yass/third_party/abseil-cpp/absl/status/status_matchers.h
new file mode 100644
index 0000000000..837660eb06
--- /dev/null
+++ b/yass/third_party/abseil-cpp/absl/status/status_matchers.h
@@ -0,0 +1,118 @@
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: status_matchers.h
+// -----------------------------------------------------------------------------
+//
+// Testing utilities for working with `absl::Status` and `absl::StatusOr`.
+//
+// Defines the following utilities:
+//
+// ===============
+// `IsOkAndHolds(m)`
+// ===============
+//
+// This gMock matcher matches a StatusOr value whose status is OK
+// and whose inner value matches matcher m. Example:
+//
+// ```
+// using ::testing::MatchesRegex;
+// using ::absl_testing::IsOkAndHolds;
+// ...
+// absl::StatusOr maybe_name = ...;
+// EXPECT_THAT(maybe_name, IsOkAndHolds(MatchesRegex("John .*")));
+// ```
+//
+// ===============================
+// `StatusIs(status_code_matcher)`
+// ===============================
+//
+// This is a shorthand for
+// `StatusIs(status_code_matcher, ::testing::_)`
+// In other words, it's like the two-argument `StatusIs()`, except that it
+// ignores error message.
+//
+// ===============
+// `IsOk()`
+// ===============
+//
+// Matches an `absl::Status` or `absl::StatusOr` value whose status value
+// is `absl::StatusCode::kOk.`
+//
+// Equivalent to 'StatusIs(absl::StatusCode::kOk)'.
+// Example:
+// ```
+// using ::absl_testing::IsOk;
+// ...
+// absl::StatusOr maybe_name = ...;
+// EXPECT_THAT(maybe_name, IsOk());
+// Status s = ...;
+// EXPECT_THAT(s, IsOk());
+// ```
+
+#ifndef ABSL_STATUS_STATUS_MATCHERS_H_
+#define ABSL_STATUS_STATUS_MATCHERS_H_
+
+#include // NOLINT
+#include
+#include
+
+#include "gmock/gmock.h" // gmock_for_status_matchers.h
+#include "absl/base/config.h"
+#include "absl/status/internal/status_matchers.h"
+
+namespace absl_testing {
+ABSL_NAMESPACE_BEGIN
+
+// Returns a gMock matcher that matches a StatusOr<> whose status is
+// OK and whose value matches the inner matcher.
+template
+status_internal::IsOkAndHoldsMatcher::type>
+IsOkAndHolds(InnerMatcherT&& inner_matcher) {
+ return status_internal::IsOkAndHoldsMatcher<
+ typename std::decay::type>(
+ std::forward(inner_matcher));
+}
+
+// Returns a gMock matcher that matches a Status or StatusOr<> whose status code
+// matches code_matcher and whose error message matches message_matcher.
+// Typically, code_matcher will be an absl::StatusCode, e.g.
+//
+// StatusIs(absl::StatusCode::kInvalidArgument, "...")
+template