在当今互联网环境中,安全性和隐私保护成为了我们越来越关注的问题。尤其是我们需要突破网络封锁、使用国际互联网服务时,机场免于搭建、地区多、上手即使用,已经成了大部分有科学需求的用户首选。使用机场也有一些限制,比如机场可能存在审计、记录日志、IP被滥用等行为,易使得我们的隐私泄露。要想完全控制自己上网的流量,需要我们搭建自己的代理服务。
由于墙的强大,自建代理服务器容易受到封锁处理,往往代理运行一番后就被墙发现,从而封锁服务器IP或端口。遇到这种只能更换IP处理,每年也需花费一定的费用。如果使用机场,那么IP被封锁的事情你就无需考虑了,有机场主处理。比如我前期测试了一下Shadowsocks ,几分钟后我的服务器IP便不再能PING通,好在我这是准备做前置代理的,所以被GFW封锁也无所谓,另外GFW可能会主动探测你的这台服务器。VPS服务器暴露在互联网上,这使得它们容易成为网络攻击的目标,如DDoS攻击、暴力破解等。
前置代理机场节点,指的是通过机场的节点连接自有VPS服务器。自有VPS服务器将网络流量从机场节点中转,从而突破国内网络限制,访问国际互联网服务。通过使用这种方式,用户可以访问被屏蔽的外部网站或服务,同时增强自己的匿名性和安全性。由于加密的存在,机场也无法知道你访问了哪些网站服务等。考虑到隐私、安全、服务稳定性,前置代理机场节点成为了一种常见的解决方案。
我们可以通过配置防火墙,有效过滤掉来自不可信IP的访问请求,减少潜在的安全威胁。防火墙能够阻止未经授权的流量进入或离开网络,确保只有符合条件的数据能够通过代理节点,我们可以通过NFTSET解决。现在机场都是中转机场,用户访问的是国内的机场代理服务器,机场国内服务器通过隧道等协议穿墙到国外的落地服务器,有的机场还有IEPL等专线过墙,从而保证了稳定性及低延时。但也给我们前置代理带来了不便。
由于一般机场都禁止一号多地登录,也不支持从外国使用机场服务,为了杜绝被机场禁用,这里通过2个脚本路由器和VPS配合,自动获取机场所有节点的落地IP上传到自有的VPS服务器,VPS服务器自动执行脚本完成防火墙设置。路由器是OPENWRT软路由,VPS服务器是bebian12系统。2台设备均安装有sing-box。软路由上使用的是Homeproxy软件管理sing-box,服务器上代理服务是sing-box是官方版本一键安装的,本站均有介绍。
这2个脚本在我的机场及服务器均运行通过。自用机场,瓦工GIA服务器 见链接。该机场是中转机场,只有shadowsocks和trojan两种协议,因此脚本里只能处理这2种协议。路由器上安装了Homeproxy代理软件。一般来说大部分机场节点的落地IP是不怎么变动的,脚本每天检测1次机场落地IP情况;碰到重大节日,机场落地IP变化频繁,可修改计划任务增加检测次数。30个节点,检测一次需耗时3min左右。
软路由获取机场落地IP脚本
自动通过sing-box来获取中转机场落地IP。通过socks5也不影响路由器HOMEPROXY的代理服务。脚本主要做了这几个任务:
筛选延迟最低的节点并发送到HOMEPROXY日志,方便设置节点信息;
脚本自动设置计划任务,每天可以自动获取机场落地IP及本地公网IP并上传至服务器VPS。
#!/bin/sh # 订阅地址,改为自己的 SUBSCRIPTION_URL="https://..." # 远程主机,改为自己的vps服务器及ssh端口号 REMOTEHOST="1.2.3.4" REMOTEPORT="22" # 公共 IP 服务,自己到ipinfo.io申请 IPINFOTOKEN="12345678" # IP 服务的 API Token IP_SERVICE="https://ipinfo.io/ip?token=$IPINFOTOKEN" # 获取 IP 的服务 URL # 临时文件和日志设置,一下无需修改 SCRIPT_PATH=$(readlink -f "$0") BASE_DIR="/usr/share/airport" LOG_FILE="/var/log/singbox_blockcn.log" CONFIG_DIR=/tmp/singbox # 用于存储临时配置文件的目录 TEMP_FILE=$(mktemp) # 临时文件路径 DECODED_FILE=$(mktemp) # 用于存储解码后的内容的临时文件 LANDING_FILE="$BASE_DIR/landing_ip.txt" # 存储代理落地 IP 的文件 # 创建日志和数据目录 mkdir -p "$BASE_DIR" mkdir -p "$CONFIG_DIR" mkdir -p "$(dirname "$LOG_FILE")" # 清理临时文件和进程 trap "rm -f $TEMP_FILE $DECODED_FILE; rm -rf $CONFIG_DIR" EXIT rm -rf $LANDING_FILE # 检查依赖项 for cmd in curl base64 sing-box; do if ! command -v $cmd >/dev/null 2>&1; then echo "需要安装 $cmd" | tee -a "$LOG_FILE" >&2 exit 1 fi done # 检查订阅地址 if [[ -z $SUBSCRIPTION_URL ]]; then echo "订阅地址为空!请检查配置。" | tee -a "$LOG_FILE" >&2 exit 1 fi # 下载订阅信息 if ! curl -s "$SUBSCRIPTION_URL" -o "$TEMP_FILE"; then echo "订阅地址下载失败!" | tee -a "$LOG_FILE" >&2 exit 1 fi # 检查文件是否为空 if [[ ! -s $TEMP_FILE ]]; then echo "订阅文件内容为空!" | tee -a "$LOG_FILE" >&2 exit 1 fi # Base64 解码 if ! base64 -d "$TEMP_FILE" > "$DECODED_FILE" 2>> "$LOG_FILE"; then echo "Base64 解码失败!" | tee -a "$LOG_FILE" >&2 exit 1 fi # 解析解码后的内容并生成配置 cat "$DECODED_FILE" | while read -r LINE; do if [[ $LINE == ss://* || $LINE == trojan://* ]]; then # 获取类型 TYPE=$(echo $LINE | cut -d':' -f1) # 提取 Base64 部分 BASE64_PART=$(echo $LINE | sed 's/^ss:\/\///' | sed 's/^trojan:\/\///' | cut -d'#' -f1) # Base64 解码 DECODED=$(echo $BASE64_PART | base64 -d 2>/dev/null) if [[ -z $DECODED ]]; then echo "Base64 解码失败: $LINE" | tee -a $LOG_FILE >&2 continue fi # 提取加密协议、密码 PROTOCOL=$(echo $DECODED | cut -d':' -f1) # 提取加密密码 if [[ $TYPE == "ss" ]]; then PASSWORD=$(echo $DECODED | cut -d':' -f2 | cut -d'@' -f1) elif [[ $TYPE == "trojan" ]]; then PASSWORD=$(echo "$LINE" | sed -n 's/^trojan:\/\/\([^@]*\)@.*/\1/p') fi # 提取服务器和端口 SERVER=$(echo $LINE | sed 's/^ss:\/\/.*@//g' | sed 's/^trojan:\/\/.*@//g' | cut -d':' -f1) PORT=$(echo "$LINE" | sed -E 's/.*@[^:]+:([0-9]+).*/\1/') # 提取备注并解码为中文 REMARK=$(echo "$LINE" | awk -F'#' '{print $2}' | sed 's/+/ /g; s/%/\\x/g' | xargs -0 printf "%b" | tr -d '\r') # 设置机场节点配置文件 CONFIG_FILE_NAME="$CONFIG_DIR/$(echo -n "$REMARK" | sha256sum | cut -c 1-8).json" # 根据节点类型生成配置文件 if [[ $TYPE == "ss" ]]; then cat <<-EOF > "$CONFIG_FILE_NAME" { "log": { "level": "error" }, "outbounds": [ { "type": "shadowsocks", "tag": "ss-out", "server": "$SERVER", "server_port": $PORT, "password": "$PASSWORD", "method": "$PROTOCOL" } ], "inbounds": [ { "type": "socks", "tag": "socks-in", "listen": "::", "listen_port": 2025 } ] } EOF elif [[ $TYPE == "trojan" ]]; then cat <<-EOF > "$CONFIG_FILE_NAME" { "log": { "level": "error" }, "outbounds": [ { "type": "trojan", "tag": "trojan-out", "server": "$SERVER", "server_port": $PORT, "password": "$PASSWORD", "tls": { "enabled": true, "server_name": "$(echo "$LINE" | sed -n 's/^.*sni=\([^&#]\+\).*/\1/p')", "insecure": $(echo $LINE | grep -o 'allowInsecure=\([0-9]\+\)' | cut -d'(' -f2 | awk '{print ($1 == 1) ? "true" : "false"}' || echo "false") } } ], "inbounds": [ { "type": "socks", "tag": "socks-in", "listen": "::", "listen_port": 2025 } ] } EOF fi # 启动 sing-box 并测试代理 sing-box run -c "$CONFIG_FILE_NAME" & SING_BOX_PID=$! # 等待代理启动 sleep 5 # 分开检测 # LANDING_IP=$(curl -s --socks5 127.0.0.1:2025 $IP_SERVICE) # LATENCY=$(curl -s -o /dev/null -w "%{time_total}\n" --socks5 127.0.0.1:2025 https://wwww.google.com) # 获取落地 IP及延时 result=$(curl -s --socks5 127.0.0.1:2025 -w " TIME: %{time_total}" $IP_SERVICE) # 提取访问者 IP 和延时 LANDING_IP=$(echo "$result" | awk '{print $1}') # 提取第一部分(IP) LATENCY=$(echo "$result" | awk -F'TIME: ' '{print $2}') # 提取 "TIME:" 后的延时值 if echo "$LANDING_IP" | grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$|^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'; then echo "# ${REMARK},HTTPS真延时为${LATENCY}s" >> "$LANDING_FILE" echo "$LANDING_IP" >> "$LANDING_FILE" echo "${REMARK}的落地IP是${LANDING_IP},HTTPS真延时为${LATENCY}s" else echo "无法通过代理获取落地 IP: $SERVER" | tee -a $LOG_FILE >&2 fi # 停止 sing-box kill $SING_BOX_PID wait $SING_BOX_PID 2>/dev/null fi done # 获取本机IP,注意ipip.net不能被代理,可直接在浏览器里打开查看 LOCALIP=$(curl -s http://myip.ipip.net/ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+') echo "# 国内本地公网IPv4,无需获取延时" >> "$LANDING_FILE" echo "$LOCALIP" >> "$LANDING_FILE" # 设置定时任务 CRON_JOB="48 7 * * * /bin/sh $SCRIPT_PATH" if ! crontab -l 2>/dev/null | grep -q "$SCRIPT_PATH"; then (crontab -l 2>/dev/null; echo "$CRON_JOB") | crontab - fi # openwrt的密钥和openssh的不兼容,需要在服务器上安装apt install dropbear , # 然后dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear_rsa_host_key转换, # 转换后文件放入openwrt中,密钥需要设为600权限 if ! grep -q "$REMOTEHOST" "/root/.ssh/known_hosts"; then # 如果没有找到该主机的指纹,输出提示信息 echo "第一次运行需要手工确认信任主机" fi scp -q -p -i /etc/ssl/private/vps_dropbear_private_key -P $REMOTEPORT $LANDING_FILE root@$REMOTEHOST:/usr/local && echo "文件已上传" || echo "文件上传失败" echo "脚本执行成功" | tee -a $LOG_FILE >&2
注意点:一些说明在脚本中已经说明,请仔细查看。上传至服务器使用的是scp协议,ssh登录是使用的证书登录,本脚本也是通过证书登录的方法上传至服务器。服务器证书是openssh生成的,OPENWRT的scp命令只认可dropbear生成的公钥,所以需要转换服务器证书为dropbear格式的。需要在服务器上安装dropbear后转换openssh的证书。需要密码登录自行查找相关命令。
# 在vps服务器上执行 apt install dropbear dropbearconvert openssh dropbear /path/to/ssh_host_rsa_key /path/to/dropbear_rsa_host_key
转换路径需自己确定好。
Homeproxy日志显示
VPS服务器设置防火墙脚本
该脚本主要处理了:
禁止VPS服务器访问国内的网络,需要在sing-box配置文件outbounds段内加入 “routing_mark”: 100
定时更新IP相关数据
提供机场节点变化情况到日志。
#!/bin/bash # 设置 PATH 环境变量 export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin # 变量定义 SCRIPT_PATH=$(realpath "$0") URLCN="https://fastly.jsdelivr.net/gh/gaoyifan/china-operator-ip@ip-lists/china.txt" URLCN6="https://raw.githubusercontent.com/1715173329/IPCIDR-CHINA/refs/heads/master/ipv6.txt" # 自定义singbox服务端端口,根据自己的修改 SS_PORT=1234 #自定义ss端口 SOCKS_PORT=4321 #自定义socks端口 REALITY_PORT=443 #自定义reality端口 # 以下无需修改 ALLOWED_IPS="allowed_ips" BLOCKCN_IPS="blockcn_ips" BLOCKCN6_IPS="blockcn6_ips" NFTTABLES_NAME="proxy" BASE_DIR="/usr/share/singbox" AIRPORTLANDING_IPS="/usr/local/landing_ip.txt" # 检查是否安装了相关软件 for cmd in nft curl base64 sing-box; do if ! command -v $cmd >/dev/null 2>&1; then echo "需要安装 $cmd" exit 1 fi done # 检查是否存在相关文件 function existfile { if [ ! -f $1 ]; then echo "$1 文件不存在,请检查!" exit 1 fi } existfile "/etc/nftables.conf" existfile "$AIRPORTLANDING_IPS" # 创建nft规则保存文件夹 mkdir -p "$BASE_DIR" function echolog() { local d="$(date "+%Y-%m-%d %H:%M:%S")" echo -e "$d $*" >> ${BASE_DIR}/frontpoxy_airport.log } function downloadfile { echo "正在下载中国IP $1" if ! curl -s "$1" -o $2; then echo "下载中国IP地址列表失败,继续使用现有的IP地址列表..." # 如果没有旧文件,退出 if [ ! -f $2 ]; then echo "未找到中国现有的IP地址列表,无法继续。" echolog "IP下载失败" exit 1 fi else echo "中国IP地址列表已成功下载并保存至$2。" fi } downloadfile "$URLCN" "/tmp/cn_ips.txt" downloadfile "$URLCN6" "/tmp/cn6_ips.txt" # 设置 IP 集合 function setipset { IPSET_NAME=$1 IPSET_TXTDIR=$2 # 判断 $IPSET_NAME 是否包含字符 "6" if echo "$IPSET_NAME" | grep -q "6"; then ADDRESS_TYPE="ipv6_addr" else ADDRESS_TYPE="ipv4_addr" fi # 检查集合是否存在 if nft list set inet $NFTTABLES_NAME "$IPSET_NAME" >/dev/null 2>&1; then nft flush set inet $NFTTABLES_NAME "$IPSET_NAME" else nft add set inet $NFTTABLES_NAME "$IPSET_NAME" { type $ADDRESS_TYPE\; flags interval\; auto-merge\; } fi # 删除注释含、空行、制表符、最后的空格 clean_output=$(sed 's/#.*$//; /^$/d; s/[ \t]*$//' "$IPSET_TXTDIR") # 处理后的结果 elements=$(echo "$clean_output" | tr '\n' ',' | sed 's/,$//') # 添加元素到集合,换行符变为逗号,且删除最后的逗号 if [[ -z $elements ]]; then echo "IP 地址列表为空,无法添加到集合中。" | tee -a "$LOG_FILE" >&2 exit 1 fi nft add element inet $NFTTABLES_NAME "$IPSET_NAME" { $elements } } # 加入自定义nftables表 if ! nft list tables | grep -q "^table .* $NFTTABLES_NAME$"; then echo "建立新NFT防火墙 ${NFTTABLES_NAME}表" nft flush table inet $NFTTABLES_NAME 2>/dev/null nft add table inet $NFTTABLES_NAME nft add chain inet $NFTTABLES_NAME singboxinput { type filter hook input priority -199 \; policy accept \; } nft add chain inet $NFTTABLES_NAME singboxforward { type filter hook forward priority -199 \; policy accept \; } nft add chain inet $NFTTABLES_NAME singboxoutput { type filter hook output priority -199 \; policy accept \; } setipset "$ALLOWED_IPS" "$AIRPORTLANDING_IPS" setipset "$BLOCKCN_IPS" "/tmp/cn_ips.txt" setipset "$BLOCKCN6_IPS" "/tmp/cn6_ips.txt" nft add chain inet $NFTTABLES_NAME singbox_proxy_allowed nft add rule inet $NFTTABLES_NAME singbox_proxy_allowed ip saddr @$ALLOWED_IPS meta l4proto tcp counter accept nft add rule inet $NFTTABLES_NAME singbox_proxy_allowed ip saddr @$ALLOWED_IPS meta l4proto udp counter accept nft add rule inet $NFTTABLES_NAME singbox_proxy_allowed meta l4proto tcp counter ct state new drop nft add rule inet $NFTTABLES_NAME singbox_proxy_allowed meta l4proto udp counter ct state new drop nft add rule inet $NFTTABLES_NAME singboxinput meta l4proto { tcp, udp } th dport $SS_PORT goto singbox_proxy_allowed nft add rule inet $NFTTABLES_NAME singboxinput meta l4proto { tcp, udp } th dport $SOCKS_PORT goto singbox_proxy_allowed nft add rule inet $NFTTABLES_NAME singboxinput meta l4proto { tcp, udp } th dport $REALITY_PORT goto singbox_proxy_allowed nft add rule inet $NFTTABLES_NAME singboxoutput ip daddr @$BLOCKCN_IPS meta mark 100 counter drop comment \"singbox中标记100目标中国拒绝\" nft add rule inet $NFTTABLES_NAME singboxoutput ip6 daddr @$BLOCKCN6_IPS meta mark 100 counter drop comment \"singbox中标记100目标中国拒绝\" echo "include \"${BASE_DIR}/singbox.nft\"" >> "/etc/nftables.conf" else echo "NFTABLES ${NFTTABLES_NAME}表已存在" fi # 刷新集合 setipset "$ALLOWED_IPS" "$AIRPORTLANDING_IPS" setipset "$BLOCKCN_IPS" "/tmp/cn_ips.txt" setipset "$BLOCKCN6_IPS" "/tmp/cn6_ips.txt" echo "NFT集合机场IP、中国IP刷新成功" #检查是否存在nftables配置文件,防止其他操作被删除 if ! grep -q "singbox.nft" "/etc/nftables.conf"; then echo "include \"${BASE_DIR}/singbox.nft\"" >> "/etc/nftables.conf" fi # 保存 nftables 规则 nft list table inet $NFTTABLES_NAME > "${BASE_DIR}/singbox.nft" # 检测IP变化 BACKUP_FILE="${BASE_DIR}/airport_ips.txt" # 创建备份 if [ ! -f "$BACKUP_FILE" ]; then cp "$AIRPORTLANDING_IPS" "$BACKUP_FILE" echo "首次运行,已创建备份文件:$BACKUP_FILE" fi # 对比当前文件和备份文件 while IFS= read -r current_line; do if echo "$current_line" | grep -qE '^# '; then # 如果是标注行,提取名称部分(假设名称部分在 `# ` 后以 `,` 结束) label=$(echo "$current_line" | awk -F',' '{print $1}' | sed 's/^# //') elif [ -n "$label" ]; then # 如果是 IP 行,检查是否发生变化 old_ip=$(grep -F "$label" "$BACKUP_FILE" -A 1 | tail -n 1) if [ "$current_line" != "$old_ip" ]; then echolog "$label 的IP发生了变化,原IP为 $old_ip,现在为 $current_line" fi fi done < $AIRPORTLANDING_IPS # 更新备份文件 cp $AIRPORTLANDING_IPS "$BACKUP_FILE" # 配置定时任务,确保日8:00下载并更新 IP 地址列表 CRON_SCHEDULE="0 8 * * *" CRON_JOB="$CRON_SCHEDULE $SCRIPT_PATH" # 检查是否已存在相同的 cron 任务 if crontab -l 2>/dev/null | grep -q "$SCRIPT_PATH"; then echo "定时任务已存在,跳过设置。" else (crontab -l 2>/dev/null; echo "$CRON_JOB") | crontab - echo "已成功设置每天定时任务,自动更新 IP 地址列表并更新规则。" fi echolog "SING-BOX防火墙设置完成" echo "SING-BOX防火墙设置完成"
本自定义防火墙优先级别较高,防火墙规则可以根据自己的实际情况修改。
机场IP发生变动
防火墙概况
我们还可以做端口重定向处理。比如VPS的reality服务运行在4433端口,可以通过防火墙,将允许的机场ip集合的443端口流量重定向至4433端口,从而让443端口保持https服务,这样你客户端虽然还是通过443端口代理,但服务器实际服务的是4433端口,其他IP访问443端口就是返回网站服务内容,从而迷惑GFW。由于我这里主要是通过机场过墙,没有做这样的处理。
首先开启端口转发
nano /etc/sysctl.conf
最下方加入
net.ipv4.ip_forward=1 net.ipv6.conf.all.forwarding=1
保存后,执行命令让其生效
sysctl -p
刚才VPS脚本里删除原有关于reality的规则,然后加入如下内容:
nft add chain inet $NFTTABLES_NAME singboxprerouting { type nat hook prerouting priority -199 \; policy accept \; } nft add rule inet "$NFTTABLES_NAME" singboxprerouting ip saddr @"$ALLOWED_IPS" tcp dport 443 counter nft add rule inet "$NFTTABLES_NAME" singboxprerouting ip saddr @"$ALLOWED_IPS" udp dport 443 counter nft add rule inet "$NFTTABLES_NAME" singboxprerouting ip saddr @"$ALLOWED_IPS" tcp dport 443 redirect to :$REALITY_PORT nft add rule inet "$NFTTABLES_NAME" singboxprerouting ip saddr @"$ALLOWED_IPS" udp dport 443 redirect to :$REALITY_PORT
这样,端口转发就处理好了。
最后:提供2个sh脚本的下载,可以根据自己的实际情况来修改使用。点我下载 。
技术不断升级,请注意文章时效性。
本站文章,欢迎转发。转载请注明出处:https://www.bandwh.com/net/2219.html