diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 18b663d..f4aca2f 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -47,53 +47,38 @@ jobs: upload: name: Telegram Upload Release runs-on: ubuntu-latest - if: ${{ startsWith(github.event.head_commit.message, '[telUp]') }} needs: [build] steps: - uses: actions/checkout@v3 + - name: Get tags + id: get_tags + run: | + echo "tag=$(grep -oP 'version=\K[^ ]+' module.prop)" >> "$GITHUB_OUTPUT" + echo "date=$(date +%Y%m%d_%H%M)" >> "$GITHUB_OUTPUT" + - name: Get Version and Build run: | - sed -i "s/${{ steps.get_tags.outputs.tags }}/&_$(date +%Y%m%d_%H%M)_debug/g" module.prop + sed -i "s/${{ steps.get_tags.outputs.tag }}/&_$(date +%Y%m%d_%H%M)_debug/g" module.prop sh build.sh - name: Release run: | mkdir bfr find -name "*.zip" -exec cp {} bfr \; - - function upload() { - for file in $@; do - echo ">> Uploading $file" - curl https://api.telegram.org/bot${{ secrets.TELEGRAM_TOKEN }}/sendDocument \ - -X POST \ - -F chat_id="${{ secrets.TELEGRAM_TO }}" \ - -F document="@$file" \ - --silent --show-error --fail >/dev/null & - done - for job in $(jobs -p); do - wait $job || exit 1 - done - } - upload bfr/* - commit: - name: Commit GitHub - runs-on: ubuntu-latest - if: ${{ startsWith(github.event.head_commit.message, '[telUp]') }} - needs: [build] - steps: - - name: Checkout Repository - uses: actions/checkout@v3 - - - name: get commit url - id: commit_url + - name: Upload to telegram + env: + CHAT_ID: ${{ secrets.CHAT_ID }} + CACHE_CHAT_ID: ${{ secrets.CACHE_CHAT_ID }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }} + COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_URL: ${{ github.event.head_commit.url }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + TITLE: BFM/R ${{ steps.get_tags.outputs.tag }}_${{ steps.get_tags.outputs.date }}_debug run: | - echo "::set-output name=commit::$(git log -1 --pretty=format:%s)" - - - name: send commit to telegram - uses: appleboy/telegram-action@master - with: - to: ${{ secrets.TELEGRAM_TO }} - token: ${{ secrets.TELEGRAM_TOKEN }} - message: "${{ steps.commit_url.outputs.commit }}" \ No newline at end of file + export VERSION=$(date +%m%d) + FILE=$(find ./bfr/* -type f) + pip3 install python-telegram-bot + python3 docs/tubot.py $FILE \ No newline at end of file diff --git a/box/scripts/box.iptables b/box/scripts/box.iptables index 491ab8d..a7ed3c7 100755 --- a/box/scripts/box.iptables +++ b/box/scripts/box.iptables @@ -74,7 +74,7 @@ box_sync_port() { find_packages_uid() { echo -n "" > "${uid_list}" for package in "${packages_list[@]}"; do - busybox awk -v p="${package}" '$1~p{print $2}' "${system_packages_file}" >> "${uid_list}" + busybox awk -v p="${package}" '$1~p{print $2}' "${system_packages_file}" >> "${uid_list}" done } @@ -95,6 +95,9 @@ disable_ipv6() { sysctl -w net.ipv6.conf.all.disable_ipv6=1 sysctl -w net.ipv6.conf.default.disable_ipv6=1 sysctl -w net.ipv6.conf.wlan0.disable_ipv6=1 + # Enable IP(4) forwarding + sysctl -w net.ipv4.ip_forward=1 + sysctl -w net.ipv6.conf.all.forwarding=0 } >> /dev/null 2>&1 ipv6_enable() { @@ -103,6 +106,9 @@ ipv6_enable() { sysctl -w net.ipv6.conf.all.disable_ipv6=0 sysctl -w net.ipv6.conf.default.disable_ipv6=0 sysctl -w net.ipv6.conf.wlan0.disable_ipv6=0 + # Enable IP(6) forwarding + sysctl -w net.ipv4.ip_forward=1 + sysctl -w net.ipv6.conf.all.forwarding=1 } >> /dev/null 2>&1 intranet=( @@ -139,54 +145,6 @@ intranet6=( ff00::/8 ) -monitor_local_ip() { - [ "${iptables}" = "iptables -w 64" ] && ipv=4 || ipv=6 - if [ "${iptables}" = "iptables -w 64" ]; then - local_ips=($(ip a | busybox awk '$1~/inet$/{print $2}')) - else - local_ips=($(ip -6 a | busybox awk '$1~/inet6$/{print $2}')) - fi - local_ip_number=${#local_ips[@]} - rules_ips=($(${iptables} -t mangle -nvL FILTER_LOCAL_IP | grep "ACCEPT" | busybox awk '{print $9}')) - rules_number=$(${iptables} -t mangle -L FILTER_LOCAL_IP | grep "ACCEPT" | wc -l) - - if [ ${local_ip_number} -ne ${rules_number} ] ; then - for rules_subnet in "${rules_ips[@]}" ; do - wait_count=0 - a_subnet=$(busybox ipcalc -n ${rules_subnet} | busybox awk -F '=' '{print $2}') - for local_subnet in "${local_ips[@]}" ; do - b_subnet=$(busybox ipcalc -n ${local_subnet} | busybox awk -F '=' '{print $2}') - if [ "${a_subnet}" != "${b_subnet}" ] ; then - wait_count=$((wait_count + 1)) - if [ ${wait_count} -ge ${local_ip_number} ] ; then - ${iptables} -t mangle -D FILTER_LOCAL_IP -d ${rules_subnet} -j ACCEPT - fi - fi - done - done - - for subnets in "${local_ips[@]}" ; do - if ! (${iptables} -t mangle -C FILTER_LOCAL_IP -d ${subnets} -j ACCEPT > /dev/null 2>&1) ; then - ${iptables} -t mangle -I FILTER_LOCAL_IP -d ${subnets} -j ACCEPT - fi - done - log Debug "Filter Local IP($ipv) ${local_ips[*]}" - - unset a_subnet - unset b_subnet - log Debug "iptables rules for bypassing the local IP($ipv) have been updated." - else - log Debug "local IP($ipv) remains unchanged, and no processing has been performed." - return 1 - fi - - unset local_ips - unset local_ip_number - unset rules_ips - unset rules_number - unset wait_count -} - forward() { ${iptables} $1 FORWARD -o "${tun_device}" -j ACCEPT ${iptables} $1 FORWARD -i "${tun_device}" -j ACCEPT @@ -346,10 +304,10 @@ start_tproxy() { if [ "${iptables}" = "iptables -w 64" ]; then ip rule add fwmark "${fwmark}" table "${table}" pref "${pref}" ip route add local default dev lo table "${table}" + # ip -6 rule add unreachable pref "${pref}" else ip -6 rule add fwmark "${fwmark}" table "${table}" pref "${pref}" ip -6 route add local default dev lo table "${table}" - # ip -6 rule add unreachable pref "${pref}" fi # Create the BOX_EXTERNAL chain if it doesn't exist @@ -535,12 +493,6 @@ start_tproxy() { ${iptables} -A OUTPUT -d ::1 -p tcp -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -m tcp --dport "${tproxy_port}" -j REJECT fi - # # Add filter local IP - ${iptables} -t mangle -N FILTER_LOCAL_IP - ${iptables} -t mangle -A PREROUTING -j FILTER_LOCAL_IP - ${iptables} -t mangle -A OUTPUT -j FILTER_LOCAL_IP - monitor_local_ip - if [ "${iptables}" = "iptables -w 64" ]; then if [ "${bin_name}" = "clash" ]; then # Create and configure CLASH_DNS_EXTERNAL chain @@ -596,12 +548,6 @@ stop_tproxy() { ${iptables} -t mangle -F DIVERT ${iptables} -t mangle -X DIVERT - # flush filter local IP - ${iptables} -t mangle -D OUTPUT -j FILTER_LOCAL_IP - ${iptables} -t mangle -D PREROUTING -j FILTER_LOCAL_IP - ${iptables} -t mangle -F FILTER_LOCAL_IP - ${iptables} -t mangle -X FILTER_LOCAL_IP - # flush QUIC # ${iptables} -D OUTPUT -p udp -m multiport --dport 443,80 -j REJECT ${iptables} -D OUTPUT -p udp --dport 443 -j REJECT diff --git a/box/scripts/box.service b/box/scripts/box.service index 67909fc..1436ff7 100755 --- a/box/scripts/box.service +++ b/box/scripts/box.service @@ -12,7 +12,6 @@ box_check_logs() { for bin in "${bin_list[@]}"; do if [ -f "${box_run}/${bin}.log" ]; then mv "${box_run}/${bin}.log" "${box_run}/${bin}-$(date +%Y-%m-%d-%H-%M-%S).log" - # rm -f "${box_run}/${bin}.log" fi done # Delete other log files @@ -61,49 +60,51 @@ box_run_crontab() { fi } +box_ownership() { + # Set ownership and permission of kernel directory + chown ${box_user_group} ${bin_path} + chown -R ${box_user_group} ${box_dir} + chmod 6755 ${bin_path} + chmod -R 644 ${box_dir}/${bin_name} +} + box_permission() { + chmod 0700 ${box_dir}/bin/yq + chmod 0700 ${box_dir}/bin/curl if [[ "${box_user_group}" == @(root:net_admin|0:3005) && -f "${bin_path}" ]]; then # Set ownership and permission of kernel directory - chown ${box_user_group} ${bin_path} - chmod 6755 ${bin_path} - chmod 0644 "${box_dir}/${bin_name}"/* - chmod 0755 "${box_dir}/bin/yq" - # Set ownership of data directory - chown -R ${box_user_group} ${box_dir} - log Info "Use the kernel located in '${bin_path}'." + box_ownership + log Info "Using kernel in ${bin_path}." elif which ${bin_name} | grep -q "/system/bin/"; then mount -o remount,rw /system/bin/$bin_name - box_user=$(echo ${box_user_group} | busybox awk -F ':' '{print $1}') - box_group=$(echo ${box_user_group} | busybox awk -F ':' '{print $2}') - box_user_id=$(id -u ${box_user}) - box_group_id=$(id -g ${box_group}) + # Split box_user_group into user and group using IFS + IFS=':' read -r box_user box_group <<< "${box_user_group}" # Check if box_user and box_group exist - if ! [[ ${box_user_id} && ${box_group_id} ]]; then - log Error "${box_user_group} error, use root:net_admin instead." - box_user_group="root:net_admin" + if ! id -u "${box_user}" 2>/dev/null || ! id -g "${box_group}" 2>/dev/null; then + log Error "${box_user_group} error, use root:net_admin instead." + box_user_group="root:net_admin" fi bin_path=$(which ${bin_name}) # Set ownership and permission of kernel directory - chown ${box_user_group} ${bin_path} - chmod 6755 ${bin_path} - chmod 0644 "${box_dir}/${bin_name}"/* - chmod 0755 "${box_dir}/bin/yq" + box_ownership # Check if user is not root and group is not net_admin - if [[ "${box_user_id}" != "0" || "${box_group_id}" != "3005" ]]; then + if [[ ${box_user_id} -ne 0 || ${box_group_id} -ne 3005 ]]; then # Set capability of kernel directory - if ! setcap 'cap_net_admin,cap_net_raw,cap_net_bind_service+ep' "${bin_path}"; then - log Error "setcap authorization failed, you may need libcap package." + box_user_group="root:net_admin" + if ! setcap 'cap_net_admin,cap_net_raw,cap_net_bind_service+ep' "${bin_path}" 2>&1; then + log Warning "setcap 'cap_net_admin,cap_net_raw,cap_net_bind_service+ep' "${bin_path}" authorization failed." + bin_path="${box_dir}/bin/${bin_name}" + # Set ownership and permission of kernel directory + box_ownership fi fi - # Set ownership of data directory - box_user_group="root:net_admin" - log Info "Using kernel directory ${bin_name} in ${bin_path}" - chown -R ${box_user_group} ${box_dir} + mount -o remount,ro /system/bin/$bin_name + log Info "Using kernel in ${bin_path}." else sed -i "s/box_user_group=.*/box_user_group=\"root:net_admin\"/g" ${settings} log Error "Kernel <${bin_name}> is missing." log Error "Please download the <${bin_name}> kernel and place it in the ${bin_dir}/ directory." - log Debug "or executed: su -c /data/adb/box/scripts/box.tool upcore ." + log Debug "exec: su -c /data/adb/box/scripts/box.tool upcore" exit 1 fi } @@ -288,8 +289,8 @@ prepare_clash() { if [ "${proxy_mode}" != "tun" ]; then if [ -n "${packages_list[*]}" ] && [ "${clash_enhanced_mode}" = "fake-ip" ]; then - log Debug "${proxy_mode} only works in enhanced-mode: redir-host (clash.meta)" - log Debug "auto replace fake-ip > redir-host" + log Warning "${proxy_mode} only works in enhanced-mode: redir-host (clash.meta)" + log Warning "auto replace fake-ip > redir-host" sed -i "s/enhanced-mode:.*/enhanced-mode: redir-host/g" "${clash_config}" fi fi @@ -462,8 +463,12 @@ box_bin_status() { log Info "${bin_name} CPU usage: not available" fi + # Check battery temperature + temperature_celsius=$(($(cat /sys/class/power_supply/battery/temp) / 10)) + log Info "battery temperature: ${temperature_celsius}°C" + # Get the running time of the binary - running_time=$(ps -p $PID -o etime | busybox awk 'NR==2{print $1}' 2> /dev/null) + running_time=$(busybox ps -o comm,etime | grep ${bin_name} | busybox awk '{print $2}') if [ -n "${running_time}" ]; then log Info "${bin_name} running time: ${running_time}" else @@ -472,7 +477,7 @@ box_bin_status() { # Save the process ID to the pid file if [ -n "$PID" ]; then - sed -Ei 's/^description=(\[.*][[:space:]]*)?/description=[ ☑️ '${bin_name}' service is running ] /g' "$PROPFILE" + sed -Ei 's/^description=(\[.*][[:space:]]*)?/description=[ ♻️ '${bin_name}' service is running ] /g' "$PROPFILE" echo -n "$PID" > "${box_pid}" fi } @@ -491,11 +496,13 @@ start_box() { echo -e "${yellow}${box_version}${normal}" echo -e "${white}--------------------------------------------${normal}" else - echo "$(getprop persist.sys.timezone)" | tee -a "${box_log}" > /dev/null 2>&1 - echo "$(getprop gsm.sim.operator.alpha) / $(getprop gsm.network.type)" | tee -a "${box_log}" > /dev/null 2>&1 - echo "$(date)" | tee -a "${box_log}" > /dev/null 2>&1 - echo "${box_version}" | tee -a "${box_log}" > /dev/null 2>&1 - echo "--------------------------------------------" | tee -a "${box_log}" > /dev/null 2>&1 + { + echo "$(getprop persist.sys.timezone)" + echo "$(getprop gsm.sim.operator.alpha) / $(getprop gsm.network.type)" + echo "$(date)" + echo "${box_version}" + echo "--------------------------------------------" + } | tee -a "${box_log}" > /dev/null 2>&1 fi # Update iptables if bin_name is still running @@ -522,8 +529,13 @@ start_box() { # Checks if bin_name is defined case "${bin_name}" in - "xray" | "sing-box" | "clash" | "v2fly") log Info "Good day 🐱";; - *) log Error "bin_name: <..${bin_name}..> unknown not defined."; exit 1;; + xray|sing-box|clash|v2fly) + log Info "Good day 🐱" + ;; + *) + log Error "bin_name: <..${bin_name}..> unknown not defined." + exit 1 + ;; esac # Check permissions, check for bin existence, delete old logs, create a TUN if necessary, run box, and wait for 1 second @@ -534,11 +546,6 @@ start_box() { fi box_check_logs - # Enable IP forwarding - if ! sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1 || ! sysctl -w net.ipv6.conf.all.forwarding=1 >/dev/null 2>&1; then - log Debug "can't enable IP forwarding." - fi - # Execute the box_create_tun functions if [[ "${network_mode}" == "mixed" || "${proxy_mode}" == "tun" ]]; then box_create_tun @@ -591,7 +598,7 @@ stop_box() { log Warning "${bin_name} Not stopped; may still be shutting down or failed to shut down." force_stop fi - sed -Ei 's/^description=(\[.*][[:space:]]*)?/description=[ 🚫 '${bin_name}' service is stopped ] /g' "$PROPFILE" + sed -Ei 's/^description=(\[.*][[:space:]]*)?/description=[ ⛔ '${bin_name}' service is stopped ] /g' "$PROPFILE" } stop_cron() { diff --git a/docs/tubot.py b/docs/tubot.py new file mode 100644 index 0000000..ca4818e --- /dev/null +++ b/docs/tubot.py @@ -0,0 +1,101 @@ +import os +import sys +import asyncio +import telegram +from telegram import helpers + + +BOT_TOKEN = os.environ.get("BOT_TOKEN") +CHAT_ID = os.environ.get("CHAT_ID") +CACHE_CHAT_ID = os.environ.get("CACHE_CHAT_ID") +MESSAGE_THREAD_ID = os.environ.get("MESSAGE_THREAD_ID") +COMMIT_URL = os.environ.get("COMMIT_URL") +COMMIT_MESSAGE = os.environ.get("COMMIT_MESSAGE") +RUN_URL = os.environ.get("RUN_URL") +TITLE = os.environ.get("TITLE") +VERSION = os.environ.get("VERSION") +MSG_TEMPLATE = """ +*{title}* +\#cli\_{version} +``` +{commit_message} +``` +[Commit]({commit_url}) +[Workflow run]({run_url}) +""".strip() + + +def get_caption(): + msg = MSG_TEMPLATE.format( + title=helpers.escape_markdown(TITLE, 2), + version=helpers.escape_markdown(VERSION, 2), + commit_message=helpers.escape_markdown(COMMIT_MESSAGE, 2, telegram.MessageEntity.PRE), + commit_url=helpers.escape_markdown(COMMIT_URL, 2, telegram.MessageEntity.TEXT_LINK), + run_url=helpers.escape_markdown(RUN_URL, 2, telegram.MessageEntity.TEXT_LINK) + ) + if len(msg) > telegram.constants.MessageLimit.CAPTION_LENGTH: + return COMMIT_URL + return msg + + +def check_environ(): + if BOT_TOKEN is None: + print("[-] Invalid BOT_TOKEN") + exit(1) + if CHAT_ID is None: + print("[-] Invalid CHAT_ID") + exit(1) + if CACHE_CHAT_ID is None: + print("[-] Invalid CACHE_CHAT_ID") + exit(1) + if COMMIT_URL is None: + print("[-] Invalid COMMIT_URL") + exit(1) + if COMMIT_MESSAGE is None: + print("[-] Invalid COMMIT_MESSAGE") + exit(1) + if RUN_URL is None: + print("[-] Invalid RUN_URL") + exit(1) + if TITLE is None: + print("[-] Invalid TITLE") + exit(1) + if VERSION is None: + print("[-] Invalid VERSION") + exit(1) + + +async def main(): + print("[+] Uploading to telegram") + check_environ() + print("[+] Files:", sys.argv[1:]) + bot = telegram.Bot(BOT_TOKEN) + files = [] + paths = sys.argv[1:] + caption = get_caption() + print("[+] Caption: ") + print("---") + print(caption) + print("---") + for one in paths: + if not os.path.exists(one): + print("[-] File not exist: " + one) + continue + print("[+] Upload: " + one) + msg = await bot.send_document(CACHE_CHAT_ID, one, write_timeout=60, connect_timeout=30) + if one == paths[-1]: + files.append(telegram.InputMediaDocument(msg.document, + caption=caption, + parse_mode=telegram.constants.ParseMode.MARKDOWN_V2)) + else: + files.append(telegram.InputMediaDocument(msg.document)) + await bot.delete_message(CACHE_CHAT_ID, msg.message_id) + print("[+] Sending") + await bot.send_media_group(CHAT_ID, files, message_thread_id=MESSAGE_THREAD_ID) + print("[+] Done!") + + +if __name__ == "__main__": + loops = asyncio.new_event_loop() + loops.run_until_complete(asyncio.wait([main()])) +