diff --git a/Dockerfile b/Dockerfile index 33d807b..c428a85 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # Stage 1 -FROM alpine:3.15 as builder -RUN apk add --no-cache git build-base libev-dev cmake && \ +FROM alpine:3.15 AS builder +RUN apk add --no-cache git build-base libev-dev cmake argp-standalone && \ mkdir -p /source/build ARG SOURCE=https://github.com/zhc105/Liteflow.git ARG BRANCH=master @@ -54,12 +54,12 @@ ENV tag="main" \ forward_rules="" RUN mkdir -p /app/bin && \ - mkdir -p /app/config + mkdir -p /app/etc WORKDIR /app COPY --from=builder /source/Liteflow/build/src/liteflow /app/bin -COPY docker/liteflow.conf.template /app/config +COPY docker/liteflow.conf.template /app/etc COPY docker/docker-start.sh /app RUN chmod +x /app/docker-start.sh diff --git a/README.cn.md b/README.cn.md index c89010c..51ca849 100644 --- a/README.cn.md +++ b/README.cn.md @@ -77,7 +77,7 @@ cd ./scripts/liteflow.sh status --local ``` -####示例1: 服务端1.2.3.4开放TCP 1501端口,映射到客户端192.168.1.100:1501 +#### 示例1: 服务端1.2.3.4开放TCP 1501端口,映射到客户端192.168.1.100:1501 部署方式: ``` @@ -130,7 +130,7 @@ cd } ``` -####示例2: 客户端192.168.1.100开放TCP 1501端口,通过反向连接映射到服务端1.2.3.4:1501 +#### 示例2: 客户端192.168.1.100开放TCP 1501端口,通过反向连接映射到服务端1.2.3.4:1501 部署方式: ``` @@ -182,6 +182,11 @@ cd } ``` +#### `entrance_rule`的`node_id` +⚠️ 请注意,如果`entrance_rule`不指定`node_id`,则本节点会从所有连接的peers中任意选择一个发送,即使该peer并不支持该`tunnel_id`。两个peer在连接时并不会交换`tunnel_id`列表,双方并不知晓对方所支持的`tunnel_id`信息。 + +**因此,Liteflow 被设计为每个进程仅支持一个用途单一的隧道。若需使用多个隧道,建议为每个隧道分别启动独立的 Liteflow 进程,并配以各自的配置文件。** + ### Cygwin编译Windows版本 Liteflow支持通过Cygwin编译提供Windows可用版本。 @@ -194,5 +199,24 @@ Cygwin必须至少安装以下Packages: * cmake * autoconf * libtool - -其它编译步骤与正常流程相同。编译完成后,将`cygwin1.dll`和产生的`liteflow.exe`复制到需要运行Liteflow的Windows机器上,准备好相应的配置文件并直接运行`liteflow.exe`。 +* libargp-devel + +其它编译步骤与正常流程相同。编译完成后,将以下文件复制到需要运行Liteflow的Windows机器上,准备好相应的配置文件并直接运行`liteflow.exe`。 +* cygwin1.dll +* cygargp-0.dll +* liteflow.exe + +⚠️ 注意Cygwin上的默认DNS服务器配置似乎有问题,请在配置文件的`service`一节中设置可用的DNS服务器,例如`"dns_server": "8.8.8.8",`。 + +#### 如何开机后台运行liteflow +由于liteflow为命令行程序,建议使用cmder,在Windows登录后自动启动liteflow,并自动最小化到系统托盘。 +1. 下载cmder,在`Settings...` -> `General` -> `Task bar`里选中`Auto minimize to TSA`。 +2. 创建cmder.exe的快捷方式,右键点击该快捷方式,在"目标"里添加后缀参数 + ```bash + /TASK "liteflow" /x -MinTSA + ``` + 最终的结果看起来像例如 + ```bash + C:\tools\cmder\Cmder.exe /TASK "liteflow" /x -MinTSA` + ``` +3. 在文件浏览器中粘贴`shell:startup`并回车,打开自动启动目录。将该快捷方式移入该目录。 diff --git a/README.md b/README.md index 2e91e10..24d62b3 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,12 @@ UDP tunnel & TCP/UDP Port forwarding ### Introduction -Liteflow implements a simple and reliable UDP transport protocol (LiteDT), and based on this protocol, develops a TCP/UDP port forwarding tool. Both the client and the server use the same binary, with the only difference being the configuration file. +Liteflow implements a simple and reliable UDP transport protocol (LiteDT) and has developed a TCP/UDP port forwarding tool based on this protocol. Both the client and the server use the same binary, with the only difference being the configuration file. You can use this tool to: 1. Accelerate TCP transmission speed in high-latency and high-packet-loss environments, or ensure UDP packets are delivered reliably and in order. -2. Map internal network ports to public servers through reverse connections, enabling internal ports to be actively accessed across NAT. +2. Map internal network ports to public servers through reverse connections, enabling direct access to internal ports across NAT. ### Build and Usage Guide ``` @@ -38,12 +38,12 @@ cd ./bin/liteflow --version # Deploy configuration file -# Example configs are in the etc folder, copy to etc/liteflow.conf and modify accordingly +# Example configs are in the etc folder, copy them to etc/liteflow.conf and modify accordingly # Test whether the configuration file is valid ./bin/liteflow -t -c ./liteflow.conf -# Run; it reads the config file named {binary_name}.conf in the current directory by default. For example, if the binary is liteflow, config file should be liteflow.conf +# Run; it reads the config file named {binary_name}.conf in the current directory by default. For example, if the binary is liteflow, the config file should be liteflow.conf ./bin/liteflow # Or specify config file path @@ -60,7 +60,7 @@ A set of control scripts is provided to make integration with crontab or systemd cd ./scripts/liteflow.sh start --local -# Check if process is alive, restart if not +# Check if the process is alive; restart if not ./scripts/liteflow.sh revive --local # Force reload configuration @@ -181,6 +181,11 @@ Client (192.168.1.100) config example: } ``` +#### `node_id` in `entrance_rule` +⚠️ Note: If `entrance_rule` does not specify a node_id, the current node will arbitrarily select one of the connected peers to send the data to — even if that peer does not support the specified `tunnel_id`. This happens because peers do not exchange their supported `tunnel_id` lists during the connection process, so neither side is aware of the other's `tunnel_id` capabilities. + +**Liteflow is designed so that each process supports only a single-purpose tunnel. If multiple tunnels are needed, it is recommended to run separate Liteflow processes, each with its own configuration file.** + ### Building Windows Version via Cygwin Liteflow supports building a Windows version using Cygwin. @@ -193,5 +198,24 @@ Cygwin must have the following packages installed: * cmake * autoconf * libtool - -Other build steps are the same. After building, copy `cygwin1.dll` and the generated `liteflow.exe` to the target Windows machine. Prepare the appropriate configuration file and directly run `liteflow.exe`. +* libargp-devel + +The remaining compilation steps follow the standard procedure. After compilation, copy the following files to the Windows machine where you want to run Liteflow. Prepare the corresponding configuration files, then run liteflow.exe directly. +* cygwin1.dll +* cygargp-0.dll +* liteflow.exe + +⚠️ Note: The default DNS server configuration on Cygwin appears to be problematic. Please specify a working DNS server in the `service` section of the configuration file, for example: `"dns_server": "8.8.8.8",`. + +#### How to Run liteflow in the Background at Startup +Since liteflow is a command-line program, it’s recommended to use cmder to automatically launch it when Windows starts and minimize it to the system tray. +1. Download cmder. In `Settings...` → `General` → `Task bar`, check the option `Auto minimize to TSA`. +2. Create a shortcut to Cmder.exe. Right-click the shortcut, and in the `Target` field, add the following suffix: + ```bash + /TASK "liteflow" /x -MinTSA + ``` + The final result should look something like: + ```bash + "C:\tools\cmder\Cmder.exe" /TASK "liteflow" /x -MinTSA + ``` +3. In File Explorer, type `shell:startup` and press Enter to open the Startup folder. Move the shortcut into this folder to enable auto-start. diff --git a/docker/README.cn.md b/docker/README.cn.md new file mode 100644 index 0000000..43185fa --- /dev/null +++ b/docker/README.cn.md @@ -0,0 +1,111 @@ +### 编译Docker镜像 + +#### 方式1: 从远程Git仓库构建(使用默认仓库和分支) +适用场景:直接使用作者仓库的稳定版本 +``` +docker build --build-arg BRANCH=master -t liteflow:master . +``` +- 代码来源:从 `https://github.com/zhc105/Liteflow.git` 自动下载 +- 使用分支:master(可通过BRANCH参数指定其他分支) + +#### 方式2: 从指定的远程Git仓库和分支构建 +适用场景:使用其他fork仓库或特定分支的代码 +``` +docker build --build-arg SOURCE=https://github.com/zhc105/Liteflow.git --build-arg BRANCH=master -t liteflow:master . +``` +- 代码来源:从指定的Git仓库URL下载 +- 使用分支:通过BRANCH参数指定 + +#### 方式3: 使用本地当前目录代码构建(不从Git下载) +适用场景:开发测试阶段,使用本地修改过的代码(包括未提交的更改) +``` +# option 1 +docker build --build-arg SOURCE=local -t liteflow:local . +# option 2 +docker build --build-arg SOURCE=. -t liteflow:local . +# option 3 +docker build --build-arg SOURCE=./ -t liteflow:local . +``` +- 代码来源:直接使用当前目录的代码文件 +- 无需网络连接,可以包含本地未提交的修改 + +### 启动容器 + +#### 方式1: 使用环境变量动态生成配置 + +脚本示例: +```bash +#!/bin/bash + +entrance_rules=$(cat <<- EOM +EOM +) + +forward_rules=$(cat <<- EOM + { + "tunnel_id": 100, // Tunnel ID和服务端entrance_rules对应 + "destination_addr": "127.0.0.1", // 为此Tunnel指定转发目标地址 + "destination_port": 1501 // 指定转发目标端口 + }, +EOM +) + +connect_peers=$(cat <<- EOM + "1.2.3.4:1901", +EOM +) + +docker run --network host --name liteflow-main -d --restart=always \ + --env tag="main" \ + --env max_incoming_peers="0" \ + --env connect_peers="$connect_peers" \ + --env node_id="1001" \ + --env password="your-password" \ + --env entrance_rules="$entrance_rules" \ + --env forward_rules="$forward_rules" \ + liteflow:master +``` + +#### 方式2: 使用预置配置文件 + +**步骤1**: 准备配置文件 +```bash +# 创建配置文件,可以参考 examples/ 目录下的示例 +cat > /host/path/to/liteflow.conf << 'EOF' +{ + "service": { + "max_incoming_peers": 0, + "connect_peers": [ + "1.2.3.4:1901" + ], + "node_id": 1001, + "listen_addr": "0.0.0.0", + "listen_port": 0 + }, + "transport": { + "password": "your-password" + }, + "entrance_rules": [ + ], + "forward_rules": [ + { + "tunnel_id": 100, + "destination_addr": "127.0.0.1", + "destination_port": 1501 + } + ] +} +EOF +``` + +**步骤2**: 启动容器并挂载配置文件 +```bash +docker run --network host --name liteflow-main -d --restart=always \ + -v /host/path/to/liteflow.conf:/app/config/liteflow.conf \ + --env confpath="/app/config/liteflow.conf" \ + liteflow:master +``` + +**注意事项**: +- 容器会检查配置文件是否存在,不存在则启动失败 +- 使用预置配置文件时,所有环境变量配置参数都会被忽略 diff --git a/docker/README.md b/docker/README.md index fb7e5ee..5c17d8c 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,17 +1,23 @@ -### 编译Docker镜像 +### Building Docker Images -命令示例: -默认从作者仓库master分支构建 +#### Method 1: Build from Remote Git Repository (Using Default Repository and Branch) +Use case: Use the stable version directly from the author's repository ``` docker build --build-arg BRANCH=master -t liteflow:master . ``` +- Code source: Automatically downloaded from `https://github.com/zhc105/Liteflow.git` +- Branch used: master (can specify other branches via BRANCH parameter) -指定构建仓库和分支 +#### Method 2: Build from Specified Remote Git Repository and Branch +Use case: Use code from other forked repositories or specific branches ``` -docker build --build-arg SOURCE=https://github.com/zhc105/Liteflow.git BRANCH=master -t liteflow:master . +docker build --build-arg SOURCE=https://github.com/zhc105/Liteflow.git --build-arg BRANCH=master -t liteflow:master . ``` +- Code source: Downloaded from the specified Git repository URL +- Branch used: Specified via BRANCH parameter -复制本地代码并构建 +#### Method 3: Build Using Local Current Directory Code (No Git Download) +Use case: Development and testing phase, using locally modified code (including uncommitted changes) ``` # option 1 docker build --build-arg SOURCE=local -t liteflow:local . @@ -20,11 +26,15 @@ docker build --build-arg SOURCE=. -t liteflow:local . # option 3 docker build --build-arg SOURCE=./ -t liteflow:local . ``` +- Code source: Use code files directly from the current directory +- No network connection required; can include uncommitted local modifications -### 启动容器 +### Starting Containers -脚本示例: -``` +#### Method 1: Dynamic Configuration Generation Using Environment Variables + +Script example: +```bash #!/bin/bash entrance_rules=$(cat <<- EOM @@ -33,9 +43,9 @@ EOM forward_rules=$(cat <<- EOM { - "tunnel_id": 100, // Tunnel ID和服务端entrance_rules对应 - "destination_addr": "127.0.0.1", // 为此Tunnel指定转发目标地址 - "destination_port": 1501 // 指定转发目标端口 + "tunnel_id": 100, // Tunnel ID corresponds to server-side entrance_rules + "destination_addr": "127.0.0.1", // Specify forwarding target address for this tunnel + "destination_port": 1501 // Specify forwarding target port }, EOM ) @@ -54,4 +64,48 @@ docker run --network host --name liteflow-main -d --restart=always \ --env entrance_rules="$entrance_rules" \ --env forward_rules="$forward_rules" \ liteflow:master -``` \ No newline at end of file +``` + +#### Method 2: Using Pre-configured Configuration File + +**Step 1**: Prepare configuration file +```bash +# Create configuration file, you can refer to examples in the examples/ directory +cat > /host/path/to/liteflow.conf << 'EOF' +{ + "service": { + "max_incoming_peers": 0, + "connect_peers": [ + "1.2.3.4:1901" + ], + "node_id": 1001, + "listen_addr": "0.0.0.0", + "listen_port": 0 + }, + "transport": { + "password": "your-password" + }, + "entrance_rules": [ + ], + "forward_rules": [ + { + "tunnel_id": 100, + "destination_addr": "127.0.0.1", + "destination_port": 1501 + } + ] +} +EOF +``` + +**Step 2**: Start container and mount configuration file +```bash +docker run --network host --name liteflow-main -d --restart=always \ + -v /host/path/to/liteflow.conf:/app/config/liteflow.conf \ + --env confpath="/app/config/liteflow.conf" \ + liteflow:master +``` + +**Important Notes**: +- The container will check if the configuration file exists, and will fail to start if it doesn't exist +- When using a pre-configured file, all environment variable configuration parameters will be ignored diff --git a/docker/docker-start.sh b/docker/docker-start.sh index 9732c84..a488fdb 100644 --- a/docker/docker-start.sh +++ b/docker/docker-start.sh @@ -5,9 +5,9 @@ declare -g gen_confpath if [[ -z "${tag}" ]]; then - gen_confpath="./config/liteflow.conf" + gen_confpath="./etc/liteflow.conf" else - gen_confpath="./config/liteflow-${tag}.conf" + gen_confpath="./etc/liteflow-${tag}.conf" fi escape_string() { @@ -36,7 +36,7 @@ emplace_variable() { } generate_config() { - mv ./config/liteflow.conf.template $gen_confpath + mv ./etc/liteflow.conf.template $gen_confpath escape_string "$connect_peers"; connect_peers="$ret" escape_string "$entrance_rules"; entrance_rules="$ret" @@ -64,9 +64,17 @@ if [ -z "$confpath" ]; then # Generate config file for liteflow node generate_config else + # Check if the specified config file exists + if [ ! -f "$confpath" ]; then + echo "Error: Config file '$confpath' does not exist!" + echo "Please make sure the file is mounted and the path is correct." + exit 1 + fi # override confpath gen_confpath=$confpath fi # Launch liteflow node -./bin/liteflow -c $gen_confpath +# liteflow will be the pid=1 process after exec, which allows liteflow to handle +# signals from other sidecar containers. +exec ./bin/liteflow -c $gen_confpath diff --git a/scripts/liteflow.sh b/scripts/liteflow.sh index ed61cbd..5d0a57c 100755 --- a/scripts/liteflow.sh +++ b/scripts/liteflow.sh @@ -1,16 +1,16 @@ #!/bin/bash -# This script is used for crontab and manual operation. +# This script is used for crontab and manual operations. # There are two modes: local, global (by default): # local: Start liteflow from a local folder and all configuration/log/pid # files are placed in local folder. This mode is typically used when you # have multiple liteflow copies on the same machine, which have different # binaries or configurations. -# global: This is the default mode. If you have installed liteflow in global -# position, use this mode. +# global: This is the default mode. If you have installed liteflow in a global +# location, use this mode. -# **NOTE** bash will not exit even if any command exits with non-zero. -# the script will take care of the liteflow process. +# **NOTE** bash will not exit even if any command exits with a non-zero exit code. +# the script will take care of the workflow. set +e PACKAGE_NAME=liteflow @@ -101,15 +101,7 @@ start() { ulimit -n 65536 if [ ! -d /etc/logrotate.d ]; then - log -r "Logrotate directory not found, using logger output. Please install logrotate if needed." - - # Don't use nohup directly since it will print "nohup: redirecting stderr to stdout". - # But if we use: - # nohup bash -c "/usr/bin/env TZ=Asia/Shanghai $CMD 2>&1 | /usr/bin/logger -t ${PACKAGE_NAME}" >/dev/null 2>&1 & - # Then the PID $! will be the parent "bash -c" PID. - # That's why we use `disown` here. - /usr/bin/env TZ=Asia/Shanghai $CMD 2>&1 | /usr/bin/logger -t ${PACKAGE_NAME} & - disown + log -r "Logrotate directory not found, writing to single log file directly. Please install logrotate if needed." else ROTATE_CONFIG="$LOG_FILE { daily @@ -149,11 +141,16 @@ start() { fi log -r "Created new logrotate config at $ROTATE_FILE." fi - - /usr/bin/env TZ=Asia/Shanghai $CMD 2>&1 >> $LOG_FILE & - disown fi + # Don't use nohup directly since it will print "nohup: redirecting stderr to stdout". + # But if we use: + # nohup bash -c "/usr/bin/env TZ=Asia/Shanghai $CMD 2>&1 | /usr/bin/logger -t ${PACKAGE_NAME}" >/dev/null 2>&1 & + # Then the PID $! will be the parent "bash -c" PID. + # That's why we use `disown` here as a workaround. + /usr/bin/env TZ=Asia/Shanghai $CMD >> "$LOG_FILE" 2>&1 < /dev/null & + disown + echo $! > "$PID_FILE" log "${PACKAGE_NAME} started (PID $(cat $PID_FILE))." } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d401c3a..08ae0eb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,10 +17,12 @@ SET(GITREV_TMP ${CMAKE_CURRENT_BINARY_DIR}/gen/${GITREV_BARE_TMP}) ADD_CUSTOM_COMMAND( OUTPUT ${GITREV_TMP} ${GITREV_FILE} COMMAND ${CMAKE_COMMAND} -E echo_append "#define GIT_BRANCH_STR " > ${GITREV_TMP} - COMMAND ${GIT_EXECUTABLE} describe --tags --dirty=-unclean >> ${GITREV_TMP} + # If no tag in current repo, use short hash instead. Otherwise build would fail in a new + # cloned repo which has not cloned any tag. + COMMAND sh -c "${GIT_EXECUTABLE} describe --tags --dirty=-unclean 2>/dev/null || ${GIT_EXECUTABLE} rev-parse --short HEAD" >> ${GITREV_TMP} COMMAND ${CMAKE_COMMAND} -E echo "#define STR(S) #S" >> ${GITREV_TMP} COMMAND ${CMAKE_COMMAND} -E echo "#define XSTR(S) STR(S)" >> ${GITREV_TMP} - COMMAND ${CMAKE_COMMAND} -E echo "const char* liteflow_version = \"liteflow.git/\" XSTR(GIT_BRANCH_STR); " >> ${GITREV_TMP} + COMMAND ${CMAKE_COMMAND} -E echo "const char* liteflow_version = \"liteflow.git/\" XSTR(GIT_BRANCH_STR);" >> ${GITREV_TMP} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GITREV_TMP} ${GITREV_FILE} COMMAND ${CMAKE_COMMAND} -E remove ${GITREV_TMP} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -46,7 +48,16 @@ add_dependencies(liteflow ev) add_dependencies(liteflow c-ares) add_dependencies(liteflow common) target_include_directories(liteflow PRIVATE ${jsonparser_INCLUDES} ${libcares_INCLUDES} ${libev_INCLUDES} ${libcommon_INCLUDES}) -target_link_libraries(liteflow c-ares ev common m) + +# Detect if building on Cygwin +if(CYGWIN) + message(STATUS "Detected Cygwin: linking with extra libraries") + set(CYGWIN_EXTRA_LIB argp) +else() + set(CYGWIN_EXTRA_LIB "") +endif() + +target_link_libraries(liteflow c-ares ev ${CYGWIN_EXTRA_LIB} common m argp) add_executable(litedt_test litedt_test.c @@ -60,7 +71,7 @@ add_executable(litedt_test add_dependencies(litedt_test common) target_include_directories(litedt_test PRIVATE ${jsonparser_INCLUDES} ${libcommon_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(litedt_test common m) +target_link_libraries(litedt_test ${CYGWIN_EXTRA_LIB} common m argp) install(TARGETS liteflow RUNTIME DESTINATION bin) diff --git a/src/liteflow.c b/src/liteflow.c index 5a3db30..2ae50ab 100644 --- a/src/liteflow.c +++ b/src/liteflow.c @@ -539,7 +539,7 @@ resolve_outbound_peer(peer_info_t *peer) int af = get_addr_family(peer->address); if (af == AF_INET) { - // peer->address is a IPv4 address + // peer->address is an IPv4 address struct sockaddr_in *addr = (struct sockaddr_in *)&storage; socklen_t addr_len = sizeof(struct sockaddr_in); addr->sin_family = AF_INET; @@ -548,7 +548,7 @@ resolve_outbound_peer(peer_info_t *peer) peer_start(peer, (struct sockaddr *)addr, addr_len); } else if (af == AF_INET6) { - // peer->address is a IPv6 address + // peer->address is an IPv6 address struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage; socklen_t addr_len = sizeof(struct sockaddr_in6); addr->sin6_family = AF_INET6; @@ -1219,4 +1219,4 @@ void start_liteflow() while (1) { ev_loop(loop, 0); } -} \ No newline at end of file +} diff --git a/src/main.c b/src/main.c index 9378d7a..c686b9b 100644 --- a/src/main.c +++ b/src/main.c @@ -47,6 +47,8 @@ const char doc[] = "UDP tunnel & TCP/UDP Port forwarding"; static struct argp_option options[] = { {"config", 'c', "CONFIG_FILE", 0, "Specify the config file path. If not specified, the default value is .conf.", 0}, + {"version", 'v', NULL, 0, + "Show the version of the executable.", 0}, {"test-config", 't', NULL, 0, "Test the config file and exit.", 0}, {0} @@ -62,6 +64,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { case 'c': strncpy(config_name, arg, sizeof(config_name) - 1); break; + case 'v': + fprintf(stdout, "Liteflow %s\n", argp_program_version); + exit(0); case 't': test_mode = true; break; diff --git a/tools/conf-compose/README.md b/tools/conf-compose/README.md deleted file mode 100644 index 90ae268..0000000 --- a/tools/conf-compose/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# conf-compose -一个用于更方便地管理和生成集群内多个liteflow实例配置文件的工具。通过YAML定义集群内所有的node实例,和tunnel隧道信息,本工具可以自动化生成各个node的JSON配置文件,避免手工维护多个实例的配置文件,降低人为出错概率。 - -## 使用说明 -首先准备好两个YAML文件,一个文件用来定义当前集群内的所有node实例和信息,另一个文件用来定义所有的tunnel隧道信息。具体的文件格式请参考example_yamls目录下给出的示例。 - -然后运行 -``` -./conf-compose.py -n -t -``` - -在指定的``输出目录中,可以找到所有实例的配置文件。 - -运行完成后,屏幕后将会输出连接到每个实例的其它实例及端口信息,以及实例监听的所有端口,便于配置防火墙规则。 - -本工具已附带一个example,请运行 -``` -./conf-compose.py -n example-regular/nodes.yaml -t example-regular/tunnels.yaml example-regular/output -``` - -本工具会检查提供的YAML的格式和内容是否符合要求。 - -## 容灾备份 -在liteflow的设置中,`entrance_rule`可以显式指定tunnel另一端的节点的`node_id`,则此规则仅用于转发到该指定下一级节点。例如: -```json -{ - "tunnel_id": 1011, - "listen_addr": "0.0.0.0", - "listen_port": 1010, - "protocol": "tcp", - "node_id": 1 -} -``` - -如果`entrance_rule`不指定下一级的`node_id`,如果有多个peer连接上来并提供和该`entrance_rule`相同的`tunnel_id`,则liteflow只会将该tunnel的数据转到到其中某一个peer。如果此peer之后断开了连接,则liteflow会选择转发给下一个peer。这是一种容灾备份,避免单个forward节点的故障导致一个tunnel完全不可用。请注意,这不能用于实现负载均衡。 - -同样地,`forward_rule`也有类似的行为,避免单个`entrance`节点的故障导致一个tunnel完全不可用。 - -在conf-compose的设置中,这可以通过在一个规则下设置多个`entrance`或`forward`来实现,请参考example。 - -同一个规则下,如果只有单个`forward`,则其`entrance`可以设置`explicit`为`true`(默认为`false`),生成的`entrance_rule`中会严格指定`forward`节点的`node_id`。同样地,如果只有单个`entrance`,则其`forward`可以设置`explict`为`true`,生成的`forward_rule`中会严格指定`entrance`节点的`node_id`。 - -## 生成拓扑图 -本工具可以生成Graphviz的dot文件和图形(支持png, svg, pdf, jpg, jpeg, bmp, gif, tiff这些格式)。运行 -``` -./draw-graphviz.py -n -t -d -i -``` - -例如,提供的example会生这样的图形: -![liteflow.png](./example_output/liteflow.png) - -## 生成防火墙规则 -用于生成所有liteflow节点的inbound和outbound防火墙规则,以及clients的outbound防火墙规则。所有规则输出为YAML文件,用作设置防火墙的参考。每一个liteflow节点或每一个client将会生成一个单独的YAML文件。 - -本工具已附带一个example,请运行 -``` -./generate-firewall-rules.py -n example-firewall-rules/nodes.yaml -t example-firewall-rules/tunnels.yaml -c example-firewall-rules/clients.yaml example-firewall-rules/output -``` \ No newline at end of file diff --git a/tools/conf-compose/example-firewall-rules/output/client.node3_firewall_inout_rules.yaml b/tools/conf-compose/example-firewall-rules/output/client.node3_firewall_inout_rules.yaml deleted file mode 100644 index 0aa8bab..0000000 --- a/tools/conf-compose/example-firewall-rules/output/client.node3_firewall_inout_rules.yaml +++ /dev/null @@ -1,12 +0,0 @@ -inbound/from_clients/server.to_node1_and_node2.fault-tolerant.tunnels/any: - destination_endpoints: any:1010 - protocols: - - tcp - - udp - source_ips: any -outbound/to_peers: - destination_endpoints: - - node1.example.com:9901 - - 88.88.88.88:9902 - protocols: - - udp diff --git a/tools/conf-compose/example-firewall-rules/output/home_devices_firewall_out_rules.yaml b/tools/conf-compose/example-firewall-rules/output/home_devices_firewall_out_rules.yaml deleted file mode 100644 index 0b9523a..0000000 --- a/tools/conf-compose/example-firewall-rules/output/home_devices_firewall_out_rules.yaml +++ /dev/null @@ -1,10 +0,0 @@ -outbound/to_entrances/server.node1_to_node2.explicit.tunnels: - destination_endpoints: - - node1.example.com:2010 - protocols: - - udp -outbound/to_entrances/server.node2_to_node1.non-explicit.tunnels: - destination_endpoints: - - 88.88.88.88:3010 - protocols: - - tcp diff --git a/tools/conf-compose/example-firewall-rules/output/school_devices_firewall_out_rules.yaml b/tools/conf-compose/example-firewall-rules/output/school_devices_firewall_out_rules.yaml deleted file mode 100644 index 0b9523a..0000000 --- a/tools/conf-compose/example-firewall-rules/output/school_devices_firewall_out_rules.yaml +++ /dev/null @@ -1,10 +0,0 @@ -outbound/to_entrances/server.node1_to_node2.explicit.tunnels: - destination_endpoints: - - node1.example.com:2010 - protocols: - - udp -outbound/to_entrances/server.node2_to_node1.non-explicit.tunnels: - destination_endpoints: - - 88.88.88.88:3010 - protocols: - - tcp diff --git a/tools/conf-compose/example-regular/output/liteflow.png b/tools/conf-compose/example-regular/output/liteflow.png deleted file mode 100644 index 5d298e5..0000000 Binary files a/tools/conf-compose/example-regular/output/liteflow.png and /dev/null differ diff --git a/tools/conf-compose/example-regular/output/liteflow.svg b/tools/conf-compose/example-regular/output/liteflow.svg deleted file mode 100644 index e1aa863..0000000 --- a/tools/conf-compose/example-regular/output/liteflow.svg +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - -Network - - - -1 - -server.node1 (1) -0.0.0.0:9901 - - - -2 - -server.node2 (2) -0.0.0.0:9902 - - - -1->2 - - - - - -1->2 - - -{'udp_tunnel_id': 2012}: 0.0.0.0:2010 → 127.0.0.1:8302 - - - -3 - -client.node3 (3) - - - -1->3 - - -{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303 - - - -4 - -client.node4 (4) - - - -1->4 - - -{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304 - - - -2->1 - - - - - -2->1 - - -{'tcp_tunnel_id': 3011}: 0.0.0.0:3010 → 127.0.0.1:8301 - - - -2->3 - - -{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303 - - - -2->4 - - -{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304 - - - -3->1 - - - - - -3->1 - - -{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301 - - - -3->2 - - - - - -3->2 - - -{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302 - - - -4->1 - - - - - -4->1 - - -{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301 - - - -4->2 - - - - - -4->2 - - -{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302 - - - diff --git a/tools/liteflow-compose/README.cn.md b/tools/liteflow-compose/README.cn.md new file mode 100644 index 0000000..97afda2 --- /dev/null +++ b/tools/liteflow-compose/README.cn.md @@ -0,0 +1,67 @@ +# liteflow-compose +一个用于更方便地管理和生成集群内多个liteflow实例配置文件的工具。通过YAML定义集群内所有的node实例,和tunnel隧道信息,本工具可以自动化生成各个node的JSON配置文件,避免手工维护多个实例的配置文件,降低人为出错概率。 + +## 使用说明 +首先准备好两个YAML文件,一个文件用来定义当前集群内的所有node实例和信息,另一个文件用来定义所有的tunnel隧道信息。具体的文件格式请参考example_yamls目录下给出的示例。 + +然后运行 +``` +./liteflow-compose.py -n -t +``` + +在指定的``输出目录中,可以找到所有实例的配置文件。 + +运行完成后,屏幕后将会输出连接到每个实例的其它实例及端口信息,以及实例监听的所有端口,便于配置防火墙规则。 + +本工具已附带一个example,请运行 +``` +./liteflow-compose.py -n example-regular/nodes.yaml -t example-regular/tunnels.yaml example-regular/output +``` + +本工具会检查提供的YAML的格式和内容是否符合要求。 + +## 生成拓扑图 +本工具可以生成Graphviz的dot文件和图形(支持png, svg, pdf, jpg, jpeg, bmp, gif, tiff这些格式)。运行 +``` +./draw-graphviz.py -n -t -d -i +``` + +例如,提供的example会生这样的图形: +``` +./draw-graphviz.py -n example-regular/nodes.yaml -t example-regular/tunnels.yaml -d example-regular/output/liteflow.dot -i example-regular/output/liteflow.png +``` +![liteflow.png](./example-regular/output/liteflow.png) + +## 生成防火墙规则 +用于生成所有liteflow节点的inbound和outbound防火墙规则,以及clients的outbound防火墙规则。所有规则输出为YAML文件,用作设置防火墙的参考。每一个liteflow节点或每一个client将会生成一个单独的YAML文件。 + +本工具已附带一个example,请运行 +``` +./generate-firewall-rules.py -n example-firewall-rules/nodes.yaml -t example-firewall-rules/tunnels.yaml -c example-firewall-rules/clients.yaml example-firewall-rules/output +``` + +## 高级进阶:容灾备份 +在liteflow的设置中,`entrance_rule`可以显式指定tunnel另一端的节点的`node_id`,则此规则仅用于转发到该指定下一级节点。例如: +```json +{ + "tunnel_id": 1011, + "listen_addr": "0.0.0.0", + "listen_port": 1010, + "protocol": "tcp", + "node_id": 1 +} +``` + +如果`entrance_rule`不指定下一级的`node_id`,则liteflow只会将该tunnel的数据转到其中任意一个peer。如果此peer之后断开了连接,则liteflow会选择转发给下一个peer。这是一种容灾备份,避免单个forward节点的故障导致一个tunnel完全不可用。请注意,这不能用于实现负载均衡。 + +同样地,`forward_rule`也有类似的行为。如果在`forward_rule`中指定了`node_id`,就只能接受来自该node的用户连接。否则就可以接受来自任意peer的用户连接。这是为了避免单个`entrance`节点的故障导致一个tunnel完全不可用。 + +> ⚠️ 请注意,如果`entrance_rule`不指定`node_id`,则本节点会从所有连接的peers中任意选择一个发送,即使该peer并不支持该`tunnel_id`。这是因为两个peer在连接时并不会交换`tunnel_id`列表,双方并不知晓对方所支持的`tunnel_id`信息。 +> +> **因此,Liteflow 被设计为每个进程仅支持一个用途单一的隧道。若需使用多个隧道,建议为每个隧道分别启动独立的 Liteflow 进程,并配以各自的配置文件。** + +在liteflow-compose的设置中,这可以通过在一个规则下设置多个`entrance`或`forward`来实现,请参考example。 + +同一个规则下,如果多于一个`forward`,则其`entrance`可以设置`explicit`为`false`(默认为`true`),生成的`entrance_rule`中就不会设置`forward`节点的`node_id`。 + +相对应的时,如果只有单个`entrance`,则其`forward`可以设置`explict`为`true`(默认为`false`),生成的`forward_rule`中会严格指定`entrance`节点的`node_id`。 \ No newline at end of file diff --git a/tools/liteflow-compose/README.md b/tools/liteflow-compose/README.md new file mode 100644 index 0000000..9629695 --- /dev/null +++ b/tools/liteflow-compose/README.md @@ -0,0 +1,67 @@ +# liteflow-compose +A tool for convenient management and generation of configuration files for multiple liteflow instances within a cluster. By defining node instances and tunnel information through YAML files, this tool automatically generates JSON configuration files for each node, eliminating the need for manual maintenance and reducing the risk of human errors. + +## Usage Instructions +First, prepare two YAML files: one file to define all node instances and information in the current cluster, and another file to define all tunnel information. For specific file formats, please refer to the examples provided in the example-regular directory. + +Then run: +``` +./liteflow-compose.py -n -t +``` + +In the specified `` output directory, you can find configuration files for all instances. + +Upon completion, the tool will display information about other instances and ports connected to each instance, as well as all ports that instances listen on, to facilitate firewall rule configuration. + +This tool includes an example; please run: +``` +./liteflow-compose.py -n example-regular/nodes.yaml -t example-regular/tunnels.yaml example-regular/output +``` + +This tool will check whether the format and content of the provided YAML meet the requirements. + +## Generating Topology Diagrams +This tool can generate Graphviz dot files and graphics (supports png, svg, pdf, jpg, jpeg, bmp, gif, tiff formats). Run: +``` +./draw-graphviz.py -n -t -d -i +``` + +For example, the provided example will generate graphics like this: +``` +./draw-graphviz.py -n example-regular/nodes.yaml -t example-regular/tunnels.yaml -d example-regular/output/liteflow.dot -i example-regular/output/liteflow.png +``` +![liteflow.png](./example-regular/output/liteflow.png) + +## Generating Firewall Rules +Used to generate inbound and outbound firewall rules for all liteflow nodes, as well as outbound firewall rules for clients. All rules are output as YAML files for reference when setting up firewalls. Each liteflow node or each client will generate a separate YAML file. + +This tool includes an example; please run: +``` +./generate-firewall-rules.py -n example-firewall-rules/nodes.yaml -t example-firewall-rules/tunnels.yaml -c example-firewall-rules/clients.yaml example-firewall-rules/output +``` + +## Advanced: Disaster Recovery Backup +In liteflow settings, `entrance_rule` can explicitly specify the `node_id` of the node at the other end of the tunnel, then this rule will only forward to that specified next-level node. For example: +```json +{ + "tunnel_id": 1011, + "listen_addr": "0.0.0.0", + "listen_port": 1010, + "protocol": "tcp", + "node_id": 1 +} +``` + +If `entrance_rule` does not specify the next-level `node_id`, liteflow will only forward the tunnel data to any one of its peers. If this peer later disconnects, liteflow will choose to forward to the next peer. This is a disaster recovery backup to prevent a single forward node failure from making a tunnel completely unavailable. Please note that this cannot be used to implement load balancing. + +Similarly, `forward_rule` has similar behavior. If `node_id` is specified in `forward_rule`, it can only accept user connections from that node. Otherwise, it can accept user connections from any peer. This is to prevent a single `entrance` node failure from making a tunnel completely unavailable. + +> ⚠️ Please note that if `entrance_rule` does not specify `node_id`, this node will arbitrarily choose one from all connected peers to send to, even if that peer does not support that `tunnel_id`. This is because the two peers do not exchange `tunnel_id` lists when connecting, and neither side knows the `tunnel_id` information supported by the other. +> +> **Therefore, Liteflow is designed so that each process supports only a single-purpose tunnel. If multiple tunnels are needed, it is recommended to start separate Liteflow processes for each tunnel, each with its own configuration file.** + +In liteflow-compose settings, this can be achieved by setting multiple `entrance` or `forward` under one rule, please refer to the example. + +Under the same rule, if there are more than one `forward`, then its `entrance` can set `explicit` to `false` (default is `true`), and the generated `entrance_rule` will not set the `node_id` of the `forward` node. + +Correspondingly, if there is only a single `entrance`, then its `forward` can set `explicit` to `true` (default is `false`), and the generated `forward_rule` will strictly specify the `node_id` of the `entrance` node. diff --git a/tools/conf-compose/conf-compose.py b/tools/liteflow-compose/conf-compose.py similarity index 97% rename from tools/conf-compose/conf-compose.py rename to tools/liteflow-compose/conf-compose.py index 0367f81..595cebf 100644 --- a/tools/conf-compose/conf-compose.py +++ b/tools/liteflow-compose/conf-compose.py @@ -109,6 +109,7 @@ def generate_node_configs(node_file, tunnel_file, output_dir): } # Process entrance rules (acting as tunnel entry points) + # By default, entrance rule uses explicit:true. for tunnel_name, tunnel in tunnels_data.items(): has_multiple_entrances = len(tunnel.get("entrances", [])) > 1 has_multiple_forwards = len(tunnel.get("forwards", [])) > 1 @@ -123,7 +124,7 @@ def generate_node_configs(node_file, tunnel_file, output_dir): "listen_port": int(entrance["listen_endpoint"].split(":")[1]), "protocol": "tcp" } - if entrance.get("explicit", False): + if entrance.get("explicit", True): entrance_rule["node_id"] = node_name_to_id[forward["node"]] config["entrance_rules"].append(entrance_rule) if "udp_tunnel_id" in tunnel: @@ -133,7 +134,7 @@ def generate_node_configs(node_file, tunnel_file, output_dir): "listen_port": int(entrance["listen_endpoint"].split(":")[1]), "protocol": "udp" } - if entrance.get("explicit", False): + if entrance.get("explicit", True): entrance_rule["node_id"] = node_name_to_id[forward["node"]] config["entrance_rules"].append(entrance_rule) # If there are multiple forwards, this is a fault-tolerant @@ -144,6 +145,7 @@ def generate_node_configs(node_file, tunnel_file, output_dir): config["entrance_rules"] = sorted(config["entrance_rules"], key=lambda x: x["tunnel_id"]) + # By default, forward rule uses explicit:false. for forward in tunnel.get("forwards", []): if node_name_to_id[forward["node"]] == node_id: for entrance in tunnel.get("entrances", []): diff --git a/tools/conf-compose/draw-graphviz.py b/tools/liteflow-compose/draw-graphviz.py similarity index 100% rename from tools/conf-compose/draw-graphviz.py rename to tools/liteflow-compose/draw-graphviz.py diff --git a/tools/conf-compose/example-firewall-rules/clients.yaml b/tools/liteflow-compose/example-firewall-rules/clients.yaml similarity index 100% rename from tools/conf-compose/example-firewall-rules/clients.yaml rename to tools/liteflow-compose/example-firewall-rules/clients.yaml diff --git a/tools/conf-compose/example-firewall-rules/nodes.yaml b/tools/liteflow-compose/example-firewall-rules/nodes.yaml similarity index 95% rename from tools/conf-compose/example-firewall-rules/nodes.yaml rename to tools/liteflow-compose/example-firewall-rules/nodes.yaml index e95dd11..565e983 100644 --- a/tools/conf-compose/example-firewall-rules/nodes.yaml +++ b/tools/liteflow-compose/example-firewall-rules/nodes.yaml @@ -44,6 +44,7 @@ client.node3: transport: password: 1234-5678-90AB-CDEF transmit_rate_min: 4000000 + domain: 192.168.1.3 # When nic_ips is unspecified, it's "any" by default. outbound_ips: - 50.40.0.0/16 @@ -59,6 +60,7 @@ client.node4: transport: password: 1234-5678-90AB-CDEF transmit_rate_min: 4000000 + domain: 192.168.1.4 outbound_ips: - 50.41.0.0/16 - - 50.51.1.218 \ No newline at end of file + - 50.51.1.218 diff --git a/tools/liteflow-compose/example-firewall-rules/output/client.node3_firewall_inout_rules.yaml b/tools/liteflow-compose/example-firewall-rules/output/client.node3_firewall_inout_rules.yaml new file mode 100644 index 0000000..d4ff882 --- /dev/null +++ b/tools/liteflow-compose/example-firewall-rules/output/client.node3_firewall_inout_rules.yaml @@ -0,0 +1,25 @@ +inbound/from_clients/server.node3_to_others.non-explicit.tunnels/home_devices: + destination_endpoints: any:4010 + protocols: + - tcp + source_ips: + - 50.35.0.0/16 + - 50.36.1.80 +inbound/from_clients/server.node3_to_others.non-explicit.tunnels/school_devices: + destination_endpoints: any:4010 + protocols: + - tcp + source_ips: + - 205.251.33.0/24 +inbound/from_clients/server.to_node1_and_node2.fault-tolerant.tunnels/any: + destination_endpoints: any:1010 + protocols: + - tcp + - udp + source_ips: any +outbound/to_peers: + destination_endpoints: + - node1.example.com:9901 + - 88.88.88.88:9902 + protocols: + - udp diff --git a/tools/conf-compose/example-firewall-rules/output/client.node4_firewall_inout_rules.yaml b/tools/liteflow-compose/example-firewall-rules/output/client.node4_firewall_inout_rules.yaml similarity index 100% rename from tools/conf-compose/example-firewall-rules/output/client.node4_firewall_inout_rules.yaml rename to tools/liteflow-compose/example-firewall-rules/output/client.node4_firewall_inout_rules.yaml diff --git a/tools/liteflow-compose/example-firewall-rules/output/home_devices_firewall_out_rules.yaml b/tools/liteflow-compose/example-firewall-rules/output/home_devices_firewall_out_rules.yaml new file mode 100644 index 0000000..6f2610d --- /dev/null +++ b/tools/liteflow-compose/example-firewall-rules/output/home_devices_firewall_out_rules.yaml @@ -0,0 +1,15 @@ +outbound/to_entrances/server.node1_to_node2.tunnels: + destination_endpoints: + - node1.example.com:2010 + protocols: + - udp +outbound/to_entrances/server.node2_to_node1.tunnels: + destination_endpoints: + - 88.88.88.88:3010 + protocols: + - tcp +outbound/to_entrances/server.node3_to_others.non-explicit.tunnels: + destination_endpoints: + - 192.168.1.3:4010 + protocols: + - tcp diff --git a/tools/liteflow-compose/example-firewall-rules/output/school_devices_firewall_out_rules.yaml b/tools/liteflow-compose/example-firewall-rules/output/school_devices_firewall_out_rules.yaml new file mode 100644 index 0000000..6f2610d --- /dev/null +++ b/tools/liteflow-compose/example-firewall-rules/output/school_devices_firewall_out_rules.yaml @@ -0,0 +1,15 @@ +outbound/to_entrances/server.node1_to_node2.tunnels: + destination_endpoints: + - node1.example.com:2010 + protocols: + - udp +outbound/to_entrances/server.node2_to_node1.tunnels: + destination_endpoints: + - 88.88.88.88:3010 + protocols: + - tcp +outbound/to_entrances/server.node3_to_others.non-explicit.tunnels: + destination_endpoints: + - 192.168.1.3:4010 + protocols: + - tcp diff --git a/tools/conf-compose/example-firewall-rules/output/server.node1_firewall_inout_rules.yaml b/tools/liteflow-compose/example-firewall-rules/output/server.node1_firewall_inout_rules.yaml similarity index 86% rename from tools/conf-compose/example-firewall-rules/output/server.node1_firewall_inout_rules.yaml rename to tools/liteflow-compose/example-firewall-rules/output/server.node1_firewall_inout_rules.yaml index dfb5439..c27e0f5 100644 --- a/tools/conf-compose/example-firewall-rules/output/server.node1_firewall_inout_rules.yaml +++ b/tools/liteflow-compose/example-firewall-rules/output/server.node1_firewall_inout_rules.yaml @@ -1,4 +1,4 @@ -inbound/from_clients/server.node1_to_node2.explicit.tunnels/home_devices: +inbound/from_clients/server.node1_to_node2.tunnels/home_devices: destination_endpoints: - 10.0.0.1:2010 - 10.0.0.2:2010 @@ -7,7 +7,7 @@ inbound/from_clients/server.node1_to_node2.explicit.tunnels/home_devices: source_ips: - 50.35.0.0/16 - 50.36.1.80 -inbound/from_clients/server.node1_to_node2.explicit.tunnels/school_devices: +inbound/from_clients/server.node1_to_node2.tunnels/school_devices: destination_endpoints: - 10.0.0.1:2010 - 10.0.0.2:2010 diff --git a/tools/conf-compose/example-firewall-rules/output/server.node2_firewall_inout_rules.yaml b/tools/liteflow-compose/example-firewall-rules/output/server.node2_firewall_inout_rules.yaml similarity index 83% rename from tools/conf-compose/example-firewall-rules/output/server.node2_firewall_inout_rules.yaml rename to tools/liteflow-compose/example-firewall-rules/output/server.node2_firewall_inout_rules.yaml index f1d4aac..cc3cede 100644 --- a/tools/conf-compose/example-firewall-rules/output/server.node2_firewall_inout_rules.yaml +++ b/tools/liteflow-compose/example-firewall-rules/output/server.node2_firewall_inout_rules.yaml @@ -1,11 +1,11 @@ -inbound/from_clients/server.node2_to_node1.non-explicit.tunnels/home_devices: +inbound/from_clients/server.node2_to_node1.tunnels/home_devices: destination_endpoints: any:3010 protocols: - tcp source_ips: - 50.35.0.0/16 - 50.36.1.80 -inbound/from_clients/server.node2_to_node1.non-explicit.tunnels/school_devices: +inbound/from_clients/server.node2_to_node1.tunnels/school_devices: destination_endpoints: any:3010 protocols: - tcp diff --git a/tools/conf-compose/example-regular/tunnels.yaml b/tools/liteflow-compose/example-firewall-rules/tunnels.yaml similarity index 58% rename from tools/conf-compose/example-regular/tunnels.yaml rename to tools/liteflow-compose/example-firewall-rules/tunnels.yaml index 0595f39..e634281 100644 --- a/tools/conf-compose/example-regular/tunnels.yaml +++ b/tools/liteflow-compose/example-firewall-rules/tunnels.yaml @@ -1,3 +1,5 @@ +# Though it's `clients: any`, we don't add specific rules to each +# client in `clients.yaml`. server.to_node1_and_node2.fault-tolerant.tunnels: tcp_tunnel_id: 1011 udp_tunnel_id: 1012 @@ -11,7 +13,9 @@ server.to_node1_and_node2.fault-tolerant.tunnels: destination_endpoint: 127.0.0.1:8301 - node: server.node2 destination_endpoint: 127.0.0.1:8302 + clients: any +# No `clients` section. Then "clients: any" is default. server.to_node3_and_node4.fault-tolerant.tunnels: tcp_tunnel_id: 1021 udp_tunnel_id: 1022 @@ -26,7 +30,7 @@ server.to_node3_and_node4.fault-tolerant.tunnels: - node: client.node4 destination_endpoint: 127.0.0.1:8304 -server.node1_to_node2.explicit.tunnels: +server.node1_to_node2.tunnels: udp_tunnel_id: 2012 entrances: - node: server.node1 @@ -34,14 +38,34 @@ server.node1_to_node2.explicit.tunnels: forwards: - node: server.node2 destination_endpoint: 127.0.0.1:8302 - explicit: true + clients: + - home_devices + - school_devices -server.node2_to_node1.non-explicit.tunnels: +server.node2_to_node1.tunnels: tcp_tunnel_id: 3011 entrances: - node: server.node2 listen_endpoint: 0.0.0.0:3010 - explicit: true forwards: - node: server.node1 - destination_endpoint: 127.0.0.1:8301 \ No newline at end of file + destination_endpoint: 127.0.0.1:8301 + explicit: false + clients: + - home_devices + - school_devices + +server.node3_to_others.non-explicit.tunnels: + tcp_tunnel_id: 4011 + entrances: + - node: client.node3 + listen_endpoint: 0.0.0.0:4010 + explicit: false + forwards: + - node: server.node1 + destination_endpoint: 127.0.0.1:8401 + - node: server.node2 + destination_endpoint: 127.0.0.1:8402 + clients: + - home_devices + - school_devices diff --git a/tools/conf-compose/example-regular/nodes.yaml b/tools/liteflow-compose/example-regular/nodes.yaml similarity index 91% rename from tools/conf-compose/example-regular/nodes.yaml rename to tools/liteflow-compose/example-regular/nodes.yaml index b320735..7e7fd0a 100644 --- a/tools/conf-compose/example-regular/nodes.yaml +++ b/tools/liteflow-compose/example-regular/nodes.yaml @@ -32,6 +32,7 @@ client.node3: transport: password: 1234-5678-90AB-CDEF transmit_rate_min: 4000000 + domain: 192.168.1.3 client.node4: service: @@ -42,4 +43,5 @@ client.node4: debug_log: 0 transport: password: 1234-5678-90AB-CDEF - transmit_rate_min: 4000000 \ No newline at end of file + transmit_rate_min: 4000000 + domain: 192.168.1.4 diff --git a/tools/conf-compose/example-regular/output/client.node3.conf b/tools/liteflow-compose/example-regular/output/client.node3.conf similarity index 80% rename from tools/conf-compose/example-regular/output/client.node3.conf rename to tools/liteflow-compose/example-regular/output/client.node3.conf index c9f53d2..8126723 100644 --- a/tools/conf-compose/example-regular/output/client.node3.conf +++ b/tools/liteflow-compose/example-regular/output/client.node3.conf @@ -16,13 +16,21 @@ "tunnel_id": 1011, "listen_addr": "0.0.0.0", "listen_port": 1010, - "protocol": "tcp" + "protocol": "tcp", + "node_id": 1 }, { "tunnel_id": 1012, "listen_addr": "0.0.0.0", "listen_port": 1010, - "protocol": "udp" + "protocol": "udp", + "node_id": 1 + }, + { + "tunnel_id": 4011, + "listen_addr": "0.0.0.0", + "listen_port": 4010, + "protocol": "tcp" } ], "forward_rules": [ diff --git a/tools/conf-compose/example-regular/output/client.node4.conf b/tools/liteflow-compose/example-regular/output/client.node4.conf similarity index 89% rename from tools/conf-compose/example-regular/output/client.node4.conf rename to tools/liteflow-compose/example-regular/output/client.node4.conf index c93e283..5b29392 100644 --- a/tools/conf-compose/example-regular/output/client.node4.conf +++ b/tools/liteflow-compose/example-regular/output/client.node4.conf @@ -16,13 +16,15 @@ "tunnel_id": 1011, "listen_addr": "0.0.0.0", "listen_port": 1010, - "protocol": "tcp" + "protocol": "tcp", + "node_id": 1 }, { "tunnel_id": 1012, "listen_addr": "0.0.0.0", "listen_port": 1010, - "protocol": "udp" + "protocol": "udp", + "node_id": 1 } ], "forward_rules": [ diff --git a/tools/conf-compose/example-regular/output/liteflow.dot b/tools/liteflow-compose/example-regular/output/liteflow.dot similarity index 53% rename from tools/conf-compose/example-regular/output/liteflow.dot rename to tools/liteflow-compose/example-regular/output/liteflow.dot index 79f8684..acfe23a 100644 --- a/tools/conf-compose/example-regular/output/liteflow.dot +++ b/tools/liteflow-compose/example-regular/output/liteflow.dot @@ -11,14 +11,16 @@ digraph Network { 3 -> 2 [color=black penwidth=2.0] 4 -> 1 [color=black penwidth=2.0] 4 -> 2 [color=black penwidth=2.0] - 3 -> 1 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301" color="#a863ba" fontcolor="#a863ba" style=dashed] - 3 -> 2 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302" color="#a863ba" fontcolor="#a863ba" style=dashed] - 4 -> 1 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301" color="#a863ba" fontcolor="#a863ba" style=dashed] - 4 -> 2 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302" color="#a863ba" fontcolor="#a863ba" style=dashed] - 1 -> 3 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303" color="#ce1d8a" fontcolor="#ce1d8a" style=dashed] - 1 -> 4 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304" color="#ce1d8a" fontcolor="#ce1d8a" style=dashed] - 2 -> 3 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303" color="#ce1d8a" fontcolor="#ce1d8a" style=dashed] - 2 -> 4 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304" color="#ce1d8a" fontcolor="#ce1d8a" style=dashed] - 1 -> 2 [label="{'udp_tunnel_id': 2012}: 0.0.0.0:2010 → 127.0.0.1:8302" color="#bc020b" fontcolor="#bc020b" style=dashed] - 2 -> 1 [label="{'tcp_tunnel_id': 3011}: 0.0.0.0:3010 → 127.0.0.1:8301" color="#97c108" fontcolor="#97c108" style=dashed] + 3 -> 1 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301" color="#777204" fontcolor="#777204" style=dashed] + 3 -> 2 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302" color="#777204" fontcolor="#777204" style=dashed] + 4 -> 1 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301" color="#777204" fontcolor="#777204" style=dashed] + 4 -> 2 [label="{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302" color="#777204" fontcolor="#777204" style=dashed] + 1 -> 3 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303" color="#e163b1" fontcolor="#e163b1" style=dashed] + 1 -> 4 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304" color="#e163b1" fontcolor="#e163b1" style=dashed] + 2 -> 3 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303" color="#e163b1" fontcolor="#e163b1" style=dashed] + 2 -> 4 [label="{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304" color="#e163b1" fontcolor="#e163b1" style=dashed] + 1 -> 2 [label="{'udp_tunnel_id': 2012}: 0.0.0.0:2010 → 127.0.0.1:8302" color="#8bcb3b" fontcolor="#8bcb3b" style=dashed] + 2 -> 1 [label="{'tcp_tunnel_id': 3011}: 0.0.0.0:3010 → 127.0.0.1:8301" color="#13d47e" fontcolor="#13d47e" style=dashed] + 3 -> 1 [label="{'tcp_tunnel_id': 4011}: 0.0.0.0:4010 → 127.0.0.1:8401" color="#8b1a94" fontcolor="#8b1a94" style=dashed] + 3 -> 2 [label="{'tcp_tunnel_id': 4011}: 0.0.0.0:4010 → 127.0.0.1:8402" color="#8b1a94" fontcolor="#8b1a94" style=dashed] } diff --git a/tools/liteflow-compose/example-regular/output/liteflow.png b/tools/liteflow-compose/example-regular/output/liteflow.png new file mode 100644 index 0000000..e6837a7 Binary files /dev/null and b/tools/liteflow-compose/example-regular/output/liteflow.png differ diff --git a/tools/liteflow-compose/example-regular/output/liteflow.svg b/tools/liteflow-compose/example-regular/output/liteflow.svg new file mode 100644 index 0000000..454f719 --- /dev/null +++ b/tools/liteflow-compose/example-regular/output/liteflow.svg @@ -0,0 +1,159 @@ + + + + + + +Network + + + +1 + +server.node1 (1) +0.0.0.0:9901 + + + +2 + +server.node2 (2) +0.0.0.0:9902 + + + +1->2 + + + + + +1->2 + + +{'udp_tunnel_id': 2012}: 0.0.0.0:2010 → 127.0.0.1:8302 + + + +3 + +client.node3 (3) + + + +1->3 + + +{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303 + + + +4 + +client.node4 (4) + + + +1->4 + + +{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304 + + + +2->1 + + + + + +2->1 + + +{'tcp_tunnel_id': 3011}: 0.0.0.0:3010 → 127.0.0.1:8301 + + + +2->3 + + +{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8303 + + + +2->4 + + +{'tcp_tunnel_id': 1021, 'udp_tunnel_id': 1022}: 0.0.0.0:1020 → 127.0.0.1:8304 + + + +3->1 + + + + + +3->1 + + +{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301 + + + +3->1 + + +{'tcp_tunnel_id': 4011}: 0.0.0.0:4010 → 127.0.0.1:8401 + + + +3->2 + + + + + +3->2 + + +{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302 + + + +3->2 + + +{'tcp_tunnel_id': 4011}: 0.0.0.0:4010 → 127.0.0.1:8402 + + + +4->1 + + + + + +4->1 + + +{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8301 + + + +4->2 + + + + + +4->2 + + +{'tcp_tunnel_id': 1011, 'udp_tunnel_id': 1012}: 0.0.0.0:1010 → 127.0.0.1:8302 + + + diff --git a/tools/conf-compose/example-regular/output/server.node1.conf b/tools/liteflow-compose/example-regular/output/server.node1.conf similarity index 80% rename from tools/conf-compose/example-regular/output/server.node1.conf rename to tools/liteflow-compose/example-regular/output/server.node1.conf index 8f6d09a..9b0ddcf 100644 --- a/tools/conf-compose/example-regular/output/server.node1.conf +++ b/tools/liteflow-compose/example-regular/output/server.node1.conf @@ -17,19 +17,22 @@ "tunnel_id": 1021, "listen_addr": "0.0.0.0", "listen_port": 1020, - "protocol": "tcp" + "protocol": "tcp", + "node_id": 3 }, { "tunnel_id": 1022, "listen_addr": "0.0.0.0", "listen_port": 1020, - "protocol": "udp" + "protocol": "udp", + "node_id": 3 }, { "tunnel_id": 2012, "listen_addr": "0.0.0.0", "listen_port": 2010, - "protocol": "udp" + "protocol": "udp", + "node_id": 2 } ], "forward_rules": [ @@ -50,6 +53,12 @@ "destination_addr": "127.0.0.1", "destination_port": 8301, "protocol": "tcp" + }, + { + "tunnel_id": 4011, + "destination_addr": "127.0.0.1", + "destination_port": 8401, + "protocol": "tcp" } ] } \ No newline at end of file diff --git a/tools/conf-compose/example-regular/output/server.node2.conf b/tools/liteflow-compose/example-regular/output/server.node2.conf similarity index 86% rename from tools/conf-compose/example-regular/output/server.node2.conf rename to tools/liteflow-compose/example-regular/output/server.node2.conf index 5370873..69f7088 100644 --- a/tools/conf-compose/example-regular/output/server.node2.conf +++ b/tools/liteflow-compose/example-regular/output/server.node2.conf @@ -17,13 +17,15 @@ "tunnel_id": 1021, "listen_addr": "0.0.0.0", "listen_port": 1020, - "protocol": "tcp" + "protocol": "tcp", + "node_id": 3 }, { "tunnel_id": 1022, "listen_addr": "0.0.0.0", "listen_port": 1020, - "protocol": "udp" + "protocol": "udp", + "node_id": 3 }, { "tunnel_id": 3011, @@ -50,8 +52,13 @@ "tunnel_id": 2012, "destination_addr": "127.0.0.1", "destination_port": 8302, - "protocol": "udp", - "node_id": 1 + "protocol": "udp" + }, + { + "tunnel_id": 4011, + "destination_addr": "127.0.0.1", + "destination_port": 8402, + "protocol": "tcp" } ] } \ No newline at end of file diff --git a/tools/conf-compose/example-firewall-rules/tunnels.yaml b/tools/liteflow-compose/example-regular/tunnels.yaml similarity index 73% rename from tools/conf-compose/example-firewall-rules/tunnels.yaml rename to tools/liteflow-compose/example-regular/tunnels.yaml index c1feb79..1ac1733 100644 --- a/tools/conf-compose/example-firewall-rules/tunnels.yaml +++ b/tools/liteflow-compose/example-regular/tunnels.yaml @@ -11,9 +11,7 @@ server.to_node1_and_node2.fault-tolerant.tunnels: destination_endpoint: 127.0.0.1:8301 - node: server.node2 destination_endpoint: 127.0.0.1:8302 - clients: any -# No `clients` section. Then "clients: any" is default. server.to_node3_and_node4.fault-tolerant.tunnels: tcp_tunnel_id: 1021 udp_tunnel_id: 1022 @@ -28,7 +26,7 @@ server.to_node3_and_node4.fault-tolerant.tunnels: - node: client.node4 destination_endpoint: 127.0.0.1:8304 -server.node1_to_node2.explicit.tunnels: +server.node1_to_node2.tunnels: udp_tunnel_id: 2012 entrances: - node: server.node1 @@ -36,20 +34,25 @@ server.node1_to_node2.explicit.tunnels: forwards: - node: server.node2 destination_endpoint: 127.0.0.1:8302 - explicit: true - clients: - - home_devices - - school_devices -server.node2_to_node1.non-explicit.tunnels: +server.node2_to_node1.tunnels: tcp_tunnel_id: 3011 entrances: - node: server.node2 listen_endpoint: 0.0.0.0:3010 - explicit: true forwards: - node: server.node1 destination_endpoint: 127.0.0.1:8301 - clients: - - home_devices - - school_devices \ No newline at end of file + explicit: false + +server.node3_to_others.non-explicit.tunnels: + tcp_tunnel_id: 4011 + entrances: + - node: client.node3 + listen_endpoint: 0.0.0.0:4010 + explicit: false + forwards: + - node: server.node1 + destination_endpoint: 127.0.0.1:8401 + - node: server.node2 + destination_endpoint: 127.0.0.1:8402 diff --git a/tools/conf-compose/generate-firewall-rules.py b/tools/liteflow-compose/generate-firewall-rules.py similarity index 100% rename from tools/conf-compose/generate-firewall-rules.py rename to tools/liteflow-compose/generate-firewall-rules.py diff --git a/tools/conf-compose/schema-clients.json b/tools/liteflow-compose/schema-clients.json similarity index 100% rename from tools/conf-compose/schema-clients.json rename to tools/liteflow-compose/schema-clients.json diff --git a/tools/conf-compose/schema-nodes.json b/tools/liteflow-compose/schema-nodes.json similarity index 100% rename from tools/conf-compose/schema-nodes.json rename to tools/liteflow-compose/schema-nodes.json diff --git a/tools/conf-compose/schema-tunnels.json b/tools/liteflow-compose/schema-tunnels.json similarity index 100% rename from tools/conf-compose/schema-tunnels.json rename to tools/liteflow-compose/schema-tunnels.json diff --git a/tools/conf-compose/validate-yamls.py b/tools/liteflow-compose/validate-yamls.py similarity index 75% rename from tools/conf-compose/validate-yamls.py rename to tools/liteflow-compose/validate-yamls.py index 51ff945..efc9d25 100644 --- a/tools/conf-compose/validate-yamls.py +++ b/tools/liteflow-compose/validate-yamls.py @@ -127,6 +127,86 @@ def validate_nodes_yaml(nodes_data): return None +def build_bidirectional_peer_map(nodes_data): + """ + Build a bidirectional peer map from nodes.yaml. + Ensures that if A -> B in connect_peers, then B -> A is also included. + Returns: dict[node_name] = set of peer node names + """ + peer_map = defaultdict(set) + + for node_name, node_data in nodes_data.items(): + peers = node_data.get("service", {}).get("connect_peers", []) + for peer in peers: + peer_map[node_name].add(peer) + peer_map[peer].add(node_name) # reverse link + + return peer_map + +def validate_explicit_false_peers_support_tunnel_ids(tunnels_data, nodes_data): + """ + When an entrance rule has explicit=False, all its peers must also support + the same tcp_tunnel_id and/or udp_tunnel_id, otherwise random forwarding + may hit an unsupported peer. + + This function builds: + 1. peer_map: node_name -> set of peers (from nodes.yaml) + 2. node_tunnel_ids: node_name -> set of supported tunnel_ids (from tunnels.yaml) + Then checks each entrance with explicit=False against its peers' support. + """ + peer_map = build_bidirectional_peer_map(nodes_data) + print(peer_map) + + # Build a map of node -> tunnel_ids it participates in + node_tunnel_ids = defaultdict(lambda: {"tcp": set(), "udp": set()}) + for section in tunnels_data.values(): + tid = section.get("tcp_tunnel_id") + uid = section.get("udp_tunnel_id") + for ent in section.get("entrances", []): + node_tunnel_ids[ent["node"]]["tcp"].add(tid) + node_tunnel_ids[ent["node"]]["udp"].add(uid) + for fwd in section.get("forwards", []): + node_tunnel_ids[fwd["node"]]["tcp"].add(tid) + node_tunnel_ids[fwd["node"]]["udp"].add(uid) + + # Now validate each entrance with explicit=False + for section_name, section in tunnels_data.items(): + tid = section.get("tcp_tunnel_id") + uid = section.get("udp_tunnel_id") + + for entrance in section.get("entrances", []): + node_name = entrance["node"] + print(entrance) + explicit = entrance.get("explicit", True) + if explicit is True: + continue # only validate when explicit is false + + print(f"{node_name} is explicit") + peers = peer_map.get(node_name, set()) + for peer in peers: + if peer not in node_tunnel_ids: + return f"Peer node {peer} (peer of {node_name}) is not used in any tunnel and cannot receive traffic from {section_name}" + + if tid is not None and tid not in node_tunnel_ids[peer]["tcp"]: + return f"Peer node {peer} (peer of {node_name}) does not support tcp_tunnel_id {tid} required by {section_name} (explicit=false)" + if uid is not None and uid not in node_tunnel_ids[peer]["udp"]: + return f"Peer node {peer} (peer of {node_name}) does not support udp_tunnel_id {uid} required by {section_name} (explicit=false)" + + return None + +def validate_entrance_nodes_have_domain(tunnels_data, nodes_data): + """ + Ensures that every node listed in entrances of tunnels.yaml + has a 'domain' field defined in nodes.yaml. + """ + for section_name, section in tunnels_data.items(): + for entrance in section.get("entrances", []): + node = entrance["node"] + node_entry = nodes_data.get(node, {}) + if "domain" not in node_entry: + return f"Node '{node}' used in entrances of '{section_name}' is missing required 'domain' in nodes.yaml" + return None + # Validate tunnels.yaml additional constraints def validate_tunnels_yaml(tunnels_data, nodes_data, clients_data): """ @@ -139,6 +219,11 @@ def validate_tunnels_yaml(tunnels_data, nodes_data, clients_data): 6. Each entrance-forward node pair must have a valid connection in nodes.yaml. 7. If clients.yaml is provided, every tunnel section should have "clients" key. 8. If clients is an array, each element must be a valid key in clients_data. + 9. If explicit is false, all peers of every entrance node in the entrance rule + must support this tcp_tunnel_id and/or udp_tunnel_id. + 10. Though schema-nodes.json has verified a node should define domain if it has + defined listen_endpoint, here we still need to verify every entrance node + should also have defined domain. """ tunnel_ids = set() listen_endpoints = defaultdict(set) @@ -202,6 +287,15 @@ def validate_tunnels_yaml(tunnels_data, nodes_data, clients_data): if client not in all_clients_keys: return f"Client {client} in {section_name} does not exist in clients.yaml" + # Validate explicit=false tunnel compatibility + errmsg = validate_explicit_false_peers_support_tunnel_ids(tunnels_data, nodes_data) + if errmsg: + return errmsg + + errmsg = validate_entrance_nodes_have_domain(tunnels_data, nodes_data) + if errmsg: + return errmsg + return None # Validate clients.yaml additional constraints @@ -230,7 +324,7 @@ def validate_clients_yaml(clients_data): def main(): current_dir = os.path.dirname(os.path.abspath(__file__)) - parser = argparse.ArgumentParser(description="conf-compose YAML format validation tool") + parser = argparse.ArgumentParser(description="liteflow-compose YAML format validation tool") # Allow both positional and optional named arguments parser.add_argument("-n", "--nodes_yaml_file", type=str,