diff --git a/Dockerfile b/Dockerfile index ef9e77b..3d1221a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,9 +5,9 @@ ARG TAG=main ENV TAG=${TAG} WORKDIR /app -ADD ./entrypoint.sh /app/entrypoint.sh -ADD ./http_server.js /app/http_server.js -ADD ./mkmoonworld-x86_64 /app/mkmoonworld-x86_64 +ADD ./patch/entrypoint.sh /app/entrypoint.sh +ADD ./patch/http_server.js /app/http_server.js +ADD ./patch/mkworld_custom.cpp /app/patch/mkworld_custom.cpp # init tool RUN set -x\ @@ -29,7 +29,15 @@ RUN set -x\ && echo "make success!"\ ; zerotier-one -d \ ; sleep 5s && ps -ef |grep zerotier-one |grep -v grep |awk '{print $1}' |xargs kill -9\ - && echo "zerotier-one init success!" + && echo "zerotier-one init success!"\ + && cd ./attic/world \ + && cp /app/patch/mkworld_custom.cpp .\ + && mv mkworld.cpp mkworld.cpp.bak \ + && mv mkworld_custom.cpp mkworld.cpp \ + && sh build.sh \ + && mv mkworld /var/lib/zerotier-one\ + && echo "mkworld build success!" + #make ztncui @@ -53,7 +61,7 @@ ENV ZT_PORT=9994 ENV API_PORT=3443 ENV FILE_SERVER_PORT=3000 -ENV GH_MIRROR="https://ghproxy.imoyuapp.win/" +ENV GH_MIRROR="https://mirror.ghproxy.com/" ENV FILE_KEY='' ENV TZ=Asia/Shanghai @@ -63,9 +71,8 @@ COPY --from=builder /var/lib/zerotier-one /bak/zerotier-one COPY --from=builder /app/ZeroTierOne/zerotier-one /usr/sbin/zerotier-one COPY --from=builder /app/entrypoint.sh /app/entrypoint.sh COPY --from=builder /app/http_server.js /app/http_server.js -COPY --from=builder /app/mkmoonworld-x86_64 /app/mkmoonworld-x86_64 -RUN set -x ;sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \ +RUN set -x \ && apk update \ && apk add --no-cache npm curl jq openssl\ && mkdir /app/config -p @@ -73,4 +80,4 @@ RUN set -x ;sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /et VOLUME [ "/app/dist","/app/ztncui","/var/lib/zerotier-one","/app/config"] -CMD ["/bin/sh","/app/entrypoint.sh"] +CMD ["/bin/sh","/app/entrypoint.sh"] \ No newline at end of file diff --git a/build.sh b/build.sh index ef64dd8..a207dde 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,11 @@ #!/bin/bash -docker build --build-arg TAG=1.12.2 -t xubiaolin/zerotier-planet:latest . \ No newline at end of file +USER=zerotier +REPO=ZeroTierOne + +latest_tag=$(curl -s "https://api.github.com/repos/$USER/$REPO/tags" | jq -r '.[].name' | grep -E "^[0-9]+\.[0-9]+\.[0-9]+$" | sort -V | tail -n 1) + +echo "Latest tag for $USER/$REPO matching latest is: $latest_tag" + +docker build --build-arg TAG="$latest_tag" -t "xubiaolin/zerotier-planet:$latest_tag" . +docker tag "xubiaolin/zerotier-planet:$latest_tag" "xubiaolin/zerotier-planet:latest" diff --git a/deploy.sh b/deploy.sh index 7bd4ba3..e841a4a 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,116 +1,131 @@ #!/bin/bash -CONTAINER_NAME=myztplanet -# 如果是centos 且内核版本小于5.*,提示内核版本太低 -kernel_check(){ - os_name=$(cat /etc/os-release | grep ^ID= | cut -d'=' -f2) +CONTAINER_NAME="myztplanet" +ZEROTIER_PATH="$(pwd)/data/zerotier" +CONFIG_PATH="${ZEROTIER_PATH}/config" +DIST_PATH="${ZEROTIER_PATH}/dist" +ZTNCUI_PATH="${ZEROTIER_PATH}/ztncui" +DOCKER_IMAGE="xubiaolin/zerotier-planet:latest" + +print_message() { + local message=$1 + local color_code=$2 + echo -e "\033[${color_code}m${message}\033[0m" +} + +# 检查内核版本 +kernel_check() { + os_name=$(grep ^ID= /etc/os-release | cut -d'=' -f2 | tr -d '"') kernel_version=$(uname -r | cut -d'.' -f1) - if [[ "$kernel_version" -lt 5 ]]; then - if [[ "$os_name" == "\"centos\"" ]]; then - echo -e "\033[31m内核版本太低,请在菜单中选择CentOS内核升级\033[0m" - exit 1 + if ((kernel_version < 5)); then + if [[ "$os_name" == "centos" ]]; then + print_message "内核版本太低,请在菜单中选择CentOS内核升级" "31" else - echo -e "\033[31m请自行升级系统内核到5.*及其以上版本\033[0m" - exit 1 + print_message "请自行升级系统内核到5.*及其以上版本" "31" fi + exit 1 else - echo "当前内核版本为:$kernel_version" - echo -e "\033[32m系统和内核版本检查通过。\033[0m" + print_message "系统和内核版本检查通过,当前内核版本为:$kernel_version" "32" fi } -update_centos_kernal(){ +# 升级CentOS内核 +update_centos_kernel() { echo "请注意备份数据,升级内核有风险" - read -p "是否继续升级内核?(y/n)" continue_update - continue_update=${continue_update:-n} + read -p "是否继续升级内核?(y/n) " continue_update if [[ "$continue_update" =~ ^[Yy]$ ]]; then - echo "如果配置较低,可能升级时间较长,请耐心等待!开始升级内核..." + echo "升级时间较长,请耐心等待!开始升级内核..." yum update -y rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org - yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm -y - yum --disablerepo="*" --enablerepo="elrepo-kernel" list available - yum --enablerepo=elrepo-kernel install kernel-lt-devel kernel-lt -y + yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm + yum --disablerepo="*" --enablerepo="elrepo-kernel" install -y kernel-lt-devel kernel-lt sudo awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg grub2-set-default 0 grub2-mkconfig -o /boot/grub2/grub.cfg - - read -p "内核升级完成,请重启系统,是否立刻重启?(y/n)" reboot - reboot=${reboot:-n} + read -p "内核升级完成,请重启系统,是否立刻重启?(y/n) " reboot if [[ "$reboot" =~ ^[Yy]$ ]]; then reboot now else echo "已取消重启" exit 0 fi - - echo "内核升级完成,请重启系统" - exit 0 else echo "已取消升级内核" exit 0 fi - } +# 安装lsof工具 install_lsof() { - if [ ! -f "/usr/bin/lsof" ]; then + if ! command -v lsof &>/dev/null; then echo "开始安装lsof工具..." - [ -f "/usr/bin/apt" ] && ( - apt update - apt install -y lsof - ) - [ -f "/usr/bin/yum" ] && yum install -y lsof + if command -v apt &>/dev/null; then + apt update && apt install -y lsof + elif command -v yum &>/dev/null; then + yum install -y lsof + fi fi } +# 检查端口是否被占用 check_port() { local port=$1 - if [ $(lsof -i:${port} | wc -l) -gt 0 ]; then + if lsof -i:${port} &>/dev/null; then echo "端口${port}已被占用,请重新输入" exit 1 fi } +# 读取端口号 read_port() { local port local prompt=$1 - read -p "${prompt}" port - while [[ ! "$port" =~ ^[0-9]+$ ]]; do - read -p "端口号必须是数字,请重新输入: " port + while :; do + read -p "${prompt}" port + [[ "$port" =~ ^[0-9]+$ ]] && break + echo "端口号必须是数字,请重新输入: " done check_port $port echo $port } +# 获取IP地址 +configure_ip() { + ipv4=$(curl -s https://ipv4.icanhazip.com/) + ipv6=$(curl -s https://ipv6.icanhazip.com/) + echo "获取到的IPv4地址为: $ipv4" + echo "获取到的IPv6地址为: $ipv6" +} + +# 安装zerotier-planet install() { kernel_check - echo "开始安装,如果你已经安装了,将会删除旧的数据,10s后开始安装..." + if docker inspect ${CONTAINER_NAME} &>/dev/null; then + echo "容器${CONTAINER_NAME}已经存在" + read -p "是否更新版本?(y/n) " update_version + if [[ "$update_version" =~ ^[Yy]$ ]]; then + upgrade + exit 0 + fi + fi + + echo "开始安装,如果你已经安装了,将会删除旧的数据,10秒后开始安装..." sleep 10 install_lsof - docker rm -f ${CONTAINER_NAME} - rm -rf $(pwd)/data/zerotier + docker rm -f ${CONTAINER_NAME} || true + rm -rf ${ZEROTIER_PATH} - ZT_PORT=$(read_port "请输入zerotier-planet要使用的端口号,例如9994: ") - API_PORT=$(read_port "请输入zerotier-planet的API端口号,例如3443: ") - FILE_PORT=$(read_port "请输入zerotier-planet的FILE端口号,例如3000: ") + ZT_PORT=$(read_port "请输入zerotier-planet要使用的端口号,例如9994: ") + API_PORT=$(read_port "请输入zerotier-planet的API端口号,例如3443: ") + FILE_PORT=$(read_port "请输入zerotier-planet的FILE端口号,例如3000: ") - configure_ip() { - ipv4=$(curl -s https://ipv4.icanhazip.com/) - ipv6=$(curl -s https://ipv6.icanhazip.com/) - echo "获取到的IPv4地址为: $ipv4" - echo "获取到的IPv6地址为: $ipv6" - } - - read -p "是否自动获取公网IP地址?(y/n)" use_auto_ip - use_auto_ip=${use_auto_ip:-y} + read -p "是否自动获取公网IP地址?(y/n) " use_auto_ip if [[ "$use_auto_ip" =~ ^[Yy]$ ]]; then configure_ip - - read -p "是否使用上面获取到的IP地址?(y/n)" use_auto_ip_result - use_auto_ip_result=${use_auto_ip_result:-y} + read -p "是否使用上面获取到的IP地址?(y/n) " use_auto_ip_result if [[ "$use_auto_ip_result" =~ ^[Nn]$ ]]; then read -p "请输入IPv4地址: " ipv4 read -p "请输入IPv6地址(可留空): " ipv6 @@ -139,32 +154,17 @@ install() { -e ZT_PORT=${ZT_PORT} \ -e API_PORT=${API_PORT} \ -e FILE_SERVER_PORT=${FILE_PORT} \ - -v $(pwd)/data/zerotier/dist:/app/dist \ - -v $(pwd)/data/zerotier/ztncui:/app/ztncui \ - -v $(pwd)/data/zerotier/one:/var/lib/zerotier-one -v $(pwd)/data/zerotier/config:/app/config --restart unless-stopped xubiaolin/zerotier-planet:latest - - if [ $? -ne 0 ]; then - echo "安装失败" - exit 1 - fi + -v ${DIST_PATH}:/app/dist \ + -v ${ZTNCUI_PATH}:/app/ztncui \ + -v ${ZEROTIER_PATH}/one:/var/lib/zerotier-one \ + -v ${CONFIG_PATH}:/app/config \ + --restart unless-stopped \ + ${DOCKER_IMAGE} sleep 10 - retrieve_keys() { - KEY=$(docker exec -it ${CONTAINER_NAME} sh -c 'cat /app/config/file_server.key') - MOON_NAME=$(docker exec -it ${CONTAINER_NAME} sh -c 'ls /app/dist | grep moon') - } - - retrieve_keys - - clean_vars() { - ipv4=$(echo $ipv4 | tr -d '\r') - FILE_PORT=$(echo $FILE_PORT | tr -d '\r') - KEY=$(echo $KEY | tr -d '\r') - MOON_NAME=$(echo $MOON_NAME | tr -d '\r') - } - - clean_vars + KEY=$(docker exec -it ${CONTAINER_NAME} sh -c 'cat /app/config/file_server.key' | tr -d '\r') + MOON_NAME=$(docker exec -it ${CONTAINER_NAME} sh -c 'ls /app/dist | grep moon' | tr -d '\r') echo "安装完成" echo "---------------------------" @@ -173,26 +173,23 @@ install() { echo "默认密码:password" echo "请及时修改密码" echo "---------------------------" - - echo "moon配置和planet配置在 $(pwd)/data/zerotier/dist 目录下" - echo -e "moons 文件下载: http://${ipv4}:${FILE_PORT}/${MOON_NAME}?key=${KEY} " - echo -e "planet文件下载: http://${ipv4}:${FILE_PORT}/planet?key=${KEY} " - + echo "moon配置和planet配置在 ${DIST_PATH} 目录下" + echo "moons 文件下载: http://${ipv4}:${FILE_PORT}/${MOON_NAME}?key=${KEY} " + echo "planet文件下载: http://${ipv4}:${FILE_PORT}/planet?key=${KEY} " echo "---------------------------" - echo "请放行以下端口请:${ZT_PORT}/tcp,${ZT_PORT}/udp,${API_PORT}/tcp,${FILE_PORT}/tcp" + echo "请放行以下端口:${ZT_PORT}/tcp,${ZT_PORT}/udp,${API_PORT}/tcp,${FILE_PORT}/tcp" echo "---------------------------" } -info() { - docker inspect ${CONTAINER_NAME} >/dev/null 2>&1 - if [ $? -ne 0 ]; then - echo "容器${CONTAINER_NAME}不存在,请先安装" +install_from_config() { + if [ ! -d "${CONFIG_PATH}" ] || [ ! "$(ls -A ${CONFIG_PATH})" ]; then + echo "配置文件目录不存在或为空,请先上传配置文件" exit 1 fi extract_config() { local config_name=$1 - docker exec -it ${CONTAINER_NAME} sh -c "cat /app/config/${config_name}" | tr -d '\r' + cat ${CONFIG_PATH}/${config_name} | tr -d '\r' } ipv4=$(extract_config "ip_addr4") @@ -201,21 +198,96 @@ info() { FILE_PORT=$(extract_config "file_server.port") ZT_PORT=$(extract_config "zerotier-one.port") KEY=$(extract_config "file_server.key") - - MOON_NAME=$(docker exec -it ${CONTAINER_NAME} sh -c "ls /app/dist | grep moon" | tr -d '\r') + MOON_NAME=$(ls ${DIST_PATH}/ | grep moon | tr -d '\r') echo "---------------------------" - echo "以下端口的tcp和udp协议请放行:${ZT_PORT},${API_PORT},${FILE_PORT}" + echo "ipv4:${ipv4}" + echo "ipv6:${ipv6}" + echo "API_PORT:${API_PORT}" + echo "FILE_PORT:${FILE_PORT}" + echo "ZT_PORT:${ZT_PORT}" + echo "KEY:${KEY}" + echo "MOON_NAME:${MOON_NAME}" + echo "---------------------------" + + docker run -d \ + --name ${CONTAINER_NAME} \ + -p ${ZT_PORT}:${ZT_PORT} \ + -p ${ZT_PORT}:${ZT_PORT}/udp \ + -p ${API_PORT}:${API_PORT} \ + -p ${FILE_PORT}:${FILE_PORT} \ + -e IP_ADDR4=${ipv4} \ + -e IP_ADDR6=${ipv6} \ + -e ZT_PORT=${ZT_PORT} \ + -e API_PORT=${API_PORT} \ + -e FILE_SERVER_PORT=${FILE_PORT} \ + -v ${DIST_PATH}:/app/dist \ + -v ${ZTNCUI_PATH}:/app/ztncui \ + -v ${ZEROTIER_PATH}/one:/var/lib/zerotier-one \ + -v ${CONFIG_PATH}:/app/config \ + --restart unless-stopped \ + ${DOCKER_IMAGE} +} + +upgrade() { + if ! docker inspect ${CONTAINER_NAME} &>/dev/null; then + echo "容器${CONTAINER_NAME}不存在,请先安装" + exit 1 + fi + + docker pull ${DOCKER_IMAGE} + new_image_id=$(docker inspect ${DOCKER_IMAGE} --format='{{.Id}}') + old_image_id=$(docker inspect ${CONTAINER_NAME} --format='{{.Image}}') + if [ "$new_image_id" == "$old_image_id" ]; then + print_message "当前版本已经是最新版本" "32" + exit 0 + else + echo "发现新版本,开始升级...new_image_id:${new_image_id},old_image_id:${old_image_id}" + echo "更新可能存在风险,请手动备份data目录中的数据,谨慎操作" + read -p "是否继续升级?(y/n) " continue_upgrade + if [[ ! "$continue_upgrade" =~ ^[Yy]$ ]]; then + echo "已取消升级" + exit 0 + fi + fi + + echo "开始升级,将会删除旧的容器,10秒后开始升级..." + sleep 10 + + docker rm -f ${CONTAINER_NAME} || true + install_from_config +} + +info() { + if ! docker inspect ${CONTAINER_NAME} &>/dev/null; then + echo "容器${CONTAINER_NAME}不存在,请先安装" + exit 1 + fi + + extract_config() { + local config_name=$1 + cat ${CONFIG_PATH}/${config_name} | tr -d '\r' + } + + ipv4=$(extract_config "ip_addr4") + ipv6=$(extract_config "ip_addr6") + API_PORT=$(extract_config "ztncui.port") + FILE_PORT=$(extract_config "file_server.port") + ZT_PORT=$(extract_config "zerotier-one.port") + KEY=$(extract_config "file_server.key") + MOON_NAME=$(ls ${DIST_PATH}/ | grep moon | tr -d '\r') + + echo "---------------------------" + print_message "以下端口的tcp和udp协议请放行:${ZT_PORT},${API_PORT},${FILE_PORT}" "32" echo "---------------------------" echo "请访问 http://${ipv4}:${API_PORT} 进行配置" echo "默认用户名:admin" echo "默认密码:password" echo "请及时修改密码" echo "---------------------------" - echo "moon配置和planet配置在 $(pwd)/data/zerotier/dist 目录下" - echo "" - echo "planet文件下载: http://${ipv4}:${FILE_PORT}/planet?key=${KEY} " - echo "moon文件下载: http://${ipv4}:${FILE_PORT}/${MOON_NAME}?key=${KEY} " + print_message "moon配置和planet配置在 ${DIST_PATH} 目录下" "32" + print_message "planet文件下载: http://${ipv4}:${FILE_PORT}/planet?key=${KEY} " "32" + print_message "moon文件下载: http://${ipv4}:${FILE_PORT}/${MOON_NAME}?key=${KEY} " "32" } uninstall() { @@ -223,71 +295,16 @@ uninstall() { docker stop ${CONTAINER_NAME} docker rm ${CONTAINER_NAME} - docker rmi xubiaolin/zerotier-planet:latest + docker rmi ${DOCKER_IMAGE} - read -p "是否删除数据?(y/n)" delete_data - delete_data=${delete_data:-n} + read -p "是否删除数据?(y/n) " delete_data if [[ "$delete_data" =~ ^[Yy]$ ]]; then - rm -rf $(pwd)/data/zerotier + rm -rf ${ZEROTIER_PATH} fi echo "卸载完成" } -# update() { -# docker inspect ${CONTAINER_NAME} >/dev/null 2>&1 -# if [ $? -ne 0 ]; then -# echo "容器${CONTAINER_NAME}不存在,请先安装" -# exit 1 -# fi - -# echo "如果用于生产环境,请先备份数据,不建议直接更新,10s后开始更新..." -# sleep 10 - -# if [ ! -d "$(pwd)/data/zerotier" ]; then -# echo "目录$(pwd)/data/zerotier不存在,无法更新" -# exit 0 -# fi - -# extract_config() { -# local config_name=$1 -# docker exec -it ${CONTAINER_NAME} sh -c "cat /app/config/${config_name}" | tr -d '\r' -# } - -# ipv4=$(extract_config "ip_addr4") -# ipv6=$(extract_config "ip_addr6") -# API_PORT=$(extract_config "ztncui.port") -# FILE_PORT=$(extract_config "ztncui.port") -# ZT_PORT=$(extract_config "zerotier-one.port") - -# echo "---------------------------" -# echo "ipv4地址为:${ipv4}" -# echo "ipv6地址为:${ipv6}" -# echo "API端口号为:${API_PORT}" -# echo "FILE端口号为:${FILE_PORT}" -# echo "ZT端口号为:${ZT_PORT}" - -# docker stop ${CONTAINER_NAME} -# docker rm ${CONTAINER_NAME} - -# docker pull xubiaolin/zerotier-planet:latest -# docker run -d --name ${CONTAINER_NAME} -p ${ZT_PORT}:${ZT_PORT} \ -# -p ${ZT_PORT}:${ZT_PORT}/udp \ -# -p ${API_PORT}:${API_PORT} \ -# -p ${FILE_PORT}:${FILE_PORT} \ -# -e IP_ADDR4=${ipv4} \ -# -e IP_ADDR6=${ipv6} \ -# -e ZT_PORT=${ZT_PORT} \ -# -e API_PORT=${API_PORT} \ -# -e FILE_SERVER_PORT=${FILE_PORT} \ -# -v $(pwd)/data/zerotier/dist:/app/dist \ -# -v $(pwd)/data/zerotier/ztncui:/app/ztncui \ -# -v $(pwd)/data/zerotier/one:/var/lib/zerotier-one \ -# -v $(pwd)/data/zerotier/config:/app/config \ -# --restart unless-stopped \ -# xubiaolin/zerotier-planet:latest -# } - resetpwd() { docker exec -it ${CONTAINER_NAME} sh -c 'cp /app/ztncui/src/etc/default.passwd /app/ztncui/src/etc/passwd' if [ $? -ne 0 ]; then @@ -311,21 +328,21 @@ menu() { echo "欢迎使用zerotier-planet脚本,请选择需要执行的操作:" echo "1. 安装" echo "2. 卸载" - # echo "3. 更新" + echo "3. 更新" echo "4. 查看信息" echo "5. 重置密码" echo "6. CentOS内核升级" echo "0. 退出" read -p "请输入数字:" num case "$num" in - [1]) install ;; - [2]) uninstall ;; - # [3]) update ;; - [4]) info ;; - [5]) resetpwd ;; - [6]) update_centos_kernal ;; - [0]) exit ;; - *) echo "请输入正确数字 [1-5]" ;; + 1) install ;; + 2) uninstall ;; + 3) upgrade ;; + 4) info ;; + 5) resetpwd ;; + 6) update_centos_kernel ;; + 0) exit ;; + *) echo "请输入正确数字 [0-6]" ;; esac } diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index 4185168..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/sh - -set -x - -function start() { - echo "start ztncui and zerotier" - cd /var/lib/zerotier-one && ./zerotier-one -p$(cat /app/config/zerotier-one.port) -d || exit 1 - nohup node /app/http_server.js &> /app/server.log & - cd /app/ztncui/src && npm start || exit 1 -} - -function check_file_server(){ - if [ ! -f "/app/config/file_server.port" ]; then - echo "file_server.port is not exist, generate it" - echo "${FILE_SERVER_PORT}" >/app/config/file_server.port - echo "${FILE_SERVER_PORT}" - else - echo "file_server.port is exist, read it" - FILE_SERVER_PORT=$(cat /app/config/file_server.port) - echo "${FILE_SERVER_PORT}" - fi -} - -function check_zerotier() { - mkdir -p /var/lib/zerotier-one - if [ "$(ls -A /var/lib/zerotier-one)" ]; then - echo "/var/lib/zerotier-one is not empty, start directly" - else - mkdir -p /app/config - echo "/var/lib/zerotier-one is empty, init data" - echo "${ZT_PORT}" >/app/config/zerotier-one.port - cp -r /bak/zerotier-one/* /var/lib/zerotier-one/ - - cd /var/lib/zerotier-one - echo "start mkmoonworld" - openssl rand -hex 16 > authtoken.secret - - ./zerotier-idtool generate identity.secret identity.public - ./zerotier-idtool initmoon identity.public >moon.json - - if [ -z "$IP_ADDR4" ]; then IP_ADDR4=$(curl -s https://ipv4.icanhazip.com/); fi - if [ -z "$IP_ADDR6" ]; then IP_ADDR6=$(curl -s https://ipv6.icanhazip.com/); fi - - echo "IP_ADDR4=$IP_ADDR4" - echo "IP_ADDR6=$IP_ADDR6" - - ZT_PORT=$(cat /app/config/zerotier-one.port) - - echo "ZT_PORT=$ZT_PORT" - - if [ -z "$IP_ADDR4" ]; then stableEndpoints="[\"$IP_ADDR6/${ZT_PORT}\"]"; fi - if [ -z "$IP_ADDR6" ]; then stableEndpoints="[\"$IP_ADDR4/${ZT_PORT}\"]"; fi - if [ -n "$IP_ADDR4" ] && [ -n "$IP_ADDR6" ]; then stableEndpoints="[\"$IP_ADDR4/${ZT_PORT}\",\"$IP_ADDR6/${ZT_PORT}\"]"; fi - if [ -z "$IP_ADDR4" ] && [ -z "$IP_ADDR6" ]; then - echo "IP_ADDR4 and IP_ADDR6 are both empty!" - exit 1 - fi - - echo "$IP_ADDR4">/app/config/ip_addr4 - echo "$IP_ADDR6">/app/config/ip_addr6 - - echo "stableEndpoints=$stableEndpoints" - - jq --argjson newEndpoints "$stableEndpoints" '.roots[0].stableEndpoints = $newEndpoints' moon.json >temp.json && mv temp.json moon.json - ./zerotier-idtool genmoon moon.json && mkdir -p moons.d && cp ./*.moon ./moons.d - - cp /app/mkmoonworld-x86_64 ./mkmoonworld-x86_64 - chmod +x ./mkmoonworld-x86_64 - ./mkmoonworld-x86_64 moon.json - if [ $? -ne 0 ]; then - echo "mkmoonworld failed!" - exit 1 - fi - - mkdir -p /app/dist/ - mv world.bin /app/dist/planet - cp *.moon /app/dist/ - echo -e "mkmoonworld success!\n" - fi -} - -function check_ztncui() { - mkdir -p /app/ztncui - if [ "$(ls -A /app/ztncui)" ]; then - echo "${API_PORT}" >/app/config/ztncui.port - echo "/app/ztncui is not empty, start directly" - else - echo "/app/ztncui is empty, init data" - cp -r /bak/ztncui/* /app/ztncui/ - - echo "config ztncui" - mkdir -p /app/config - echo "${API_PORT}" >/app/config/ztncui.port - cd /app/ztncui/src - echo "HTTP_PORT=${API_PORT}" >.env && - echo 'NODE_ENV=production' >>.env && - echo 'HTTP_ALL_INTERFACES=true' >>.env && - echo "ZT_ADDR=localhost:${ZT_PORT}" >>.env && echo "${ZT_PORT}" >/app/config/zerotier-one.port && - cp -v etc/default.passwd etc/passwd && TOKEN=$(cat /var/lib/zerotier-one/authtoken.secret) && - echo "ZT_TOKEN=$TOKEN" >>.env && - echo "make ztncui success!" - fi -} - -check_file_server -check_zerotier -check_ztncui - -start \ No newline at end of file diff --git a/mkmoonworld-x86_64 b/mkmoonworld-x86_64 deleted file mode 100755 index db80c95..0000000 Binary files a/mkmoonworld-x86_64 and /dev/null differ diff --git a/patch/entrypoint.sh b/patch/entrypoint.sh new file mode 100755 index 0000000..55b2b2b --- /dev/null +++ b/patch/entrypoint.sh @@ -0,0 +1,125 @@ +#!/bin/sh + +set -x + +# 配置路径和端口 +ZEROTIER_PATH="/var/lib/zerotier-one" +APP_PATH="/app" +CONFIG_PATH="${APP_PATH}/config" +BACKUP_PATH="/bak" +ZTNCUI_PATH="${APP_PATH}/ztncui" +ZTNCUI_SRC_PATH="${ZTNCUI_PATH}/src" + +# 启动 ZeroTier 和 ztncui +function start() { + echo "Start ztncui and zerotier" + cd $ZEROTIER_PATH && ./zerotier-one -p$(cat ${CONFIG_PATH}/zerotier-one.port) -d || exit 1 + nohup node ${APP_PATH}/http_server.js &> ${APP_PATH}/server.log & + cd $ZTNCUI_SRC_PATH && npm start || exit 1 +} + +# 检查文件服务器端口配置文件 +function check_file_server() { + if [ ! -f "${CONFIG_PATH}/file_server.port" ]; then + echo "file_server.port does not exist, generating it" + echo "${FILE_SERVER_PORT}" > ${CONFIG_PATH}/file_server.port + else + echo "file_server.port exists, reading it" + FILE_SERVER_PORT=$(cat ${CONFIG_PATH}/file_server.port) + fi + echo "${FILE_SERVER_PORT}" +} + +# 初始化 ZeroTier 数据 +function init_zerotier_data() { + echo "Initializing ZeroTier data" + echo "${ZT_PORT}" > ${CONFIG_PATH}/zerotier-one.port + cp -r ${BACKUP_PATH}/zerotier-one/* $ZEROTIER_PATH + + cd $ZEROTIER_PATH + openssl rand -hex 16 > authtoken.secret + ./zerotier-idtool generate identity.secret identity.public + ./zerotier-idtool initmoon identity.public > moon.json + + IP_ADDR4=${IP_ADDR4:-$(curl -s https://ipv4.icanhazip.com/)} + IP_ADDR6=${IP_ADDR6:-$(curl -s https://ipv6.icanhazip.com/)} + + echo "IP_ADDR4=$IP_ADDR4" + echo "IP_ADDR6=$IP_ADDR6" + ZT_PORT=$(cat ${CONFIG_PATH}/zerotier-one.port) + echo "ZT_PORT=$ZT_PORT" + + if [ -n "$IP_ADDR4" ] && [ -n "$IP_ADDR6" ]; then + stableEndpoints="[\"$IP_ADDR4/${ZT_PORT}\",\"$IP_ADDR6/${ZT_PORT}\"]" + elif [ -n "$IP_ADDR4" ]; then + stableEndpoints="[\"$IP_ADDR4/${ZT_PORT}\"]" + elif [ -n "$IP_ADDR6" ]; then + stableEndpoints="[\"$IP_ADDR6/${ZT_PORT}\"]" + else + echo "IP_ADDR4 and IP_ADDR6 are both empty!" + exit 1 + fi + + echo "$IP_ADDR4" > ${CONFIG_PATH}/ip_addr4 + echo "$IP_ADDR6" > ${CONFIG_PATH}/ip_addr6 + echo "stableEndpoints=$stableEndpoints" + + jq --argjson newEndpoints "$stableEndpoints" '.roots[0].stableEndpoints = $newEndpoints' moon.json > temp.json && mv temp.json moon.json + ./zerotier-idtool genmoon moon.json && mkdir -p moons.d && cp ./*.moon ./moons.d + + ./mkworld + if [ $? -ne 0 ]; then + echo "mkmoonworld failed!" + exit 1 + fi + + mkdir -p ${APP_PATH}/dist/ + mv world.bin ${APP_PATH}/dist/planet + cp *.moon ${APP_PATH}/dist/ + echo "mkmoonworld success!" +} + +# 检查并初始化 ZeroTier +function check_zerotier() { + mkdir -p $ZEROTIER_PATH + if [ "$(ls -A $ZEROTIER_PATH)" ]; then + echo "$ZEROTIER_PATH is not empty, starting directly" + else + init_zerotier_data + fi +} + +# 初始化 ztncui 数据 +function init_ztncui_data() { + echo "Initializing ztncui data" + cp -r ${BACKUP_PATH}/ztncui/* $ZTNCUI_PATH + + echo "Configuring ztncui" + mkdir -p ${CONFIG_PATH} + echo "${API_PORT}" > ${CONFIG_PATH}/ztncui.port + cd $ZTNCUI_SRC_PATH + echo "HTTP_PORT=${API_PORT}" > .env + echo 'NODE_ENV=production' >> .env + echo 'HTTP_ALL_INTERFACES=true' >> .env + echo "ZT_ADDR=localhost:${ZT_PORT}" >> .env + cp -v etc/default.passwd etc/passwd + TOKEN=$(cat ${ZEROTIER_PATH}/authtoken.secret) + echo "ZT_TOKEN=$TOKEN" >> .env + echo "ztncui configuration successful!" +} + +# 检查并初始化 ztncui +function check_ztncui() { + mkdir -p $ZTNCUI_PATH + if [ "$(ls -A $ZTNCUI_PATH)" ]; then + echo "${API_PORT}" > ${CONFIG_PATH}/ztncui.port + echo "$ZTNCUI_PATH is not empty, starting directly" + else + init_ztncui_data + fi +} + +check_file_server +check_zerotier +check_ztncui +start diff --git a/http_server.js b/patch/http_server.js similarity index 100% rename from http_server.js rename to patch/http_server.js diff --git a/patch/mkworld_custom.cpp b/patch/mkworld_custom.cpp new file mode 100644 index 0000000..16830e8 --- /dev/null +++ b/patch/mkworld_custom.cpp @@ -0,0 +1,232 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + /* + * This utility makes the World from the configuration specified below. + * It probably won't be much use to anyone outside ZeroTier, Inc. except + * for testing and experimentation purposes. + * + * If you want to make your own World you must edit this file. + * + * When run, it expects two files in the current directory: + * + * previous.c25519 - key pair to sign this world (key from previous world) + * current.c25519 - key pair whose public key should be embedded in this world + * + * If these files do not exist, they are both created with the same key pair + * and a self-signed initial World is born. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace ZeroTier; +using json = nlohmann::json; + +void printHelp() { + printf("Usage: mkworld [options]\n"); + printf("Options:\n"); + printf(" -h, --help Display this help message\n"); + printf(" -j, --json2bin Convert from JSON file to world.bin\n"); + printf(" -b, --bin2json Convert from world.bin to JSON format\n"); +} + +int jsonToBinary() { + std::string previous, current; + if ((!OSUtils::readFile("previous.c25519", previous)) || (!OSUtils::readFile("current.c25519", current))) { + C25519::Pair np(C25519::generate()); + previous = std::string(); + previous.append((const char*)np.pub.data, ZT_C25519_PUBLIC_KEY_LEN); + previous.append((const char*)np.priv.data, ZT_C25519_PRIVATE_KEY_LEN); + current = previous; + OSUtils::writeFile("previous.c25519", previous); + OSUtils::writeFile("current.c25519", current); + fprintf(stderr, "INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)" ZT_EOL_S); + } + + if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN)) || (current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) { + fprintf(stderr, "FATAL: previous.c25519 or current.c25519 empty or invalid" ZT_EOL_S); + return 1; + } + C25519::Pair previousKP; + memcpy(previousKP.pub.data, previous.data(), ZT_C25519_PUBLIC_KEY_LEN); + memcpy(previousKP.priv.data, previous.data() + ZT_C25519_PUBLIC_KEY_LEN, ZT_C25519_PRIVATE_KEY_LEN); + C25519::Pair currentKP; + memcpy(currentKP.pub.data, current.data(), ZT_C25519_PUBLIC_KEY_LEN); + memcpy(currentKP.priv.data, current.data() + ZT_C25519_PUBLIC_KEY_LEN, ZT_C25519_PRIVATE_KEY_LEN); + + // ========================================================================= + // EDIT BELOW HERE + + std::vector roots; + + const uint64_t id = ZT_WORLD_ID_EARTH; + const uint64_t ts = 1567191349589ULL; // August 30th, 2019 + + std::string fileContent; + if (!OSUtils::readFile("moon.json", fileContent)) { + fprintf(stderr, "Failed to open config file." ZT_EOL_S); + return 1; + } + + // 解析JSON数据 + json config = json::parse(fileContent); + + + for (auto& root : config["roots"]) { + roots.push_back(World::Root()); + roots.back().identity = Identity(root["identity"].get().c_str()); + for (auto& endpoint : root["stableEndpoints"]) { + roots.back().stableEndpoints.push_back(InetAddress(endpoint.get().c_str())); + } + } + + fprintf(stderr, "INFO: generating and signing id==%llu ts==%llu" ZT_EOL_S, (unsigned long long)id, (unsigned long long)ts); + + World nw = World::make(World::TYPE_PLANET, id, ts, currentKP.pub, roots, previousKP); + + Buffer outtmp; + nw.serialize(outtmp, false); + World testw; + testw.deserialize(outtmp, 0); + if (testw != nw) { + fprintf(stderr, "FATAL: serialization test failed!" ZT_EOL_S); + return 1; + } + + OSUtils::writeFile("world.bin", std::string((const char*)outtmp.data(), outtmp.size())); + fprintf(stderr, "INFO: world.bin written with %u bytes of binary world data." ZT_EOL_S, outtmp.size()); + + fprintf(stdout, ZT_EOL_S); + fprintf(stdout, "#define ZT_DEFAULT_WORLD_LENGTH %u" ZT_EOL_S, outtmp.size()); + fprintf(stdout, "static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); + for (unsigned int i = 0; i < outtmp.size(); ++i) { + const unsigned char* d = (const unsigned char*)outtmp.data(); + if (i > 0) + fprintf(stdout, ","); + fprintf(stdout, "0x%.2x", (unsigned int)d[i]); + } + fprintf(stdout, "};" ZT_EOL_S); + return 0; +} + +void binaryToJson() { + // Read world.bin file into memory + std::string binContent; + if (!OSUtils::readFile("world.bin", binContent)) { + fprintf(stderr, "Failed to open world.bin file." ZT_EOL_S); + return; + } + + // Deserialize the binary data into a World object + Buffer binBuffer(binContent.data(), binContent.size()); + World world; + if (!world.deserialize(binBuffer, 0)) { + fprintf(stderr, "Failed to deserialize world.bin content." ZT_EOL_S); + return; + } + + // Create a JSON object to store the world data + json worldJson; + + + // Add roots array to the JSON object + json rootsJson; + for (const auto& root : world.roots()) { + json rootJson; + + // Add identity to the root JSON object + char identityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + root.identity.toString(true, identityStr); // Include private key + rootJson["identity"] = identityStr; + + // Add stableEndpoints array to the root JSON object + json stableEndpointsJson; + for (const auto& endpoint : root.stableEndpoints) { + char ipStr[64]; + endpoint.toString(ipStr); + stableEndpointsJson.push_back(ipStr); + } + rootJson["stableEndpoints"] = stableEndpointsJson; + + rootsJson.push_back(rootJson); + } + worldJson["roots"] = rootsJson; + std::string jsonStr = worldJson.dump(4); + printf("World JSON:\n%s\n", jsonStr.c_str()); + if (!OSUtils::writeFile("config.json", jsonStr.c_str(), jsonStr.size())) { + fprintf(stderr, "Failed to write JSON data to config.json." ZT_EOL_S); + } + else { + printf("JSON data successfully written to config.json." ZT_EOL_S); + } +} + + +int main(int argc, char** argv) +{ + bool json2bin = false; + bool bin2json = false; + + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "-h" || arg == "--help") { + printHelp(); + return 0; + } + else if (arg == "-j" || arg == "--json2bin") { + json2bin = true; + } + else if (arg == "-b" || arg == "--bin2json") { + bin2json = true; + } + } + + if (!(json2bin || bin2json)) { + // Default behavior: convert from JSON to world.bin + json2bin = true; + } + + if (json2bin && bin2json) { + printf("Error: Cannot specify both JSON to binary and binary to JSON conversion options.\n"); + printHelp(); + return 1; + } + + if (json2bin) { + jsonToBinary(); + } + else if (bin2json) { + binaryToJson(); + } + + return 0; +}