Update On Fri Jan 3 19:34:59 CET 2025

This commit is contained in:
github-action[bot]
2025-01-03 19:34:59 +01:00
parent c410a3a62a
commit 8cf2bd5d97
98 changed files with 6059 additions and 2599 deletions
+297 -612
View File
File diff suppressed because it is too large Load Diff
+5 -6
View File
@@ -14,17 +14,16 @@ await fs.write(f.fd, '**❤️ [Shiliew - A network app designed for those who
var s = await fs.readFile('getting-started.md', { encoding: 'utf8' })
await fs.write(f.fd, s)
var s = await fs.readFile('gui.md', { encoding: 'utf8' })
var s = await fs.readFile('server.md', { encoding: 'utf8' })
await fs.write(f.fd, s)
var s = await fs.readFile('client.md', { encoding: 'utf8' })
await fs.write(f.fd, s)
var s = await fs.readFile('other.md', { encoding: 'utf8' })
await fs.write(f.fd, s)
await fs.write(f.fd, '# CLI Documentation\n')
await fs.write(f.fd, 'Each subcommand has a `--example` parameter that can print the minimal example of usage\n')
var s = await $`brook mdpage`.text()
s = s.split("\n").filter(v => !v.startsWith("[")).join("\n").replace("```\n```", "```\nbrook --help\n```").split("\n").map(v => v.startsWith("**") && !v.startsWith("**Usage") ? "- " + v : v).join('\n')
s = s.replace("### help, h", "").replace("Shows a list of commands or help for one command", "").replaceAll("- **--help, -h**: show help", "")
await fs.write(f.fd, s)
var s = await fs.readFile('example.md', { encoding: 'utf8' })
await fs.write(f.fd, s)
var s = await fs.readFile('resources.md', { encoding: 'utf8' })
await fs.write(f.fd, s)
await fs.close(f.fd)
await $`markdown ../readme.md ./index.html`
+49 -143
View File
@@ -1,7 +1,5 @@
# Client
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`
## CLI
Before discussing the GUI client, let's first talk about the command line client `brook`. As we know, after you have deployed the server, you can use the command line client `brook` to create a local socks5 proxy or http proxy on your machine, and then configure it in your system proxy settings or in your browser to use this proxy. However:
@@ -13,106 +11,52 @@ For the specifics of socks5 and http proxy, you can read [this article](https://
## GUI
The GUI client does not use socks5 and http proxy mode, so there is no issue with some software not using the system proxy. Instead, it uses a virtual network card to take over the entire system's network, including UDP-based http3. Moreover, Brook allows us to control network requests programmatically, so it is necessary to have basic knowledge of network requests.
The GUI client does not use socks5 and http proxy mode, so there is no issue with some software not using the system proxy. Instead, it uses a virtual network card to take over the entire system's network, including UDP-based http3. Moreover, Brook allows us to control network requests programmatically, so it is necessary to have basic knowledge of network requests. 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`
## Without Brook: Basic Knowledge of Network Requests
## Without Brook
> Note: When we talk about addresses, we mean addresses that include the port number, such as a domain address: `google.com:443`, or an IP address: `8.8.8.8:53`
![x](./images/network.svg)
1. When an app requests a domain address, such as `google.com:443`
2. It will first perform a DNS resolution, which means that the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
1. The system DNS will return the IP of `google.com`, such as `1.2.3.4`, to the app
1. The system DNS will return the IP of `google.com`, such as `1.2.3.4`, to the app
3. The app will combine the IP and port into an IP address, such as: `1.2.3.4:443`
4. The app makes a network request to this IP address `1.2.3.4:443`
5. The app receives the response data
In the above process, the app actually makes two network requests: one to the IP address `8.8.8.8:53` and another to the IP address `1.2.3.4:443`. In other words, the domain name is essentially an alias for the IP, and must obtain the domain's IP to establish a connection.
## With Brook: Fake DNS On
## With Brook
Brook has a Fake DNS feature, which can parse the domain name out of the query requests that an app sends to the system DNS and decide how to respond to the app.
Brook has a Fake DNS feature default, which can parse the domain name out of the query requests that an app sends to the system DNS UDP 53 and decide how to respond to the app.
![x](./images/brook-client.svg)
1. When an app requests a domain name address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:53`. <mark>This will trigger the `in_dnsquery` variable, carrying information such as `domain`</mark>
1. The Brook client returns a fake IP to the app, such as `240.0.0.1`
1. The Brook client returns a fake IP to the app, such as `240.0.0.1`
4. The app combines the IP and port into an IP address, such as: `240.0.0.1:443`
5. The app makes a network request to the IP address `240.0.0.1:443`
6. The Brook client detects that an app is sending a network request to `240.0.0.1:443`, discovers that this is a fake IP, and will convert the fake IP address back to the domain address `google.com:443`. <mark>This will trigger the `in_address` variable, carrying information such as `domainaddress`</mark>
1. The Brook client sends `google.com:443` to the Brook Server
2. The Brook Server first requests its own DNS to resolve the domain name to find out the IP of `google.com`, such as receiving `1.2.3.4`
3. The Brook Server combines the IP and port into an IP address, such as: `1.2.3.4:443`
4. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
5. The Brook client then returns the data to the app
1. The Brook client sends `google.com:443` to the Brook Server
2. The Brook Server first requests its own DNS to resolve the domain name to find out the IP of `google.com`, such as receiving `1.2.3.4`
3. The Brook Server combines the IP and port into an IP address, such as: `1.2.3.4:443`
4. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
5. The Brook client then returns the data to the app
7. The app receives the response data
However, if the following situations occur, the domain name will not/cannot be parsed, meaning that the Brook client will not/cannot know what the domain name is and will treat it as a normal request sent to an IP address:
However, if the following situations occur, the domain name will not/cannot be parsed, meaning that the Brook client will not/cannot know what the domain name is and will treat it as a normal request sent to an IP address. To avoid the ineffectiveness of Fake DNS, please refer to [this article](https://www.txthinking.com/talks/articles/brook-fakedns-en.article):
- Fake DNS not enabled: in this case, the Brook client will not attempt to parse the domain name from the request sent to the system DNS and will treat it as a normal request sent to an IP address.
- Even with Fake DNS enabled, but the app uses the system's secure DNS or the app's own secure DNS: in this case, the Brook client cannot parse the domain name from the request sent to the secure DNS and will treat it as a normal request sent to an IP address.
To avoid the ineffectiveness of Fake DNS, please refer to [this article](https://www.txthinking.com/talks/articles/brook-fakedns-en.article).
Script can do more:
## With Brook: Fake DNS Off
1. When an app requests a domain address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:53`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `8.8.8.8:53` to the Brook Server
2. The Brook Server sends a network request to `8.8.8.8:53` and returns the result, such as `1.2.3.4`, to the Brook client
3. The Brook client then returns the result to the app
4. The app combines the IP and port into an IP address, such as: `1.2.3.4:443`
5. The app makes a network request to the IP address `1.2.3.4:443`
6. The Brook client detects that an app is sending a network request to `1.2.3.4:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `1.2.3.4:443` to the Brook Server
2. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
3. The Brook client then returns the data to the app
7. The app receives the response data
## With Brook: Fake DNS On, But the App Uses the System's Secure DNS or Its Own Secure DNS
1. When an app requests a domain name address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the secure DNS, such as `8.8.8.8:443`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `8.8.8.8:443` to the Brook Server
2. The Brook Server sends a network request to `8.8.8.8:443`, and returns the result, such as `1.2.3.4`, to the Brook client
3. The Brook client then returns the result to the app
4. The app combines the IP and port into an IP address, such as: `1.2.3.4:443`
5. The app makes a network request to the IP address `1.2.3.4:443`
6. The Brook client detects that an app is sending a network request to `1.2.3.4:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `1.2.3.4:443` to the Brook Server
2. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
3. The Brook client then returns the data to the app
7. The app receives the response data
To avoid the ineffectiveness of Fake DNS, please refer to [this article](https://www.txthinking.com/talks/articles/brook-fakedns-en.article).
## Handle Variable Trigger
- When the `in_brooklinks` variable is triggered:
- This is currently the only variable that gets triggered before the Brook client starts.
- We know that Brook starts with your choice of a Brook Server, and this variable lets you specify multiple Brook Servers.
- Then during runtime, you can use one of these Brook Servers as needed.
- When the `in_dnsquery` variable is triggered, you can process as needed, such as:
- Blocking, such as to prevent ad domain names.
- Directly specifying the response IP.
- Letting the system DNS resolve this domain.
- Letting Bypass DNS resolve this domain.
- And so on.
- When the `in_address` variable is triggered, you can process as needed, such as:
- Block this connection.
- Rewrite the destination.
- If it's a domain address, you can specify that Bypass DNS is responsible for resolving the IP of this domain.
- Allow it to connect directly without going through a proxy.
- If it's HTTP/HTTPS, you can start MITM (Man-In-The-Middle), which will subsequently trigger `in_httprequest` and `in_httpresponse`.
- And so on.
- When the `in_httprequest` variable is triggered, you can process as needed, such as:
- Modifying the HTTP request.
- Returning a custom HTTP response directly.
- When the `in_httpresponse` variable is triggered, you can process as needed, such as:
- Modifying the HTTP response.
For detailed information on the properties and responses of variables, please refer to the following content.
- In the `script: in_dnsquery` step, script can do more, read more below
- In the `script: in_address` step, script can do more, read more below
## Variables
@@ -120,9 +64,9 @@ For detailed information on the properties and responses of variables, please re
| ------------------------------ | ---- | ----------- | --------------------------------- | ------------------------------------------------- | -------- |
| in_brooklinks | map | / | Before connecting | Predefine multiple brook links, and then programmatically specify which one to connect to | map |
| in_dnsquery | map | FakeDNS: On | When a DNS query occurs | Script can decide how to handle this request | map |
| in_address | map | / | When connecting to an address | script can decide how to connect | map |
| in_httprequest | map | / | When an HTTP(S) request comes in | the script can decide how to handle this request | map |
| in_httprequest,in_httpresponse | map | / | when an HTTP(S) response comes in | the script can decide how to handle this response | map |
| in_address | map | / | When connecting to an address | Script can decide how to handle this request | map |
| in_httprequest | map | / | When an HTTP(S) request comes in | Script can decide how to handle this request | map |
| in_httprequest,in_httpresponse | map | / | when an HTTP(S) response comes in | Script can decide how to handle this response | map |
## in_brooklinks
@@ -144,42 +88,40 @@ For detailed information on the properties and responses of variables, please re
| ------ | ------ | ----------- | ---------- |
| domain | string | domain name | google.com |
| type | string | query type | A |
| appid | string | App ID or path | com.google.Chrome.helper |
| interface | string | network interface. Mac only | en0 |
| appid | string | macOS App Mode: this is app id; Linux and Windows: this is app path; OpenWrt: this is IP address of client device. Note: In some operating systems, the app may initiate DNS queries through the system app. | com.google.Chrome.helper |
`out`, if it is `error` type will be recorded in the log. Ignored if not of type `map`
| Key | Type | Description | Example |
| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------- | ------- |
| block | bool | Whether Block, default `false` | false |
| ip | string | Specify IP directly, only valid when `type` is `A`/`AAAA` | 1.2.3.4 |
| system | bool | Resolve by System DNS, default `false` | false |
| bypass | bool | Resolve by Bypass DNS, default `false` | false |
| brooklinkkey | string | When need to connect the Serverinstead, connect to the Server specified by the key in_brooklinks | custom name |
| ip | string | Ignore fake DNS, specify IP directly, only valid when `type` is `A`/`AAAA` | 1.2.3.4 |
| system | bool | Ignore fake DNS, resolve by System DNS over brook, default `false` | false |
| bypass | bool | Ignore fake DNS, resolve by Bypass DNS, default `false` | false |
| brooklinkkey | string | When need to connect the Server, instead, perfer connect to the Server specified by the key in_brooklinks | custom name |
## in_address
| Key | Type | Description | Example |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------- | -------------- |
| network | string | Network type, the value `tcp`/`udp` | tcp |
| ipaddress | string | IP type address. There is only of ipaddress and domainaddress. Note that there is no relationship between these two | 1.2.3.4:443 |
| ipaddress | string | IP type address. There is only one of ipaddress and domainaddress. Note that there is no relationship between these two | 1.2.3.4:443 |
| domainaddress | string | Domain type address, because of FakeDNS we can get the domain name address here | google.com:443 |
| appid | string | App ID or path | com.google.Chrome.helper |
| interface | string | network interface. Mac only | en0 |
| appid | string | macOS App Mode: this is app id; Linux and Windows: this is app path; OpenWrt: this is IP address of client device | com.google.Chrome.helper |
`out`, if it is `error` type will be recorded in the log. Ignored if not of type `map`
| Key | Type | Description | Example |
| ---------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| block | bool | Whether Block, default `false` | false |
| ipaddress | string | IP type address, rewrite destination | 1.2.3.4:443 |
| ipaddress | string | Rewrite destination to an ip address | 1.2.3.4:443 |
| ipaddressfrombypassdns | string | Use Bypass DNS to obtain `A` or `AAAA` IP and rewrite the destination, only valid when `domainaddress` exists, the value `A`/`AAAA` | A |
| bypass | bool | Bypass, default `false`. If `true` and `domainaddress`, then `ipaddress` or `ipaddressfrombypassdns` must be specified | false |
| bypass | bool | Bypass, default `false`. If `true` and `domainaddress` exists, then `ipaddress` or `ipaddressfrombypassdns` must be specified | false |
| mitm | bool | Whether to perform MITM, default `false`. Only valid when `network` is `tcp`. Need to install CA, see below | false |
| mitmprotocol | string | MITM protocol needs to be specified explicitly, the value is `http`/`https` | https |
| mitmcertdomain | string | The MITM certificate domain name, which is taken from `domainaddress` by default. If `ipaddress` and `mitm` is `true` and `mitmprotocol` is `https` then must be must be specified explicitly | example.com |
| mitmcertdomain | string | The MITM certificate domain name, which is taken from `domainaddress` by default. If `ipaddress` exists and `mitm` is `true` and `mitmprotocol` is `https` then must be must be specified explicitly | example.com |
| mitmwithbody | bool | Whether to manipulate the http body, default `false`. will read the body of the request and response into the memory and interact with the script. iOS 50M total memory limit may kill process | false |
| mitmautohandlecompress | bool | Whether to automatically decompress the http body when interacting with the script, default `false` | false |
| mitmautohandlecompress | bool | Whether to automatically decompress the http body when interacting with the script, default `false`. Usually need set this to true | false |
| mitmclienttimeout | int | Timeout for MITM talk to server, second, default 0 | 0 |
| mitmserverreadtimeout | int | Timeout for MITM read from client, second, default 0 | 0 |
| mitmserverwritetimeout | int | Timeout for MITM write to client, second, default 0 | 0 |
@@ -194,7 +136,7 @@ For detailed information on the properties and responses of variables, please re
| Body | bytes | HTTP request body | / |
| ... | string | other fields are HTTP headers | / |
`out`, must be set to a request or response
`out`, must be set to an unmodified or modified request or a response
## in_httpresponse
@@ -204,11 +146,11 @@ For detailed information on the properties and responses of variables, please re
| Body | bytes | HTTP response body | / |
| ... | string | other fields are HTTP headers | / |
`out`, must be set to a response
`out`, must be set to an unmodified or modified response
## Modules
In Brook GUI, scripts are abstracted into **Modules**. There are already [some modules](https://github.com/txthinking/brook/blob/master/programmable/modules/), and thre is no magic, it just 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.
In Brook GUI, scripts are abstracted into **Modules**. There are already [some modules](https://github.com/txthinking/brook/blob/master/programmable/modules/), and there is no magic, it just 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, {
@@ -235,11 +177,11 @@ modules = append(modules, {
})
```
## tun2brook
## ipio
https://github.com/txthinking/tun2brook
https://github.com/txthinking/ipio
If you are using tun2brook, you can manually combine multiple modules into a complete script in the following way. For example:
ipio uses the same script as the GUI. If you are using ipio, you can manually combine multiple modules into a complete script in the following way. For example:
```
cat _header.tengo > my.tengo
@@ -250,56 +192,24 @@ cat block_aaaa.tengo >> my.tengo
cat _footer.tengo >> my.tengo
```
## Syntax
## openwrt
[Tengo Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
https://www.txthinking.com/talks/articles/brook-openwrt-en.article
Library
openwrt uses the same script as the GUI. If you are using openwrt, you can manually combine multiple modules into a complete script in the following way. For example:
- [text](https://github.com/d5/tengo/blob/master/docs/stdlib-text.md): regular expressions, string conversion, and manipulation
- [math](https://github.com/d5/tengo/blob/master/docs/stdlib-math.md): mathematical constants and functions
- [times](https://github.com/d5/tengo/blob/master/docs/stdlib-times.md): time-related functions
- [rand](https://github.com/d5/tengo/blob/master/docs/stdlib-rand.md): random functions
- [fmt](https://github.com/d5/tengo/blob/master/docs/stdlib-fmt.md): formatting functions
- [json](https://github.com/d5/tengo/blob/master/docs/stdlib-json.md): JSON functions
- [enum](https://github.com/d5/tengo/blob/master/docs/stdlib-enum.md): Enumeration functions
- [hex](https://github.com/d5/tengo/blob/master/docs/stdlib-hex.md): hex encoding and decoding functions
- [base64](https://github.com/d5/tengo/blob/master/docs/stdlib-base64.md): base64 encoding and decoding functions
- `brook`: brook module
```
cat _header.tengo > my.tengo
```
Constants
cat block_google_secure_dns.tengo >> my.tengo
cat block_aaaa.tengo >> my.tengo
* os: string, linux/darwin/windows/ios/android
Functions
* splithostport(address string) => map/error: splits a network address of the form "host:port" to { "host": "xxx", "port": "xxx" }
* country(ip string) => string/error: get country code from ip
* cidrcontainsip(cidr string, ip string) => bool/error: reports whether the network includes ip
* parseurl(url string) => map/error: parses a raw url into a map, keys: scheme/host/path/rawpath/rawquery
* parsequery(query string) => map/error: parses a raw query into a kv map
* map2query(kv map) => string/error: convert map{string:string} into a query string
* bytes2ints(b bytes) => array/error: convert bytes into [int]
* ints2bytes(ints array) => bytes/error: convert [int] into bytes
* bytescompare(a bytes, b bytes) => int/error: returns an integer comparing two bytes lexicographically. The result will be 0 if a == b, -1 if a < b, and +1 if a > b
* bytescontains(b bytes, sub bytes) => bool/error: reports whether sub is within b
* byteshasprefix(s bytes, prefix bytes) => bool/error: tests whether the bytes s begins with prefix
* byteshassuffix(s bytes, suffix bytes) => bool/error: tests whether the bytes s ends with suffix
* bytesindex(s bytes, sep bytes) => int/error: returns the index of the first instance of sep in s, or -1 if sep is not present in s
* byteslastindex(s bytes, sep bytes) => int/error: returns the index of the last instance of sep in s, or -1 if sep is not present in s
* bytesreplace(s bytes, old bytes, new bytes, n int) => bytes/error: returns a copy of the s with the first n non-overlapping instances of old replaced by new. If n < 0, there is no limit on the number of replacements
* pathescape(s string) => string/error: escapes the string so it can be safely placed inside a URL path segment, replacing special characters (including /) with %XX sequences as needed
* pathunescape(s string) => string/error: does the inverse transformation of pathescape
* queryescape(s string) => string/error: escapes the string so it can be safely placed inside a URL query
* queryunescape(s string) => string/error: does the inverse transformation of queryescape
* hexdecode(s string) => bytes/error: returns the bytes represented by the hexadecimal string s
* hexencode(s string) => string/error: returns the hexadecimal encoding of src
```
cat _footer.tengo >> my.tengo
```
## Debug
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`
If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use [ipio](https://github.com/txthinking/ipio) on desktop to debug with `fmt.println`
## CA
@@ -314,10 +224,6 @@ https://txthinking.github.io/ca/ca.pem
> Some software may not read the system CAyou can use `curl --cacert ~/.nami/bin/ca.pem` to debug
## OpenWrt
[Brook OpenWRT: Perfectly supports IPv4/IPv6/TCP/UDP](https://www.txthinking.com/talks/articles/brook-openwrt-en.article)
## IPv6
Brook's stance on IPv6 is positive, if your server or local environment doesn't have an IPv6 stack, read [this article](https://www.txthinking.com/talks/articles/brook-ipv6-en.article).
-265
View File
@@ -1,265 +0,0 @@
# Examples
List some examples of common scene commands, pay attention to replace the parameters such as IP, port, password, domain name, certificate path, etc. in the example by yourself
## Run brook server
```
brook server --listen :9999 --password hello
```
then
- server: `1.2.3.4:9999`
- password: `hello`
or get brook link
```
brook link --server 1.2.3.4:9999 --password hello --name 'my brook server'
```
or get brook link with `--udpovertcp`
```
brook link --server 1.2.3.4:9999 --password hello --udpovertcp --name 'my brook server'
```
## Run brook wsserver
```
brook wsserver --listen :9999 --password hello
```
then
- server: `ws://1.2.3.4:9999`
- password: `hello`
or get brook link
```
brook link --server ws://1.2.3.4:9999 --password hello --name 'my brook wsserver'
```
or get brook link with domain, even if that's not your domain
```
brook link --server ws://hello.com:9999 --password hello --address 1.2.3.4:9999 --name 'my brook wsserver'
```
## Run brook wssserver: automatically certificate
> Make sure your domain has been resolved to your server IP successfully. Automatic certificate issuance requires the use of port 80
```
brook wssserver --domainaddress domain.com:443 --password hello
```
then
- server: `wss://domain.com:443`
- password: `hello`
or get brook link
```
brook link --server wss://domain.com:443 --password hello --name 'my brook wssserver'
```
## Run brook wssserver Use a certificate issued by an existing trust authority
> Make sure your domain has been resolved to your server IP successfully
```
brook wssserver --domainaddress domain.com:443 --password hello --cert /root/cert.pem --certkey /root/certkey.pem
```
then
- server: `wss://domain.com:443`
- password: `hello`
or get brook link
```
brook link --server wss://domain.com:443 --password hello --name 'my brook wssserver'
```
## Run brook wssserver issue untrusted certificates yourself, any domain
Install [mad](https://github.com/txthinking/mad)
```
nami install mad
```
Generate root ca
```
mad ca --ca /root/ca.pem --key /root/cakey.pem
```
Generate domain cert by root ca
```
mad cert --ca /root/ca.pem --ca_key /root/cakey.pem --cert /root/cert.pem --key /root/certkey.pem --domain domain.com
```
Run brook
```
brook wssserver --domainaddress domain.com:443 --password hello --cert /root/cert.pem --certkey /root/certkey.pem
```
get brook link with `--insecure`
```
brook link --server wss://domain.com:443 --password hello --name 'my brook wssserver' --address 1.2.3.4:443 --insecure
```
or get brook link with `--ca`
```
brook link --server wss://domain.com:443 --password hello --name 'my brook wssserver' --address 1.2.3.4:443 --ca /root/ca.pem
```
## withoutBrookProtocol
Better performance, but data is not strongly encrypted using Brook protocol. So please use certificate encryption, and it is not recommended to use --withoutBrookProtocol and --insecure together
## withoutBrookProtocol automatically certificate
> Make sure your domain has been resolved to your server IP successfully. Automatic certificate issuance requires the use of port 80
```
brook wssserver --domainaddress domain.com:443 --password hello --withoutBrookProtocol
```
get brook link
```
brook link --server wss://domain.com:443 --password hello --withoutBrookProtocol
```
## withoutBrookProtocol Use a certificate issued by an existing trust authority
> Make sure your domain has been resolved to your server IP successfully
```
brook wssserver --domainaddress domain.com:443 --password hello --cert /root/cert.pem --certkey /root/certkey.pem --withoutBrookProtocol
```
get brook link
```
brook link --server wss://domain.com:443 --password hello --name 'my brook wssserver' --withoutBrookProtocol
```
## withoutBrookProtocol issue untrusted certificates yourself, any domain
Install [mad](https://github.com/txthinking/mad)
```
nami install mad
```
Generate root ca
```
mad ca --ca /root/ca.pem --key /root/cakey.pem
```
Generate domain cert by root ca
```
mad cert --ca /root/ca.pem --ca_key /root/cakey.pem --cert /root/cert.pem --key /root/certkey.pem --domain domain.com
```
Run brook wssserver
```
brook wssserver --domainaddress domain.com:443 --password hello --cert /root/cert.pem --certkey /root/certkey.pem --withoutBrookProtocol
```
Get brook link
```
brook link --server wss://domain.com:443 --password hello --withoutBrookProtocol --address 1.2.3.4:443 --ca /root/ca.pem
```
## Run brook socks5, A stand-alone standard socks5 server
```
brook socks5 --listen :1080 --socks5ServerIP 1.2.3.4
```
then
- server: `1.2.3.4:1080`
or get brook link
```
brook link --server socks5://1.2.3.4:1080
```
## Run brook socks5 with username and password. A stand-alone standard socks5 server
```
brook socks5 --listen :1080 --socks5ServerIP 1.2.3.4 --username hello --password world
```
then
- server: `1.2.3.4:1080`
- username: `hello`
- password: `world`
or get brook link
```
brook link --server socks5://1.2.3.4:1080 --username hello --password world
```
## brook relayoverbrook can relay a local address to a remote address over brook, both TCP and UDP, it works with brook server wsserver wssserver.
```
brook relayoverbrook ... --from 127.0.0.1:5353 --to 8.8.8.8:53
```
## brook dnsserveroverbrook can create a encrypted DNS server, both TCP and UDP, it works with brook server wsserver wssserver.
```
brook dnsserveroverbrook ... --listen 127.0.0.1:53
```
## Brook OpenWRT Router: Perfectly supports IPv4/IPv6/TCP/UDP. Native IPv6
https://www.txthinking.com/talks/articles/brook-openwrt-en.article
## Turn macOS into a Gateway with Brook
https://www.txthinking.com/talks/articles/brook-macos-gateway-en.article
## Turn Windows into a Gateway with Brook
https://www.txthinking.com/talks/articles/brook-windows-gateway-en.article
## Turn Linux into a Gateway with Brook
https://www.txthinking.com/talks/articles/brook-linux-gateway-en.article
## brook relay can relay a address to a remote address. It can relay any tcp and udp server
```
brook relay --from :9999 --to 1.2.3.4:9999
```
## brook socks5tohttp can convert a socks5 to a http proxy
```
brook socks5tohttp --socks5 127.0.0.1:1080 --listen 127.0.0.1:8010
```
## 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...
+2 -2
View File
@@ -21,12 +21,12 @@ brook server -l :9999 -p hello
- [macOS](https://apps.apple.com/us/app/brook-network-tool/id1216002642)
- [Windows](https://github.com/txthinking/brook/releases/latest/download/Brook.msix)
- [Linux](https://github.com/txthinking/brook/releases/latest/download/Brook.bin)
- [OpenWrt](https://github.com/txthinking/brook/releases)
- [OpenWrt](https://www.txthinking.com/talks/articles/brook-openwrt-en.article)
> You may want to use `brook link` to customize some parameters
- [About App Mode on macOS](https://www.txthinking.com/talks/articles/macos-app-mode-en.article)
- [How to install Brook on Windows?](https://www.txthinking.com/talks/articles/msix-brook-en.article)
- [How to install Brook on Windows](https://www.txthinking.com/talks/articles/msix-brook-en.article)
- [How to install Brook on Linux](https://www.txthinking.com/talks/articles/linux-app-brook-en.article)
- [How to install Brook on OpenWrt](https://www.txthinking.com/talks/articles/brook-openwrt-en.article)
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 42 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

+751 -738
View File
File diff suppressed because it is too large Load Diff
+86
View File
@@ -0,0 +1,86 @@
# Other
## Script Syntax
I think just reading this one page is enough: [Tengo Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
Library
- [text](https://github.com/d5/tengo/blob/master/docs/stdlib-text.md): regular expressions, string conversion, and manipulation
- [math](https://github.com/d5/tengo/blob/master/docs/stdlib-math.md): mathematical constants and functions
- [times](https://github.com/d5/tengo/blob/master/docs/stdlib-times.md): time-related functions
- [rand](https://github.com/d5/tengo/blob/master/docs/stdlib-rand.md): random functions
- [fmt](https://github.com/d5/tengo/blob/master/docs/stdlib-fmt.md): formatting functions
- [json](https://github.com/d5/tengo/blob/master/docs/stdlib-json.md): JSON functions
- [enum](https://github.com/d5/tengo/blob/master/docs/stdlib-enum.md): Enumeration functions
- [hex](https://github.com/d5/tengo/blob/master/docs/stdlib-hex.md): hex encoding and decoding functions
- [base64](https://github.com/d5/tengo/blob/master/docs/stdlib-base64.md): base64 encoding and decoding functions
- `brook`: brook module
```
Constants
* os: string, linux/darwin/windows/ios/android
Functions
* splithostport(address string) => map/error: splits a network address of the form "host:port" to { "host": "xxx", "port": "xxx" }
* country(ip string) => string/error: get country code from ip
* cidrcontainsip(cidr string, ip string) => bool/error: reports whether the network includes ip
* parseurl(url string) => map/error: parses a raw url into a map, keys: scheme/host/path/rawpath/rawquery
* parsequery(query string) => map/error: parses a raw query into a kv map
* map2query(kv map) => string/error: convert map{string:string} into a query string
* bytes2ints(b bytes) => array/error: convert bytes into [int]
* ints2bytes(ints array) => bytes/error: convert [int] into bytes
* bytescompare(a bytes, b bytes) => int/error: returns an integer comparing two bytes lexicographically. The result will be 0 if a == b, -1 if a < b, and +1 if a > b
* bytescontains(b bytes, sub bytes) => bool/error: reports whether sub is within b
* byteshasprefix(s bytes, prefix bytes) => bool/error: tests whether the bytes s begins with prefix
* byteshassuffix(s bytes, suffix bytes) => bool/error: tests whether the bytes s ends with suffix
* bytesindex(s bytes, sep bytes) => int/error: returns the index of the first instance of sep in s, or -1 if sep is not present in s
* byteslastindex(s bytes, sep bytes) => int/error: returns the index of the last instance of sep in s, or -1 if sep is not present in s
* bytesreplace(s bytes, old bytes, new bytes, n int) => bytes/error: returns a copy of the s with the first n non-overlapping instances of old replaced by new. If n < 0, there is no limit on the number of replacements
* pathescape(s string) => string/error: escapes the string so it can be safely placed inside a URL path segment, replacing special characters (including /) with %XX sequences as needed
* pathunescape(s string) => string/error: does the inverse transformation of pathescape
* queryescape(s string) => string/error: escapes the string so it can be safely placed inside a URL query
* queryunescape(s string) => string/error: does the inverse transformation of queryescape
* hexdecode(s string) => bytes/error: returns the bytes represented by the hexadecimal string s
* hexencode(s string) => string/error: returns the hexadecimal encoding of src
```
## Example
Each `subcommand` has a `--example`, such as:
```
brook server --example
```
## Resources
| CLI | Description |
| --- | --- |
| [nami](https://github.com/txthinking/nami) | A clean and tidy decentralized package manager |
| [joker](https://github.com/txthinking/joker) | Joker can turn process into daemon. Zero-Configuration |
| [nico](https://github.com/txthinking/nico) | Nico can work with brook wsserver together |
| [z](https://github.com/txthinking/z) | z - process manager |
| [ipio](https://github.com/txthinking/ipio) | Proxy all traffic just one line command |
| [mad](https://github.com/txthinking/mad) | Generate root CA and derivative certificate for any domains and any IPs |
| [hancock](https://github.com/txthinking/hancock) | Manage multiple remote servers and execute commands remotely |
| [sshexec](https://github.com/txthinking/sshexec) | A command-line tool to execute remote command through ssh |
| [bash](https://github.com/txthinking/bash) | Many one-click scripts |
| [docker](https://hub.docker.com/r/txthinking/brook) | `docker run txthinking/brook` |
| Resources | Description |
| --- | --- |
| [Protocol](https://github.com/txthinking/brook/tree/master/protocol) | Brook Protocol |
| [Blog](https://www.txthinking.com/talks/) | Some articles you should read |
| [YouTube](https://www.youtube.com/txthinking) | Some videos you should watch |
| [Telegram](https://t.me/txthinking) | Ask questions here |
| [Announce](https://t.me/s/txthinking_talks) | All news you should care |
| [GitHub](https://github.com/txthinking) | Other useful repos |
| [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-store](https://github.com/txthinkinginc/brook-store) | A Brook User System |
| [TxThinking](https://www.txthinking.com) | Everything |
-30
View File
@@ -1,30 +0,0 @@
# Resources
| CLI | Description |
| --- | --- |
| [nami](https://github.com/txthinking/nami) | A clean and tidy decentralized package manager |
| [joker](https://github.com/txthinking/joker) | Joker can turn process into daemon. Zero-Configuration |
| [nico](https://github.com/txthinking/nico) | Nico can work with brook wsserver together |
| [z](https://github.com/txthinking/z) | z - process manager |
| [tun2brook](https://github.com/txthinking/tun2brook) | Proxy all traffic just one line command |
| [mad](https://github.com/txthinking/mad) | Generate root CA and derivative certificate for any domains and any IPs |
| [hancock](https://github.com/txthinking/hancock) | Manage multiple remote servers and execute commands remotely |
| [sshexec](https://github.com/txthinking/sshexec) | A command-line tool to execute remote command through ssh |
| [jb](https://github.com/txthinking/jb) | write script in an easier way than bash |
| [bash](https://github.com/txthinking/bash) | Many one-click scripts |
| [docker](https://hub.docker.com/r/txthinking/brook) | `docker run txthinking/brook` |
| Resources | Description |
| --- | --- |
| [Protocol](https://github.com/txthinking/brook/tree/master/protocol) | Brook Protocol |
| [Blog](https://www.txthinking.com/talks/) | Some articles you should read |
| [YouTube](https://www.youtube.com/txthinking) | Some videos you should watch |
| [Telegram](https://t.me/txthinking) | Ask questions here |
| [Announce](https://t.me/s/txthinking_news) | All news you should care |
| [GitHub](https://github.com/txthinking) | Other useful repos |
| [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-user-system](https://github.com/txthinkinginc/brook-user-system) | A Brook User System |
| [TxThinking](https://www.txthinking.com) | Everything |
+121
View File
@@ -0,0 +1,121 @@
# Server
brook dnsserver, dohserver, dnsserveroverbrook, server, wsserver, wssserver, quicserver can use script to do more complex thing. brook 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 DNS Server
![x](./images/brook-dns-server.svg)
Script can do more:
- There are [examples](https://github.com/txthinking/brook/blob/master/programmable/dnsserver/) for dns server
- In the `script: in_dnsquery` step, script can do more, read more below
## Brook Server
![x](./images/brook-server.svg)
Script can do more:
- There are [examples](https://github.com/txthinking/brook/blob/master/programmable/server/) for server
- In the `script: in_address` step, script can do more, read more below
## Variables
| variable | type | command | timing | description | out type |
| ------------------------------ | ---- | ----------- | --------------------------------- | ------------------------------------------------- | -------- |
| in_dnsservers | map | dnsserver/dnsserveroverbrook/dohserver/server/wsserver/wssserver/quicserver | When just running | Predefine multiple dns servers, and then programmatically specify which one to use | map |
| in_dohservers | map | dnsserver/dnsserveroverbrook/dohserver/server/wsserver/wssserver/quicserver | When just running | Predefine multiple doh servers, and then programmatically specify which one to use | map |
| in_brooklinks | map | server/wsserver/wssserver/quicserver | When just running | Predefine multiple brook links, and then programmatically specify which one to use | map |
| in_dnsquery | map | dnsserver/dnsserveroverbrook/dohserver | When a DNS query occurs | Script can decide how to handle this request | map |
| in_address | map | server/wsserver/wssserver/quicserver | When the Server connects the proxied address | Script can decide how to handle this request | map |
## in_dnsservers
| Key | Type | Description | Example |
| ------ | ------ | -------- | ---------- |
| _ | bool | meaningless | true |
`out`, ignored if not of type `map`
| Key | Type | Description | Example |
| ------------ | ------ | -------------------------------------------------------------------------------------------------- | ------- |
| ... | ... | ... | ... |
| custom name | string | dns server | 8.8.8.8:53 |
| ... | ... | ... | ... |
## in_dohservers
| Key | Type | Description | Example |
| ------ | ------ | -------- | ---------- |
| _ | bool | meaningless | true |
`out`, ignored if not of type `map`
| Key | Type | Description | Example |
| ------------ | ------ | -------------------------------------------------------------------------------------------------- | ------- |
| ... | ... | ... | ... |
| custom name | string | dohserver | https://dns.quad9.net/dns-query?address=9.9.9.9%3A443 |
| ... | ... | ... | ... |
## in_brooklinks
| Key | Type | Description | Example |
| ------ | ------ | -------- | ---------- |
| _ | bool | meaningless | true |
`out`, ignored if not of type `map`
| Key | Type | Description | Example |
| ------------ | ------ | -------------------------------------------------------------------------------------------------- | ------- |
| ... | ... | ... | ... |
| custom name | string | brook link | brook://... |
| ... | ... | ... | ... |
## in_dnsquery
| Key | Type | Description | Example |
| ------ | ------ | ----------- | ---------- |
| fromipaddress | string | client address which send this request | 1.2.3.4:5 |
| domain | string | domain name | google.com |
| type | string | query type | A |
| ... | ... | ... | ... |
| tag_key | string | --tag specifies the key value | tag_value |
| ... | ... | ... | ... |
`out`, if it is `error` type will be recorded in the log. Ignored if not of type `map`
| Key | Type | Description | Example |
| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------- | ------- |
| block | bool | Whether Block, default `false` | false |
| ip | string | Specify IP directly, only valid when `type` is `A`/`AAAA` | 1.2.3.4 |
| dnsserverkey | string | Use the dnsserver specified by key to resolve | custom name |
| dohserverkey | string | Use the dohserver specified by key to resolve | custom name |
## in_address
| Key | Type | Description | Example |
| ------ | ------ | ----------- | ---------- |
| network | string | `tcp` or `udp` | tcp |
| fromipaddress | string | client address which send this request | 1.2.3.4:5 |
| ipaddress | string | ip address to be proxied | 1.2.3.4:443 |
| domainaddress | string | domain address to be proxied | google.com:443 |
| user | string | user ID, only available when used with --userAPI | 9 |
| ... | ... | ... | ... |
| tag_key | string | --tag specifies the key value | tag_value |
| ... | ... | ... | ... |
`out`, if it is `error` type will be recorded in the log. Ignored if not of type `map`
| Key | Type | Description | Example |
| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------- | ------- |
| block | bool | Whether Block, default `false` | false |
| address | string | Rewrite destination to an address | 1.2.3.4 |
| ipaddressfromdnsserverkey | string | If the destination is domain address, use the dnsserver specified by key to resolve | custom name |
| ipaddressfromdnsserverkey | string | If the destination is domain address, use the dohserver specified by key to resolve | custom name |
| aoraaaa | string | Must be used with ipaddressfromdnsserverkey or ipaddressfromdnsserverkey. Valid value is `A`/`AAAA` | A |
| speedlimit | int | Set a rate limit for this request, for example `1000000` means 1000 kb/s | 1000000 |
| brooklinkkey | string | Use the brook link specified by key to proxy | custom name |
| dialwith | string | If your server has multiple IPs or network interfaces, you can specify the IP or network interface name to initiate this request | 192.168.1.2 or 2606:4700:3030::ac43:a86a or en1 |
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bun
import { $ } from 'bun'
import * as fs from 'node:fs/promises'
var s = await $`ls`.text()
var l = s.split('\n').filter(v => v.endsWith('.tengo'))
for (var i = 0; i < l.length; i++) {
s = (await $`cat ${l[i]}`.text()).replaceAll('import("brook")', 'undefined')
await fs.writeFile('/tmp/_.tengo', `
in_dnsservers := undefined
in_dohservers := undefined
in_dnsquery := undefined
${s}
`)
await $`tengo /tmp/_.tengo`
}
@@ -0,0 +1,31 @@
f := func() {
if in_dnsservers {
return {
"google4": "8.8.8.8:53",
"google6": "[2001:4860:4860::8888]:53",
"quad4": "9.9.9.9:53"
}
}
if in_dohservers {
return {
"google4": "https://dns.google/dns-query?address=8.8.8.8%3A443",
"google6": "https://dns.google/dns-query?address=%5B2001%3A4860%3A4860%3A%3A8888%5D%3A443",
"quad4": "https://dns.quad9.net/dns-query?address=9.9.9.9%3A443"
}
}
if in_dnsquery {
m := in_dnsquery
if m.domain == "360.cn" {
return { block: true }
}
if m.domain == "360.com" && m.type == "A" {
return { ip: "1.2.3.4" }
}
if m.domain == "http3.ooo" {
return { dohserverkey: "quad4" }
}
return
}
}
out := f()
+2
View File
@@ -0,0 +1,2 @@
brook dnsserver, dohserver, dnsserveroverbrook
@@ -1,3 +0,0 @@
127.0.0.0/32
192.168.1.0/24
1.2.4.8/32
@@ -1,3 +0,0 @@
::1/128
fd00::/8
2001:dc7:1000::1/128
@@ -1,3 +0,0 @@
lt
a.com
c.b.com
@@ -1,5 +1,5 @@
// 大陆域名用 Bypass DNS 来解析, 注意与 bypass_china_domain_a.tengo 区分. 这是一个包含主流的精小样本.
// generated by: jb https://bash.ooo/china.js
// generated by: https://bash.ooo/china.js
// The script limits the stack size 2048. If your array or map exceeds max stack size, try splitting it into multiple. The memory occupied by a dictionary is approximately twice that of an array with same elements.
modules = append(modules, {
dnsquery: func(m) {
@@ -1,5 +1,5 @@
// 大陆域名用 Bypass DNS 来解析 A 并直连, 注意与 bypass_china_domain.tengo 区分. 这是一个包含主流的精小样本.
// generated by: jb https://bash.ooo/china.js
// generated by: https://bash.ooo/china.js
// The script limits the stack size 2048. If your array or map exceeds max stack size, try splitting it into multiple. The memory occupied by a dictionary is approximately twice that of an array with same elements.
modules = append(modules, {
address: func(m) {
@@ -0,0 +1,14 @@
// Ignore fake DNS for ChatGPT Advanced Voice
modules = append(modules, {
dnsquery: func(m) {
text := import("text")
l := [
"livekit.cloud"
]
for v in l {
if m.domain == v || text.has_suffix(m.domain, "."+v) {
return { system: true }
}
}
}
})
+14 -6
View File
@@ -1,10 +1,18 @@
#!/usr/bin/env jb
#!/usr/bin/env bun
var s = $1`ls`.split('\n').filter(v => !v.startsWith('_') && v.endsWith('.tengo')).map(v => $1(`cat ${v}`).replaceAll('import("brook")', 'undefined')).join('\n')
import { $ } from 'bun'
import * as fs from 'node:fs/promises'
var h = $1`cat _header.tengo`
var f = $1`cat _footer.tengo`
write_file('/tmp/_.tengo', `
var s = await $`ls`.text()
var l = s.split('\n').filter(v => !v.startsWith('_') && v.endsWith('.tengo'))
for (var i = 0; i < l.length; i++) {
l[i] = (await $`cat ${l[i]}`.text()).replaceAll('import("brook")', 'undefined')
}
s = l.join('\n')
var h = await $`cat _header.tengo`.text()
var f = await $`cat _footer.tengo`.text()
await fs.writeFile('/tmp/_.tengo', `
in_brooklinks := undefined
in_dnsquery := undefined
in_address := undefined
@@ -14,4 +22,4 @@ ${h}
${s}
${f}
`)
$1`tengo /tmp/_.tengo`
await $`tengo /tmp/_.tengo`
@@ -1,41 +1,513 @@
// Instagram has a non-standard DNS cache, so we force it don't use Fake DNS, but the list may not be enough. Or disable Fake DNS, but you will not see domain in activity.
// Instagram 使用了非标准的 DNS 机制,所以我们强制其不使用 Fake DNS, 列表不一定全. 或者关闭 Fake DNS,但日志就看不到域名了。
// If Instagram is still experiencing network issues, you can turn off Fake DNS.
// 如果Instagram仍然遇到网络问题,可以关闭 Fake DNS。
// Ignore fake DNS for instagram
modules = append(modules, {
dnsquery: func(m) {
text := import("text")
l := [
"analytics.google.com",
"apple.com",
"comodoca.com",
"autonavi.com",
"giphy.com",
"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 m.domain == v || text.has_suffix(m.domain, "."+v) {
return { system: true }
f := func(domain, l){
ss := text.split(text.to_lower(domain), ".")
s := ""
for i := len(ss) - 1; i >= 0; i-- {
if s == "" {
s = ss[i]
} else {
s = ss[i] + "." + s
}
if l[s] {
return { system: true }
}
}
}
l := {
"aboutfacebook.com": true,
"accessfacebookfromschool.com": true,
"acebooik.com": true,
"acebook.com": true,
"acheter-followers-instagram.com": true,
"acheterdesfollowersinstagram.com": true,
"acheterfollowersinstagram.com": true,
"advancediddetection.com": true,
"askfacebook.net": true,
"askfacebook.org": true,
"atdmt2.com": true,
"atlasdmt.com": true,
"atlasonepoint.com": true,
"bookstagram.com": true,
"buyingfacebooklikes.com": true,
"careersatfb.com": true,
"carstagram.com": true,
"cdninstagram.com": true,
"celebgramme.com": true,
"chickstagram.com": true,
"china-facebook.com": true,
"click-url.com": true,
"como-hackearfacebook.com": true,
"crowdtangle.com": true,
"dacebook.com": true,
"dlfacebook.com": true,
"dotfacebook.com": true,
"dotfacebook.net": true,
"expresswifi.com": true,
"faacebok.com": true,
"faacebook.com": true,
"faasbook.com": true,
"facbebook.com": true,
"facbeok.com": true,
"facboo.com": true,
"facbook.com": true,
"facbool.com": true,
"facboox.com": true,
"faccebook.com": true,
"faccebookk.com": true,
"facdbook.com": true,
"facdebook.com": true,
"face-book.com": true,
"faceabook.com": true,
"facebboc.com": true,
"facebbook.com": true,
"facebboook.com": true,
"facebcook.com": true,
"facebdok.com": true,
"facebgook.com": true,
"facebhook.com": true,
"facebkkk.com": true,
"facebo-ok.com": true,
"faceboak.com": true,
"facebock.com": true,
"facebocke.com": true,
"facebof.com": true,
"faceboik.com": true,
"facebok.com": true,
"facebokbook.com": true,
"facebokc.com": true,
"facebokk.com": true,
"facebokok.com": true,
"faceboks.com": true,
"facebol.com": true,
"facebolk.com": true,
"facebomok.com": true,
"faceboo.com": true,
"facebooa.com": true,
"faceboob.com": true,
"faceboobok.com": true,
"facebooc.com": true,
"faceboock.com": true,
"facebood.com": true,
"facebooe.com": true,
"faceboof.com": true,
"facebooi.com": true,
"facebooik.com": true,
"facebooik.org": true,
"facebooj.com": true,
"facebook-corp.com": true,
"facebook-covid-19.com": true,
"facebook-ebook.com": true,
"facebook-forum.com": true,
"facebook-hardware.com": true,
"facebook-inc.com": true,
"facebook-login.com": true,
"facebook-newsroom.com": true,
"facebook-newsroom.org": true,
"facebook-pmdcenter.com": true,
"facebook-pmdcenter.net": true,
"facebook-pmdcenter.org": true,
"facebook-privacy.com": true,
"facebook-program.com": true,
"facebook-studio.com": true,
"facebook-support.org": true,
"facebook-texas-holdem.com": true,
"facebook-texas-holdem.net": true,
"facebook.br": true,
"facebook.ca": true,
"facebook.cc": true,
"facebook.com": true,
"facebook.design": true,
"facebook.hu": true,
"facebook.in": true,
"facebook.net": true,
"facebook.nl": true,
"facebook.org": true,
"facebook.se": true,
"facebook.shop": true,
"facebook.tv": true,
"facebook.us": true,
"facebook.wang": true,
"facebook123.org": true,
"facebook30.com": true,
"facebook30.net": true,
"facebook30.org": true,
"facebook4business.com": true,
"facebookads.com": true,
"facebookadvertisingsecrets.com": true,
"facebookatschool.com": true,
"facebookawards.com": true,
"facebookblueprint.net": true,
"facebookbrand.com": true,
"facebookbrand.net": true,
"facebookcanadianelectionintegrityinitiative.com": true,
"facebookcareer.com": true,
"facebookcheats.com": true,
"facebookck.com": true,
"facebookclub.com": true,
"facebookcom.com": true,
"facebookconsultant.org": true,
"facebookcoronavirus.com": true,
"facebookcovers.org": true,
"facebookcredits.info": true,
"facebookdating.net": true,
"facebookdusexe.org": true,
"facebookemail.com": true,
"facebookenespanol.com": true,
"facebookexchange.com": true,
"facebookexchange.net": true,
"facebookfacebook.com": true,
"facebookflow.com": true,
"facebookgames.com": true,
"facebookgraphsearch.com": true,
"facebookgraphsearch.info": true,
"facebookgroups.com": true,
"facebookhome.cc": true,
"facebookhome.com": true,
"facebookhome.info": true,
"facebookhub.com": true,
"facebooki.com": true,
"facebookinc.com": true,
"facebookland.com": true,
"facebooklikeexchange.com": true,
"facebooklive.com": true,
"facebooklivestaging.net": true,
"facebooklivestaging.org": true,
"facebooklogin.com": true,
"facebooklogin.info": true,
"facebookloginhelp.net": true,
"facebooklogs.com": true,
"facebookmail.com": true,
"facebookmail.tv": true,
"facebookmanager.info": true,
"facebookmarketing.info": true,
"facebookmarketingpartner.com": true,
"facebookmarketingpartners.com": true,
"facebookmobile.com": true,
"facebookmsn.com": true,
"facebooknews.com": true,
"facebooknfl.com": true,
"facebooknude.com": true,
"facebookofsex.com": true,
"facebookook.com": true,
"facebookpaper.com": true,
"facebookpay.com": true,
"facebookphonenumber.net": true,
"facebookphoto.com": true,
"facebookphotos.com": true,
"facebookpmdcenter.com": true
}
r := f(m.domain, l)
if r != undefined {
return r
}
l = {
"facebookpoke.net": true,
"facebookpoke.org": true,
"facebookpoker.info": true,
"facebookpokerchips.info": true,
"facebookporn.net": true,
"facebookporn.org": true,
"facebookporno.net": true,
"facebookportal.com": true,
"facebooks.com": true,
"facebooksafety.com": true,
"facebooksecurity.net": true,
"facebookshop.com": true,
"facebooksignup.net": true,
"facebooksite.net": true,
"facebookstories.com": true,
"facebookstudios.net": true,
"facebookstudios.org": true,
"facebooksupplier.com": true,
"facebooksuppliers.com": true,
"facebookswagemea.com": true,
"facebookswagstore.com": true,
"facebooksz.com": true,
"facebookthreads.net": true,
"facebooktv.net": true,
"facebooktv.org": true,
"facebookvacation.com": true,
"facebookw.com": true,
"facebookwork.com": true,
"facebookworld.com": true,
"facebool.com": true,
"facebool.info": true,
"facebooll.com": true,
"faceboom.com": true,
"faceboon.com": true,
"faceboonk.com": true,
"faceboooik.com": true,
"faceboook.com": true,
"faceboop.com": true,
"faceboot.com": true,
"faceboox.com": true,
"facebopk.com": true,
"facebpook.com": true,
"facebuk.com": true,
"facebuok.com": true,
"facebvook.com": true,
"facebyook.com": true,
"facebzook.com": true,
"facecbgook.com": true,
"facecbook.com": true,
"facecbook.org": true,
"facecook.com": true,
"facecook.org": true,
"facedbook.com": true,
"faceebok.com": true,
"faceebook.com": true,
"faceebot.com": true,
"facegbok.com": true,
"facegbook.com": true,
"faceobk.com": true,
"faceobok.com": true,
"faceobook.com": true,
"faceook.com": true,
"facerbooik.com": true,
"facerbook.com": true,
"facesbooc.com": true,
"facesounds.com": true,
"facetook.com": true,
"facevbook.com": true,
"facewbook.co": true,
"facewook.com": true,
"facfacebook.com": true,
"facfebook.com": true,
"fackebook.com": true,
"facnbook.com": true,
"facrbook.com": true,
"facvebook.com": true,
"facwebook.com": true,
"facxebook.com": true,
"fadebook.com": true,
"faebok.com": true,
"faebook.com": true,
"faebookc.com": true,
"faeboook.com": true,
"faecebok.com": true,
"faesebook.com": true,
"fafacebook.com": true,
"faicbooc.com": true,
"fasebokk.com": true,
"fasebook.com": true,
"faseboox.com": true,
"favebook.com": true,
"faycbok.com": true,
"fb.careers": true,
"fb.com": true,
"fb.gg": true,
"fb.me": true,
"fb.watch": true,
"fbacebook.com": true,
"fbbmarket.com": true,
"fbboostyourbusiness.com": true,
"fbcdn-a.akamaihd.net": true,
"fbcdn.com": true,
"fbcdn.net": true,
"fbfeedback.com": true,
"fbhome.com": true,
"fbidb.io": true,
"fbinc.com": true,
"fbinnovation.com": true,
"fbmarketing.com": true,
"fbreg.com": true,
"fbrpms.com": true,
"fbsbx.com": true,
"fbsbx.net": true,
"fbsupport-covid.net": true,
"fbthirdpartypixel.com": true,
"fbthirdpartypixel.net": true,
"fbthirdpartypixel.org": true,
"fburl.com": true,
"fbwat.ch": true,
"fbworkmail.com": true,
"fcacebook.com": true,
"fcaebook.com": true,
"fcebook.com": true,
"fcebookk.com": true,
"fcfacebook.com": true,
"fdacebook.info": true,
"feacboo.com": true,
"feacbook.com": true,
"feacbooke.com": true,
"feacebook.com": true,
"fecbbok.com": true,
"fecbooc.com": true,
"fecbook.com": true,
"feceboock.com": true,
"fecebook.net": true,
"feceboox.com": true,
"fececbook.com": true,
"feook.com": true,
"ferabook.com": true,
"fescebook.com": true,
"fesebook.com": true,
"ffacebook.com": true,
"fgacebook.com": true,
"ficeboock.com": true,
"fmcebook.com": true,
"fnacebook.com": true,
"fosebook.com": true,
"fpacebook.com": true,
"fqcebook.com": true,
"fracebook.com": true,
"freeb.com": true,
"freebasics.com": true,
"freebasics.net": true,
"freebs.com": true,
"freefacebook.com": true,
"freefacebook.net": true,
"freefacebookads.net": true,
"freefblikes.com": true,
"freindfeed.com": true,
"friendbook.info": true,
"friendfed.com": true,
"friendfeed-api.com": true,
"friendfeed-media.com": true,
"friendfeed.com": true,
"friendfeedmedia.com": true,
"fsacebok.com": true,
"fscebook.com": true,
"fundraisingwithfacebook.com": true,
"funnyfacebook.org": true,
"futureofbusinesssurvey.org": true,
"gacebook.com": true,
"gameroom.com": true,
"gfacecbook.com": true,
"groups.com": true,
"hackerfacebook.com": true,
"hackfacebook.com": true,
"hackfacebookid.com": true,
"hifacebook.info": true,
"howtohackfacebook-account.com": true,
"hsfacebook.com": true,
"httpfacebook.com": true,
"httpsfacebook.com": true,
"httpwwwfacebook.com": true,
"i.org": true,
"iachat-followers-instagram.com": true,
"ig.me": true,
"igcdn.com": true,
"igsonar.com": true,
"igtv.com": true,
"imstagram.com": true,
"imtagram.com": true,
"instaadder.com": true,
"instachecker.com": true,
"instafallow.com": true,
"instafollower.com": true,
"instagainer.com": true,
"instagda.com": true,
"instagify.com": true,
"instagmania.com": true,
"instagor.com": true
}
r = f(m.domain, l)
if r != undefined {
return r
}
l = {
"instagram-brand.com": true,
"instagram-engineering.com": true,
"instagram-help.com": true,
"instagram-press.com": true,
"instagram-press.net": true,
"instagram.com": true,
"instagramci.com": true,
"instagramcn.com": true,
"instagramdi.com": true,
"instagramhashtags.net": true,
"instagramhilecim.com": true,
"instagramhilesi.org": true,
"instagramium.com": true,
"instagramizlenme.com": true,
"instagramkusu.com": true,
"instagramlogin.com": true,
"instagramm.com": true,
"instagramn.com": true,
"instagrampartners.com": true,
"instagramphoto.com": true,
"instagramq.com": true,
"instagramsepeti.com": true,
"instagramtakipcisatinal.net": true,
"instagramtakiphilesi.com": true,
"instagramtips.com": true,
"instagramtr.com": true,
"instagran.com": true,
"instagranm.com": true,
"instagrem.com": true,
"instagrm.com": true,
"instagtram.com": true,
"instagy.com": true,
"instamgram.com": true,
"instangram.com": true,
"instanttelegram.com": true,
"instaplayer.net": true,
"instastyle.tv": true,
"instgram.com": true,
"intagram.com": true,
"intagrm.com": true,
"internet.org": true,
"intgram.com": true,
"kingstagram.com": true,
"klik.me": true,
"liverail.com": true,
"liverail.tv": true,
"lnstagram-help.com": true,
"login-account.net": true,
"markzuckerberg.com": true,
"messenger.com": true,
"midentsolutions.com": true,
"mobilefacebook.com": true,
"moneywithfacebook.com": true,
"myfbfans.com": true,
"newsfeed.com": true,
"nextstop.com": true,
"oninstagram.com": true,
"online-deals.net": true,
"online-instagram.com": true,
"onlineinstagram.com": true,
"opencreate.org": true,
"reachtheworldonfacebook.com": true,
"redkix.com": true,
"rocksdb.org": true,
"shopfacebook.com": true,
"sportsfacebook.com": true,
"sportstream.com": true,
"supportfacebook.com": true,
"terragraph.com": true,
"tfbnw.net": true,
"thefacebook.com": true,
"thefacebook.net": true,
"thefind.com": true,
"theinstagramhack.com": true,
"toplayerserver.com": true,
"viewpointsfromfacebook.com": true,
"web-instagram.net": true,
"whatsapp.com": true,
"whatsapp.net": true,
"whyfacebook.com": true,
"workplace.com": true,
"workplaceusecases.com": true,
"worldhack.com": true,
"www-facebook.com": true,
"wwwfacebok.com": true,
"wwwfacebook.com": true,
"wwwinstagram.com": true,
"wwwmfacebook.com": true,
"zuckerberg.com": true,
"zuckerberg.net": true
}
r = f(m.domain, l)
if r != undefined {
return r
}
}
})
+2 -2
View File
@@ -27,9 +27,9 @@ modules = append(modules, {
})
```
## tun2brook
## ipio or openwrt
If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:
If you are using opio or openwrt, you can combine multiple modules into a complete script in the following way. For example:
```
cat _header.tengo > my.tengo
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bun
import { $ } from 'bun'
import * as fs from 'node:fs/promises'
var s = await $`ls`.text()
var l = s.split('\n').filter(v => v.endsWith('.tengo'))
for (var i = 0; i < l.length; i++) {
s = (await $`cat ${l[i]}`.text()).replaceAll('import("brook")', 'undefined')
await fs.writeFile('/tmp/_.tengo', `
in_dnsservers := undefined
in_dohservers := undefined
in_brooklinks := undefined
in_address := undefined
${s}
`)
await $`tengo /tmp/_.tengo`
}
+69
View File
@@ -0,0 +1,69 @@
f := func() {
if in_dnsservers {
return {
"google4": "8.8.8.8:53",
"google6": "[2001:4860:4860::8888]:53",
"quad4": "9.9.9.9:53"
}
}
if in_dohservers {
return {
"google4": "https://dns.google/dns-query?address=8.8.8.8%3A443",
"google6": "https://dns.google/dns-query?address=%5B2001%3A4860%3A4860%3A%3A8888%5D%3A443",
"quad4": "https://dns.quad9.net/dns-query?address=9.9.9.9%3A443"
}
}
if in_brooklinks {
return {
"huluwa": "brook://server?password=hello&server=1.3.6.9%3A9999",
"jiuyeye": "brook://socks5?password=&socks5=socks5%3A%2F%2F127.0.0.1%3A1080"
}
}
if in_address {
m := in_address
brook := import("brook")
if m.ipaddress {
r := brook.splithostport(m.ipaddress)
s := brook.country(r.host)
if s == "ZZ" {
return { block: true }
}
if m.network == "tcp" && m.ipaddress == "8.8.8.8:53" {
return { address: "9.9.9.9:53" }
}
return
}
if m.domainaddress {
r := brook.splithostport(m.domainaddress)
text := import("text")
if r.host == "localhost" || text.contains(r.host, "speedtest") {
return { block: true }
}
if m.domainaddress == "heygirl:443" {
return { address: "1.2.3.4:443" }
}
if m.domainaddress == "hello.com:443" {
return { ipaddressfromdohserverkey: "quad4", aoraaaa: "A" }
}
if m.network == "tcp" && m.domainaddress == "world.com:443" {
return { brooklinkkey: "jiuyeye" }
}
if m.domainaddress == "helloworld:443" {
return { ipaddressfromdohserverkey: "quad4", aoraaaa: "AAAA", brooklinkkey: "huluwa" }
}
if m.domainaddress == "nihao.com:443" {
return { speedlimit: 500000 }
}
if m.domainaddress == "shijie.com:443" {
return { speedlimit: 500000, brooklinkkey: "huluwa" }
}
if m.domainaddress == "nihaoshijie.com:443" {
return { speedlimit: 500000, dialwith: "192.168.3.99" }
}
return
}
return
}
}
out := f()
+2
View File
@@ -0,0 +1,2 @@
brook server, wsserver, wssserver, quicserver
@@ -1,63 +0,0 @@
# brook quicserver --withoutBrookProtocol protocol
<!--THEME:github-->
<!--G-R3M673HK5V-->
## Terminology
- **`DST Address`**: The address that the application actually wants to request, address contains IP/domain and port
```
ATYP + IP/Domain + PORT
```
- `ATYP`: 1 byte
- 0x01: IPv4
- 0x03: Domain
- 0x04: IPv6
- `IP/Domain`: 4/n/16 bytes
- If ATYP is 0x01, then this is IPv4, 4 bytes
- If ATYP is 0x03, then this is domain, n bytes, and the first byte is the domain length
- If ATYP is 0x04, then this is IPv6, 16 bytes
- `Port`: 2 bytes
- Big Endian 16-bit unsigned integer
- **`Password`**: User-defined password
- **`SHA256`**: Defined in FIPS 180-4
## Client --TCP over QUIC Stream--> Server
```
[SHA256(Password) + (DST Address Length+4) + Unix Timestamp + DST Address] + [DATA]...
```
> The maximum length of `[SHA256(Password) + (DST Address Length+4) + Unix Timestamp + DST Address]` is 2048 bytes
- `DST Address Length+4`: Big Endian 16-bit unsigned integer
- [`Unix Timestamp`](https://en.wikipedia.org/wiki/Unix_time): If it is not even, it should be increased by 1. Big Endian 32-bit unsigned integer
- `DATA`: Actual data being proxied
## Server --TCP over QUIC Stream--> Client
```
[DATA]...
```
## Client --UDP over QUIC Datagram--> Server
```
SHA256(Password) + Unix Timestamp + DST Address + Data
```
> The maximum length of datagram is [1197](https://github.com/quic-go/quic-go/blob/a81365ece88ce9d4601ef140073abadc7657fec8/internal/protocol/params.go#L137) now, and may change in the [future](https://datatracker.ietf.org/doc/html/rfc9221#section-3)
- [`Unix Timestamp`](https://en.wikipedia.org/wiki/Unix_time): Big Endian 32-bit unsigned integer
- `Data`: Actual data being proxied
## Server --UDP over QUIC Datagram--> Client
```
DST Address + Data
```
> The maximum length of datagram is [1197](https://github.com/quic-go/quic-go/blob/a81365ece88ce9d4601ef140073abadc7657fec8/internal/protocol/params.go#L137) now, and may change in the [future](https://datatracker.ietf.org/doc/html/rfc9221#section-3)
@@ -1,69 +0,0 @@
# brook wsserver --withoutBrookProtocol protocol
<!--THEME:github-->
<!--G-R3M673HK5V-->
## Terminology
- **`DST Address`**: The address that the application actually wants to request, address contains IP/domain and port
```
ATYP + IP/Domain + PORT
```
- `ATYP`: 1 byte
- 0x01: IPv4
- 0x03: Domain
- 0x04: IPv6
- `IP/Domain`: 4/n/16 bytes
- If ATYP is 0x01, then this is IPv4, 4 bytes
- If ATYP is 0x03, then this is domain, n bytes, and the first byte is the domain length
- If ATYP is 0x04, then this is IPv6, 16 bytes
- `Port`: 2 bytes
- Big Endian 16-bit unsigned integer
- **`Password`**: User-defined password
- **`SHA256`**: Defined in FIPS 180-4
## Client --TCP--> Server
```
[Standard WebSocket Protocol Header] + [SHA256(Password) + (DST Address Length+4) + Unix Timestamp + DST Address] + [DATA]...
```
> The maximum length of `[SHA256(Password) + (DST Address Length+4) + Unix Timestamp + DST Address]` is 2048 bytes
- `DST Address Length+4`: Big Endian 16-bit unsigned integer
- [`Unix Timestamp`](https://en.wikipedia.org/wiki/Unix_time): If it is not even, it should be increased by 1. Big Endian 32-bit unsigned integer
- `DATA`: Actual data being proxied
## Server --TCP--> Client
```
[Standard WebSocket Protocol Header] + [DATA]...
```
## Client --UDP(UDP over TCP)--> Server
```
[Standard WebSocket Protocol Header] + [SHA256(Password) + (DST Address Length+4) + Unix Timestamp + DST Address] + [Fragment Length + Fragment]...
```
> The maximum length of `[SHA256(Password) + (DST Address Length+4) + Unix Timestamp + DST Address]` is 2048 bytes<br/>
> The maximum length of `[Fragment Length + Fragment]` is 65507 bytes<br/>
- `DST Address Length+4`: Big Endian 16-bit unsigned integer
- `Fragment Length`: Big Endian 16-bit unsigned integer
- `Fragment`: Actual data being proxied
- [`Unix Timestamp`](https://en.wikipedia.org/wiki/Unix_time): If it is not odd, it should be increased by 1. Big Endian 32-bit unsigned integer
## Server --UDP(UDP over TCP)--> Client
```
[Standard WebSocket Protocol Header] + [Fragment Length + Fragment]...
```
> The maximum length of `[Fragment Length + Fragment]` is 65507 bytes<br/>
- `Fragment Length`: Big Endian 16-bit unsigned integer
- `Fragment`: Actual data being proxied
+2 -2
View File
@@ -61,10 +61,10 @@ The user 9 has expired
## Run Brook Server with your User API
```
brook --serverLog /path/to/log.txt --userAPI https://your-api-server.com/a_unpredictable_path server --listen :9999 --password hello
brook --userLog /path/to/log.txt --userAPI https://your-api-server.com/a_unpredictable_path server --listen :9999 --password hello
```
You can count the traffic of each user from serverLog
You can count the traffic of each user from userLog
```
{"bytes":"2190","dst":"8.8.8.8:53","from":"34.105.110.232:49514","network":"tcp","time":"2024-02-26T09:56:12Z","user":"9"}