diff --git a/README.md b/README.md index c24d9f9bf..303b0862d 100644 --- a/README.md +++ b/README.md @@ -28,18 +28,137 @@ 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) -# Client +# 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` -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` +| 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 | +# Client ## CLI @@ -52,106 +171,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 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. -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. +![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`. This will trigger the `in_dnsquery` variable, carrying information such as `domain` - 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`. This will trigger the `in_address` variable, carrying information such as `domainaddress` - 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). - -## 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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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 +Script can do more: -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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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 @@ -159,9 +224,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 @@ -183,42 +248,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 Server,instead, 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 | @@ -233,7 +296,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 @@ -243,11 +306,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, { @@ -274,11 +337,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 @@ -289,56 +352,24 @@ 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) - -Library +## openwrt -- [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 +https://www.txthinking.com/talks/articles/brook-openwrt-en.article - ``` - Constants +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: - * os: string, linux/darwin/windows/ios/android +``` +cat _header.tengo > my.tengo - Functions +cat block_google_secure_dns.tengo >> my.tengo +cat block_aaaa.tengo >> my.tengo - * 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 @@ -353,10 +384,6 @@ https://txthinking.github.io/ca/ca.pem > Some software may not read the system CA,you 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). @@ -403,91 +430,138 @@ Brook's stance on IPv6 is positive, if your server or local environment doesn't 16. Read the [documentation](https://brook.app) 14. Submit [new issue](https://github.com/txthinking/brook/issues?q=is%3Aissue) 17. Seek help in the [group](https://t.me/txthinking) -# CLI Documentation -Each subcommand has a `--example` parameter that can print the minimal example of usage -# NAME +# Other -Brook - A cross-platform programmable network tool - -# SYNOPSIS - -Brook - -``` -brook --help -``` - -**Usage**: +## Script Syntax -``` -Brook [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] -``` +I think just reading this one page is enough: [Tengo Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md) -# GLOBAL OPTIONS +Library -- **--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 +- [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 -- **--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 + ``` + Constants -- **--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 + * os: string, linux/darwin/windows/ios/android -- **--blockGeoIP**="": Block IP by Geo country code, such as US. Works with server/wsserver/wssserver/quicserver + Functions -- **--blockListUpdateInterval**="": Update list --blockDomainList,--blockCIDR4List,--blockCIDR6List interval, second. default 0, only read one time on start (default: 0) + * 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 + ``` -- **--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") +## Example -- **--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 +Each `subcommand` has a `--example`, such as: -- **--dialWithDNSPrefer**="": This is used with the dialWithDNS parameter. Prefer A record or AAAA record. Value is A or AAAA +``` +brook server --example +``` -- **--dialWithIP4**="": When the current machine establishes a network connection to the outside IPv4, both TCP and UDP, it is used to specify the IPv4 used +## Resources -- **--dialWithIP6**="": When the current machine establishes a network connection to the outside IPv6, both TCP and UDP, it is used to specify the IPv6 used +| 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` | -- **--dialWithNIC**="": When the current machine establishes a network connection to the outside, both TCP and UDP, it is used to specify the NIC used +| 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 | -- **--dialWithSocks5**="": When the current machine establishes a network connection to the outside, both TCP and UDP, with your socks5 proxy, such as 127.0.0.1:1081 +# CLI Documentation +# NAME -- **--dialWithSocks5Password**="": If there is +Brook - A cross-platform programmable network tool -- **--dialWithSocks5TCPTimeout**="": time (s) (default: 0) +# SYNOPSIS -- **--dialWithSocks5UDPTimeout**="": time (s) (default: 60) +Brook -- **--dialWithSocks5Username**="": If there is +``` +brook --help +``` +**Usage**: +``` +Brook [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] +``` -- **--ipLimitInterval**="": Interval (s) for ipLimitMax (default: 0) +# GLOBAL OPTIONS -- **--ipLimitMax**="": Limit the number of client IP addresses, be careful when using this parameter, as the client may have dynamic IP. Works with server/wsserver/wssserver/quicserver (default: 0) +- **--cliToken**="": The CLI Token of your Brook Plus or Brook Business account, get it from https://www.txthinking.com/brook.html -- **--ipLimitWait**="": How long (s) to wait for recovery after exceeding ipLimitMax (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 (default: "brook") -- **--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 +- **--log**="": Works with server, wsserver, wssserver, quicserver, dnsserver, dohserver, dnsserveroverbrook. A valid value is file path. If you want to debug SOCKS5 lib, set env SOCKS5_DEBUG=true -- **--prometheus**="": prometheus http listen addr, such as :7070. If it is transmitted on the public network, it is recommended to use it with nico +- **--pid**="": A file path used to store pid. Send SIGUSR1 to me to reset the --log or --userLog file on unix system -- **--prometheusPath**="": prometheus http path, such as /xxx. If it is transmitted on the public network, a hard-to-guess value is recommended +- **--script**="": [Brook Plus or Brook Business]. Works with server, wsserver, wssserver, quicserver, dnsserver, dohserver, dnsserveroverbrook. https://, http:// or /path/to/file.tengo. Get details at https://brook.app -- **--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") +- **--scriptUpdateInterval**="": Works with --script. The interval (s) to re-fetch script. The default is 0, which means only fetch once on startup (default: 0) -- **--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 +- **--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 (default: "brook") -- **--speedLimit**="": Limit speed (b), 500kb/s such as: 500000, works with server/wsserver/wssserver/quicserver (default: 0) +- **--tag**="": Works with --log, --userAPI, --userLog, --script. Tag can be used to the process, will be append into log or userLog, such as: 'key1:value1'. And all tags will also be appended as query parameters one by one to the userAPI -- **--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**="": [Brook Business]. Works with server, wsserver, wssserver, quicserver. 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. For more information, please read https://github.com/txthinking/brook/blob/master/protocol/user.md -- **--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 +- **--userAPIRateLimit**="": Works with --userAPI. Limit the request rate per token to the user API by Brook Server, this will reduce the load on the user API. This is especially important when users have expired, and the userAPIValidCacheTime will not cache the requests, resulting in continuous requests to the user API. The default is 0, which means no limitation. For example, setting it to 1 means the rate is limited to 1 request per token per second. The phrase 'per token' means that each token has its own rate limiter, and they do not interfere with each other (default: 1) -- **--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**="": Works with --userAPI. 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) -- **--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) +- **--userLog**="": Works with --userAPI. Log, traffic and more. A valid value is file path. Send SIGUSR1 to me to reset the log file on unix system. Mutually exclusive with the --log parameter. - **--version, -v**: print the version @@ -498,14 +572,6 @@ Brook [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] Start a brook server that supports tcp and udp -- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead - -- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead - -- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead - -- **--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' @@ -516,8 +582,6 @@ Start a brook server that supports tcp and udp - **--udpTimeout**="": time (s) (default: 0) -- **--updateListInterval**="": This option will be removed in a future version, please use the global option instead (default: 0) - ## client Start a brook client that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook client <-> $ brook server <-> dst] @@ -544,14 +608,6 @@ Start a brook client that supports tcp and udp. It can open a socks5 proxy, [src Start a brook wsserver that supports tcp and udp. It opens a standard http server and a websocket server -- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead - -- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead - -- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead - -- **--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' @@ -564,10 +620,6 @@ Start a brook wsserver that supports tcp and udp. It opens a standard http serve - **--udpTimeout**="": time (s) (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 - - **--xForwardedFor**: Replace the from field in --log, note that this may be forged ## wsclient @@ -596,14 +648,6 @@ Start a brook wsclient that supports tcp and udp. It can open a socks5 proxy, [s Start a brook wssserver that supports tcp and udp. It opens a standard https server and a websocket server -- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead - -- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead - -- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead - -- **--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 - **--certkey**="": The cert key file absolute path for the domain, such as /path/to/certkey.pem. If cert or certkey is empty, a certificate will be issued automatically @@ -620,10 +664,6 @@ Start a brook wssserver that supports tcp and udp. It opens a standard https ser - **--udpTimeout**="": time (s) (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 Start a brook wssclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook wssclient <-> $ brook wssserver <-> dst] @@ -650,14 +690,6 @@ Start a brook wssclient that supports tcp and udp. It can open a socks5 proxy, [ Start a brook quicserver that supports tcp and udp. -- **--blockCIDR4List**="": This option will be removed in a future version, please use the global option instead - -- **--blockCIDR6List**="": This option will be removed in a future version, please use the global option instead - -- **--blockDomainList**="": This option will be removed in a future version, please use the global option instead - -- **--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 - **--certkey**="": The cert key file absolute path for the domain, such as /path/to/certkey.pem. If cert or certkey is empty, a certificate will be issued automatically @@ -672,13 +704,9 @@ Start a brook quicserver that supports tcp and udp. - **--udpTimeout**="": time (s) (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 -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) +Start a brook quicclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook quicclient <-> $ brook quicserver <-> dst] - **--example**: Show a minimal example of usage @@ -716,29 +744,37 @@ Relay network traffic over brook, which supports TCP and UDP. Accessing [from ad ## dnsserveroverbrook -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] +Run a dns server over brook, which supports TCP and UDP, [src <-> $ brook dnserversoverbrook <-> $ brook server/wsserver/wssserver/quicserver <-> dns] + +- **--dns**="": Forward to DNS server (default: 8.8.8.8: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 -- **--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 +- **--password, -p**="": Password -- **--bypassDomainList**="": 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 +- **--server, -s**="": brook server or brook wsserver or brook wssserver or brook quicserver, like: 1.2.3.4:9999, ws://1.2.3.4:9999, wss://domain.com:443/ws, quic://domain.com:443 -- **--disableA**: Disable A query +- **--tcpTimeout**="": time (s) (default: 0) -- **--disableAAAA**: Disable AAAA query +- **--udpTimeout**="": time (s) (default: 0) -- **--dns**="": DNS server for resolving domains NOT in list (default: 8.8.8.8:53) +## connect -- **--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) +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 -- **--link**="": brook link, you can get it via $ brook link. The server and password parameters will be ignored +- **--http**="": Where to listen for HTTP proxy connections -- **--listen, -l**="": Listen address, like: 127.0.0.1:53 +- **--link, -l**="": brook link, you can get it via $ brook link -- **--password, -p**="": Password +- **--socks5**="": Where to listen for SOCKS5 connections (default: 127.0.0.1:1080) -- **--server, -s**="": brook server or brook wsserver or brook wssserver or brook quicserver, like: 1.2.3.4:9999, ws://1.2.3.4:9999, wss://domain.com:443/ws, quic://domain.com:443 +- **--socks5ServerIP**="": Only if your socks5 server IP is different from listen IP - **--tcpTimeout**="": time (s) (default: 0) @@ -770,34 +806,14 @@ Generate a 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 +- **--token**="": A token represents a user's identity. A string encoded in hexadecimal. Server needs to have --userAPI enabled -- **--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 +- **--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 - **--udpovertcp**: When server is brook server, UDP over TCP - **--username, -u**="": Username, when server is socks5 server -- **--withoutBrookProtocol**: When server is brook wsserver or brook wssserver or brook quicserver, the data will not be encrypted with brook protocol - -## connect - -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 - -- **--socks5**="": Where to listen for SOCKS5 connections (default: 127.0.0.1:1080) - -- **--socks5ServerIP**="": Only if your socks5 server IP is different from listen IP - -- **--tcpTimeout**="": time (s) (default: 0) - -- **--udpTimeout**="": time (s) (default: 0) - ## relay Run a standalone relay, which supports TCP and UDP. Accessing [from address] is equal to accessing [to address], [src <-> from address <-> to address] @@ -816,12 +832,6 @@ Run a standalone relay, which supports TCP and UDP. Accessing [from address] is 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 - -- **--disableA**: Disable A query - -- **--disableAAAA**: Disable AAAA query - - **--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 @@ -850,16 +860,10 @@ Send a dns query 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 - - **--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 - **--certkey**="": The cert key file absolute path for the domain, such as /path/to/certkey.pem. If cert or certkey is empty, a certificate will be issued automatically -- **--disableA**: Disable A query - -- **--disableAAAA**: Disable AAAA query - - **--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) - **--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 @@ -890,7 +894,7 @@ Send a dns query ## dhcpserver -Run a standalone dhcp server. Other running dhcp servers need to be stopped. +Run a standalone dhcp server. IPv4 only. Other running dhcp servers need to be stopped. - **--cache**="": Cache file, local absolute file path, default is $HOME/.brook.dhcpserver @@ -946,27 +950,11 @@ Convert a socks5 proxy to a http proxy, [src <-> listen address(http proxy) <-> - **--tcpTimeout**="": Connection tcp timeout (s) (default: 0) -## pac - -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 - -- **--proxy, -p**="": Proxy, like: 'SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT' (default: SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT) - ## testsocks5 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) +- **--dns**="": A DNS Server to connect to and send TCP DNS query to test TCP, and UDP DNS query to test UDP. (default: 8.8.8.8:53) - **--example**: Show a minimal example of usage @@ -976,24 +964,16 @@ Test a socks5 server to see if it works properly - **--username, -u**="": Socks5 username -- **-a**="": The A record of domain (default: 137.184.237.95) - ## testbrook -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) +Test UDP and TCP of a brook server/wsserver/wssserver/quicserver connection. -- **--domain**="": Domain for query (default: http3.ooo) +- **--dns**="": A DNS Server to connect to and send TCP DNS query to test TCP, and UDP DNS query to test UDP. (default: 8.8.8.8:53) - **--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) - -- **-a**="": The A record of domain (default: 137.184.237.95) - ## echoserver Echo server, echo UDP and TCP address of routes @@ -1054,298 +1034,3 @@ Generate man.1 page Shows a list of commands or help for one command -# 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... -# 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 | - diff --git a/docs/build.js b/docs/build.js index 50c17fe97..96a118880 100755 --- a/docs/build.js +++ b/docs/build.js @@ -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` diff --git a/docs/gui.md b/docs/client.md similarity index 58% rename from docs/gui.md rename to docs/client.md index 3582f86ec..9901073dc 100644 --- a/docs/gui.md +++ b/docs/client.md @@ -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`. This will trigger the `in_dnsquery` variable, carrying information such as `domain` - 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`. This will trigger the `in_address` variable, carrying information such as `domainaddress` - 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). - -## With Brook: Fake DNS Off +Script can do more: -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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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`. This will trigger the `in_address` variable, carrying information such as `ipaddress` - 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 Server,instead, 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 - -[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 - ``` +## openwrt + +https://www.txthinking.com/talks/articles/brook-openwrt-en.article + +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: + +``` +cat _header.tengo > my.tengo + +cat block_google_secure_dns.tengo >> my.tengo +cat block_aaaa.tengo >> my.tengo + +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 CA,you 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). diff --git a/docs/example.md b/docs/example.md deleted file mode 100644 index 1ae9d00f1..000000000 --- a/docs/example.md +++ /dev/null @@ -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... diff --git a/docs/getting-started.md b/docs/getting-started.md index 7b929673c..d0410e382 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -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) diff --git a/docs/images/brook-client.svg b/docs/images/brook-client.svg new file mode 100644 index 000000000..6a1e81b65 --- /dev/null +++ b/docs/images/brook-client.svg @@ -0,0 +1,855 @@ +

App wants to connect google.com:443

+
AppSystem DNS(8.8.8.8:53)BrookServer query IP of google.comquery IP of google.comdefault: the IP is f.a.k.ethe IP is f.a.k.econnect f.a.k.e:443default: connect google.com:443script: in_dnsqueryscript: in_address + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/docs/images/brook-dns-server.svg b/docs/images/brook-dns-server.svg new file mode 100644 index 000000000..18c5b3aac --- /dev/null +++ b/docs/images/brook-dns-server.svg @@ -0,0 +1,849 @@ +

Client wants to query google.com

+
ClientBrook DNS Server--dns I want query IP of google.comdefault: query IP of google.comscript: in_dnsquery + + + + + + + + +
\ No newline at end of file diff --git a/docs/images/brook-server.svg b/docs/images/brook-server.svg new file mode 100644 index 000000000..e91cd6d0f --- /dev/null +++ b/docs/images/brook-server.svg @@ -0,0 +1,852 @@ +

Client wants to proxy google.com:443

+
Brook ClientBrook ServerServer System DNSgoogle.com:443 I want to proxy of google.com:443default: query IP of google.comthe IP is 1.2.3.4default: connect 1.2.3.4:443script: in_address + + + + + + + + + + + +
\ No newline at end of file diff --git a/docs/images/network.svg b/docs/images/network.svg new file mode 100644 index 000000000..7fcdca648 --- /dev/null +++ b/docs/images/network.svg @@ -0,0 +1,849 @@ +

App wants to connect google.com:443

+
AppSystem DNS(8.8.8.8:53)google.com:443 query IP of google.comthe IP is 1.2.3.4connect 1.2.3.4:443 + + + + + + + + +
\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 6600dbce5..91040b6fa 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1160,30 +1160,43 @@
  • Client
  • -
  • Client
  • -
  • Examples -
  • -
  • Resources
  • @@ -1260,30 +1248,43 @@

    Brook

  • Client
  • -
  • Client
  • -
  • Examples -
  • -
  • Resources
  • @@ -1368,19 +1344,425 @@

    Client

  • macOS
  • Windows
  • Linux
  • -
  • OpenWrt
  • +
  • OpenWrt
  • You may want to use brook link to customize some parameters

    +

    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

    +

    Script can do more:

    + +

    Brook Server

    +

    x

    +

    Script can do more:

    + +

    Variables

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    variabletypecommandtimingdescriptionout type
    in_dnsserversmapdnsserver/dnsserveroverbrook/dohserver/server/wsserver/wssserver/quicserverWhen just runningPredefine multiple dns servers, and then programmatically specify which one to usemap
    in_dohserversmapdnsserver/dnsserveroverbrook/dohserver/server/wsserver/wssserver/quicserverWhen just runningPredefine multiple doh servers, and then programmatically specify which one to usemap
    in_brooklinksmapserver/wsserver/wssserver/quicserverWhen just runningPredefine multiple brook links, and then programmatically specify which one to usemap
    in_dnsquerymapdnsserver/dnsserveroverbrook/dohserverWhen a DNS query occursScript can decide how to handle this requestmap
    in_addressmapserver/wsserver/wssserver/quicserverWhen the Server connects the proxied addressScript can decide how to handle this requestmap
    +

    in_dnsservers

    + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    _boolmeaninglesstrue
    +

    out, ignored if not of type map

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    ............
    custom namestringdns server8.8.8.8:53
    ............
    +

    in_dohservers

    + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    _boolmeaninglesstrue
    +

    out, ignored if not of type map

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    ............
    custom namestringdohserverhttps://dns.quad9.net/dns-query?address=9.9.9.9%3A443
    ............
    + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    _boolmeaninglesstrue
    +

    out, ignored if not of type map

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    ............
    custom namestringbrook linkbrook://...
    ............
    +

    in_dnsquery

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    fromipaddressstringclient address which send this request1.2.3.4:5
    domainstringdomain namegoogle.com
    typestringquery typeA
    ............
    tag_keystring--tag specifies the key valuetag_value
    ............
    +

    out, if it is error type will be recorded in the log. Ignored if not of type map

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    blockboolWhether Block, default falsefalse
    ipstringSpecify IP directly, only valid when type is A/AAAA1.2.3.4
    dnsserverkeystringUse the dnsserver specified by key to resolvecustom name
    dohserverkeystringUse the dohserver specified by key to resolvecustom name
    +

    in_address

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    networkstringtcp or udptcp
    fromipaddressstringclient address which send this request1.2.3.4:5
    ipaddressstringip address to be proxied1.2.3.4:443
    domainaddressstringdomain address to be proxiedgoogle.com:443
    userstringuser ID, only available when used with --userAPI9
    ............
    tag_keystring--tag specifies the key valuetag_value
    ............
    +

    out, if it is error type will be recorded in the log. Ignored if not of type map

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyTypeDescriptionExample
    blockboolWhether Block, default falsefalse
    addressstringRewrite destination to an address1.2.3.4
    ipaddressfromdnsserverkeystringIf the destination is domain address, use the dnsserver specified by key to resolvecustom name
    ipaddressfromdnsserverkeystringIf the destination is domain address, use the dohserver specified by key to resolvecustom name
    aoraaaastringMust be used with ipaddressfromdnsserverkey or ipaddressfromdnsserverkey. Valid value is A/AAAAA
    speedlimitintSet a rate limit for this request, for example 1000000 means 1000 kb/s1000000
    brooklinkkeystringUse the brook link specified by key to proxycustom name
    dialwithstringIf your server has multiple IPs or network interfaces, you can specify the IP or network interface name to initiate this request192.168.1.2 or 2606:4700:3030::ac43:a86a or en1

    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:

      @@ -1389,127 +1771,50 @@

      CLI

    For the specifics of socks5 and http proxy, you can read this article.

    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.

    -

    Without Brook: 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

    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

    1. When an app requests a domain address, such as google.com:443
    2. -
    3. 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. 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
      2. The system DNS will return the IP of google.com, such as 1.2.3.4, to the app
      3. -
      -
    4. The app will combine the IP and port into an IP address, such as: 1.2.3.4:443
    5. The app makes a network request to this IP address 1.2.3.4:443
    6. 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

    -

    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.

    +

    With Brook

    +

    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

    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. -
    4. The Brook client detects that an app is sending a network request to 8.8.8.8:53. This will trigger the in_dnsquery variable, carrying information such as domain
        +
      1. The Brook client detects that an app is sending a network request to 8.8.8.8:53. This will trigger the in_dnsquery variable, carrying information such as domain
      2. The Brook client returns a fake IP to the app, such as 240.0.0.1
      3. -
      -
    5. The app combines the IP and port into an IP address, such as: 240.0.0.1:443
    6. The app makes a network request to the IP address 240.0.0.1:443
    7. -
    8. 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. This will trigger the in_address variable, carrying information such as domainaddress
        +
      1. 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. This will trigger the in_address variable, carrying information such as domainaddress
      2. The Brook client sends google.com:443 to the Brook Server
      3. 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
      4. The Brook Server combines the IP and port into an IP address, such as: 1.2.3.4:443
      5. The Brook Server sends a network request to 1.2.3.4:443 and returns the data to the Brook client
      6. The Brook client then returns the data to the app
      7. -
      -
    9. 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:

    -

    To avoid the ineffectiveness of Fake DNS, please refer to this article.

    -

    With Brook: Fake DNS Off

    -
      -
    1. When an app requests a domain address, such as google.com:443
    2. -
    3. 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
    4. -
    5. The Brook client detects that an app is sending a network request to 8.8.8.8:53. This will trigger the in_address variable, carrying information such as ipaddress
        -
      1. The Brook client sends 8.8.8.8:53 to the Brook Server
      2. -
      3. 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
      4. -
      5. The Brook client then returns the result to the app
      6. -
      -
    6. -
    7. The app combines the IP and port into an IP address, such as: 1.2.3.4:443
    8. -
    9. The app makes a network request to the IP address 1.2.3.4:443
    10. -
    11. The Brook client detects that an app is sending a network request to 1.2.3.4:443. This will trigger the in_address variable, carrying information such as ipaddress
        -
      1. The Brook client sends 1.2.3.4:443 to the Brook Server
      2. -
      3. The Brook Server sends a network request to 1.2.3.4:443 and returns the data to the Brook client
      4. -
      5. The Brook client then returns the data to the app
      6. -
      -
    12. -
    13. The app receives the response data
    14. -
    -

    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. -
    3. 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
    4. -
    5. The Brook client detects that an app is sending a network request to 8.8.8.8:443. This will trigger the in_address variable, carrying information such as ipaddress
        -
      1. The Brook client sends 8.8.8.8:443 to the Brook Server
      2. -
      3. 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
      4. -
      5. The Brook client then returns the result to the app
      6. -
      -
    6. -
    7. The app combines the IP and port into an IP address, such as: 1.2.3.4:443
    8. -
    9. The app makes a network request to the IP address 1.2.3.4:443
    10. -
    11. The Brook client detects that an app is sending a network request to 1.2.3.4:443. This will trigger the in_address variable, carrying information such as ipaddress
        -
      1. The Brook client sends 1.2.3.4:443 to the Brook Server
      2. -
      3. The Brook Server sends a network request to 1.2.3.4:443 and returns the data to the Brook client
      4. -
      5. The Brook client then returns the data to the app
      6. -
      -
    12. -
    13. The app receives the response data
    14. -
    -

    To avoid the ineffectiveness of Fake DNS, please refer to this article.

    -

    Handle Variable Trigger

    +

    Script can do more:

    -

    For detailed information on the properties and responses of variables, please refer to the following content.

    -

    Variables

    +

    Variables

    @@ -1542,7 +1847,7 @@

    Variables

    - + @@ -1550,7 +1855,7 @@

    Variables

    - + @@ -1558,11 +1863,11 @@

    Variables

    - +
    map / When connecting to an addressscript can decide how to connectScript can decide how to handle this request map
    map / When an HTTP(S) request comes inthe script can decide how to handle this requestScript can decide how to handle this request map
    map / when an HTTP(S) response comes inthe script can decide how to handle this responseScript can decide how to handle this response map
    - + @@ -1608,7 +1913,7 @@
    ...
    -

    in_dnsquery

    +

    in_dnsquery

    @@ -1633,15 +1938,9 @@

    in_dnsquery

    - + - - - - - -
    appid stringApp ID or pathmacOS 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
    interfacestringnetwork interface. Mac onlyen0

    out, if it is error type will be recorded in the log. Ignored if not of type map

    @@ -1662,29 +1961,29 @@

    in_dnsquery

    - + - + - + - +
    ip stringSpecify IP directly, only valid when type is A/AAAAIgnore fake DNS, specify IP directly, only valid when type is A/AAAA 1.2.3.4
    system boolResolve by System DNS, default falseIgnore fake DNS, resolve by System DNS over brook, default false false
    bypass boolResolve by Bypass DNS, default falseIgnore fake DNS, resolve by Bypass DNS, default false false
    brooklinkkey stringWhen need to connect the Server,instead, connect to the Server specified by the key in_brooklinksWhen need to connect the Server, instead, perfer connect to the Server specified by the key in_brooklinks custom name
    -

    in_address

    +

    in_address

    @@ -1703,7 +2002,7 @@

    in_address

    - + @@ -1715,15 +2014,9 @@

    in_address

    - + - - - - - -
    ipaddress stringIP type address. There is only of ipaddress and domainaddress. Note that there is no relationship between these twoIP type address. There is only one of ipaddress and domainaddress. Note that there is no relationship between these two 1.2.3.4:443
    appid stringApp ID or pathmacOS 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
    interfacestringnetwork interface. Mac onlyen0

    out, if it is error type will be recorded in the log. Ignored if not of type map

    @@ -1744,7 +2037,7 @@

    in_address

    - + @@ -1756,7 +2049,7 @@

    in_address

    - + @@ -1774,7 +2067,7 @@

    in_address

    - + @@ -1786,7 +2079,7 @@

    in_address

    - + @@ -1849,7 +2142,7 @@

    in_httprequest

    ipaddress stringIP type address, rewrite destinationRewrite destination to an ip address 1.2.3.4:443
    bypass boolBypass, default false. If true and domainaddress, then ipaddress or ipaddressfrombypassdns must be specifiedBypass, default false. If true and domainaddress exists, then ipaddress or ipaddressfrombypassdns must be specified false
    mitmcertdomain stringThe 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 explicitlyThe 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
    mitmautohandlecompress boolWhether to automatically decompress the http body when interacting with the script, default falseWhether to automatically decompress the http body when interacting with the script, default false. Usually need set this to true false
    /
    -

    out, must be set to a request or response

    +

    out, must be set to an unmodified or modified request or a response

    in_httpresponse

    @@ -1879,9 +2172,9 @@

    in_httpresponse

    /
    -

    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, and thre is no magic, it just automatically combine _header.tengo and _footer.tengo, so you only need to write the module itself.

    +

    In Brook GUI, scripts are abstracted into Modules. There are already some modules, and there is no magic, it just 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) {
    @@ -1905,9 +2198,9 @@ 

    Modules

    } })
    -

    tun2brook

    -

    https://github.com/txthinking/tun2brook

    -

    If you are using tun2brook, you can manually combine multiple modules into a complete script in the following way. For example:

    +

    ipio

    +

    https://github.com/txthinking/ipio

    +

    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
     
     cat block_google_secure_dns.tengo >> my.tengo
    @@ -1915,61 +2208,18 @@ 

    tun2brook

    cat _footer.tengo >> my.tengo
    -

    Syntax

    -

    Tengo Language Syntax

    -

    Library

    -

    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

    +

    If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use ipio on desktop to debug with fmt.println

    CA

    https://txthinking.github.io/ca/ca.pem

    @@ -1999,8 +2249,6 @@

    CA

    Some software may not read the system CA,you can use curl --cacert ~/.nami/bin/ca.pem to debug

    -

    OpenWrt

    -

    Brook OpenWRT: Perfectly supports IPv4/IPv6/TCP/UDP

    IPv6

    Brook's stance on IPv6 is positive, if your server or local environment doesn't have an IPv6 stack, read this article.

    Troubleshooting Steps

    @@ -2054,8 +2302,166 @@

    Troubleshooting Steps

  • Submit new issue
  • Seek help in the group
  • +

    Other

    +

    Script Syntax

    +

    I think just reading this one page is enough: Tengo Language Syntax

    +

    Library

    + +

    Example

    +

    Each subcommand has a --example, such as:

    +
    brook server --example
    +
    +

    Resources

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CLIDescription
    namiA clean and tidy decentralized package manager
    jokerJoker can turn process into daemon. Zero-Configuration
    nicoNico can work with brook wsserver together
    zz - process manager
    ipioProxy all traffic just one line command
    madGenerate root CA and derivative certificate for any domains and any IPs
    hancockManage multiple remote servers and execute commands remotely
    sshexecA command-line tool to execute remote command through ssh
    bashMany one-click scripts
    dockerdocker run txthinking/brook
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ResourcesDescription
    ProtocolBrook Protocol
    BlogSome articles you should read
    YouTubeSome videos you should watch
    TelegramAsk questions here
    AnnounceAll news you should care
    GitHubOther useful repos
    Socks5 ConfiguratorIf you prefer CLI brook client
    IPvBarSee domain, IP and country in browser
    TxThinking SSHA SSH Terminal
    brook-storeA Brook User System
    TxThinkingEverything

    CLI Documentation

    -

    Each subcommand has a --example parameter that can print the minimal example of usage

    NAME

    Brook - A cross-platform programmable network tool

    SYNOPSIS

    @@ -2067,83 +2473,37 @@

    SYNOPSIS

    GLOBAL OPTIONS

    COMMANDS

    -

    server

    +

    server

    Start a brook server that supports tcp and udp

    client

    Start a brook client that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook client <-> $ brook server <-> dst]

    @@ -2182,14 +2540,6 @@

    client

    wsserver

    Start a brook wsserver that supports tcp and udp. It opens a standard http server and a websocket server

    @@ -2234,14 +2580,6 @@

    wsclient

    wssserver

    Start a brook wssserver that supports tcp and udp. It opens a standard https server and a websocket server

    wssclient

    Start a brook wssclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook wssclient <-> $ brook wssserver <-> dst]

    @@ -2288,14 +2622,6 @@

    wssclient

    quicserver

    Start a brook quicserver that supports tcp and udp.

    quicclient

    -

    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)

    +

    Start a brook quicclient that supports tcp and udp. It can open a socks5 proxy, [src <-> socks5 <-> $ brook quicclient <-> $ brook quicserver <-> dst]

    dnsserveroverbrook

    -

    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]

    +

    Run a dns server over brook, which supports TCP and UDP, [src <-> $ brook dnserversoverbrook <-> $ brook server/wsserver/wssserver/quicserver <-> dns]

    +

    connect

    +

    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]

    + -

    connect

    -

    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]

    -

    relay

    Run a standalone relay, which supports TCP and UDP. Accessing [from address] is equal to accessing [to address], [src <-> from address <-> to address]

    @@ -2454,12 +2764,6 @@

    relay

    dnsserver

    Run a standalone dns server

    help, h

    Shows a list of commands or help for one command

    -

    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

    - -

    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

    - -

    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

    - -

    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

    - -

    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

    -
    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

    -
    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

    - -

    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

    - -

    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...

    -

    Resources

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CLIDescription
    namiA clean and tidy decentralized package manager
    jokerJoker can turn process into daemon. Zero-Configuration
    nicoNico can work with brook wsserver together
    zz - process manager
    tun2brookProxy all traffic just one line command
    madGenerate root CA and derivative certificate for any domains and any IPs
    hancockManage multiple remote servers and execute commands remotely
    sshexecA command-line tool to execute remote command through ssh
    jbwrite script in an easier way than bash
    bashMany one-click scripts
    dockerdocker run txthinking/brook
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ResourcesDescription
    ProtocolBrook Protocol
    BlogSome articles you should read
    YouTubeSome videos you should watch
    TelegramAsk questions here
    AnnounceAll news you should care
    GitHubOther useful repos
    Socks5 ConfiguratorIf you prefer CLI brook client
    IPvBarSee domain, IP and country in browser
    TxThinking SSHA SSH Terminal
    brook-user-systemA Brook User System
    TxThinkingEverything
    diff --git a/docs/other.md b/docs/other.md new file mode 100644 index 000000000..cea2fa47c --- /dev/null +++ b/docs/other.md @@ -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 | + diff --git a/docs/resources.md b/docs/resources.md deleted file mode 100644 index f4d61f62c..000000000 --- a/docs/resources.md +++ /dev/null @@ -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 | - diff --git a/docs/server.md b/docs/server.md new file mode 100644 index 000000000..3b2cf03c2 --- /dev/null +++ b/docs/server.md @@ -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 | diff --git a/programmable/dnsserver/check_syntax.js b/programmable/dnsserver/check_syntax.js new file mode 100755 index 000000000..402d22569 --- /dev/null +++ b/programmable/dnsserver/check_syntax.js @@ -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` +} + diff --git a/programmable/dnsserver/example.tengo b/programmable/dnsserver/example.tengo new file mode 100644 index 000000000..84efe918b --- /dev/null +++ b/programmable/dnsserver/example.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() + diff --git a/programmable/dnsserver/readme.md b/programmable/dnsserver/readme.md new file mode 100644 index 000000000..34f41068c --- /dev/null +++ b/programmable/dnsserver/readme.md @@ -0,0 +1,2 @@ +brook dnsserver, dohserver, dnsserveroverbrook + diff --git a/programmable/list/example_cidr4.txt b/programmable/list/example_cidr4.txt deleted file mode 100644 index 3b932ac36..000000000 --- a/programmable/list/example_cidr4.txt +++ /dev/null @@ -1,3 +0,0 @@ -127.0.0.0/32 -192.168.1.0/24 -1.2.4.8/32 diff --git a/programmable/list/example_cidr6.txt b/programmable/list/example_cidr6.txt deleted file mode 100644 index 4109838c1..000000000 --- a/programmable/list/example_cidr6.txt +++ /dev/null @@ -1,3 +0,0 @@ -::1/128 -fd00::/8 -2001:dc7:1000::1/128 diff --git a/programmable/list/example_domain.txt b/programmable/list/example_domain.txt deleted file mode 100644 index 9fc0e571b..000000000 --- a/programmable/list/example_domain.txt +++ /dev/null @@ -1,3 +0,0 @@ -lt -a.com -c.b.com diff --git a/programmable/modules/bypass_china_domain.tengo b/programmable/modules/bypass_china_domain.tengo index 526bff179..3c0a543f3 100644 --- a/programmable/modules/bypass_china_domain.tengo +++ b/programmable/modules/bypass_china_domain.tengo @@ -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) { diff --git a/programmable/modules/bypass_china_domain_a.tengo b/programmable/modules/bypass_china_domain_a.tengo index 48306b39d..8bae91af3 100644 --- a/programmable/modules/bypass_china_domain_a.tengo +++ b/programmable/modules/bypass_china_domain_a.tengo @@ -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) { diff --git a/programmable/modules/chatgpt_advanced_voice.tengo b/programmable/modules/chatgpt_advanced_voice.tengo new file mode 100644 index 000000000..6bcdc3764 --- /dev/null +++ b/programmable/modules/chatgpt_advanced_voice.tengo @@ -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 } + } + } + } +}) diff --git a/programmable/modules/check_syntax.js b/programmable/modules/check_syntax.js index 51e330fa4..d757ebe2e 100755 --- a/programmable/modules/check_syntax.js +++ b/programmable/modules/check_syntax.js @@ -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` diff --git a/programmable/modules/instagram_system_dns.tengo b/programmable/modules/instagram_system_dns.tengo index 0a72fe6a4..c74a04465 100644 --- a/programmable/modules/instagram_system_dns.tengo +++ b/programmable/modules/instagram_system_dns.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 + } } }) + diff --git a/programmable/modules/readme.md b/programmable/modules/readme.md index a8e7f95dd..5cff35617 100644 --- a/programmable/modules/readme.md +++ b/programmable/modules/readme.md @@ -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 diff --git a/programmable/server/check_syntax.js b/programmable/server/check_syntax.js new file mode 100755 index 000000000..30cba7604 --- /dev/null +++ b/programmable/server/check_syntax.js @@ -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` +} + diff --git a/programmable/server/example.tengo b/programmable/server/example.tengo new file mode 100644 index 000000000..8e965ce08 --- /dev/null +++ b/programmable/server/example.tengo @@ -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() + diff --git a/programmable/server/readme.md b/programmable/server/readme.md new file mode 100644 index 000000000..21d44db7f --- /dev/null +++ b/programmable/server/readme.md @@ -0,0 +1,2 @@ +brook server, wsserver, wssserver, quicserver + diff --git a/protocol/brook-quicserver-wbp-protocol.md b/protocol/brook-quicserver-wbp-protocol.md deleted file mode 100644 index c0031c7da..000000000 --- a/protocol/brook-quicserver-wbp-protocol.md +++ /dev/null @@ -1,63 +0,0 @@ -# brook quicserver --withoutBrookProtocol protocol - - - - -## 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) diff --git a/protocol/brook-wsserver-wbp-protocol.md b/protocol/brook-wsserver-wbp-protocol.md deleted file mode 100644 index 61862c616..000000000 --- a/protocol/brook-wsserver-wbp-protocol.md +++ /dev/null @@ -1,69 +0,0 @@ -# brook wsserver --withoutBrookProtocol protocol - - - - -## 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
    -> The maximum length of `[Fragment Length + Fragment]` is 65507 bytes
    - -- `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
    - -- `Fragment Length`: Big Endian 16-bit unsigned integer -- `Fragment`: Actual data being proxied diff --git a/protocol/user.md b/protocol/user.md index ddc4af15c..1ebb7e509 100644 --- a/protocol/user.md +++ b/protocol/user.md @@ -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"}