本文介绍了Linux系统端口转发的原理和操作,包括如何使用iptables配置基础防火墙规则、添加/删除端口转发规则,以及通过forward_port脚本便捷管理转发条目。
端口转发原理
端口转发(Port Forwarding), 也称为端口映射(Port Mapping),是一种网络技术,它允许将网络流量从一个 IP 地址和端口重定向到另一个 IP 地址和端口。 在 Linux 系统中, 我们通常使用 iptables
工具来实现端口转发。
基础防火墙规则配置
在开始配置端口转发之前,我们需要先配置一些基础的防火墙规则,包括开启 IP 转发、允许转发流量和配置 NAT 表。
command1 2 3
| echo 1 > /proc/sys/net/ipv4/ip_forward iptables -A FORWARD -j ACCEPT iptables -t nat -A POSTROUTING -j MASQUERADE
|
解释:
echo 1 > /proc/sys/net/ipv4/ip_forward
: 开启 IP 转发功能,允许 Linux 系统作为路由器转发数据包。
iptables -A FORWARD -j ACCEPT
: 允许所有转发流量通过防火墙,即允许从一个网卡转发到另一个网卡的数据包。
iptables -t nat -A POSTROUTING -j MASQUERADE
: 配置网络地址转换(NAT), 将转发的数据包的源 IP 地址转换为本机 IP 地址,以便目标机器能够正常响应。
添加端口转发规则
以下示例展示了如何将本地端口 80 的流量转发到 192.168.2.123
的 80 端口。
command1 2
| iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.2.123:80 iptables -t nat -A POSTROUTING -p tcp -d 192.168.2.123 --dport 80 -j MASQUERADE
|
解释:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.2.123:80
:
-t nat
: 指定操作的表为 NAT 表,用于网络地址转换。
-A PREROUTING
: 将规则添加到 PREROUTING
链,该链用于处理进入本机的数据包。
-p tcp
: 指定协议为 TCP。
--dport 80
: 指定目标端口为 80。
-j DNAT
: 执行目标地址转换(DNAT)。
--to-destination 192.168.2.123:80
: 将目标地址转换为 192.168.2.123:80
。
iptables -t nat -A POSTROUTING -p tcp -d 192.168.2.123 --dport 80 -j MASQUERADE
:
-t nat
: 指定操作的表为 NAT 表。
-A POSTROUTING
: 将规则添加到 POSTROUTING
链,该链用于处理即将离开本机的数据包。
-p tcp
: 指定协议为 TCP。
-d 192.168.2.123
: 指定目标 IP 地址为 192.168.2.123
。
--dport 80
: 指定目标端口为80.
-j MASQUERADE
: 执行地址伪装,将源 IP 地址转换为本机 IP 地址。
删除端口转发规则
以下示例展示了如何删除将本地端口 80 的流量转发到 192.168.2.123
的 80 端口的规则。
command1 2
| iptables -t nat -D PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.2.123:80 iptables -t nat -D POSTROUTING -p tcp -d 192.168.2.123 --dport 80 -j MASQUERADE
|
解释:
- 与添加规则类似,只是将
-A
改为 -D
,表示删除规则。
查看转发规则
使用以下命令可以查看当前配置的端口转发规则:
command
解释:
-t nat
: 指定查看 NAT 表。
-L
: 列出规则。
-n
: 使用数字格式显示 IP 地址和端口,而不是使用主机名和服务名。
端口转发管理脚本
为了方便管理端口转发规则,我们提供了一个 forward_port
脚本。 该脚本可以帮助您更方便地添加、删除和查看转发规则。
使用方法
以下是一些脚本的使用示例:
command1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| root@localhost:~# forward_port list 当前端口转发规则列表: ---------------------------------------- [TCP] 本地端口: 8000 转发目标: 192.168.2.142:8000 root@localhost:~# forward_port add tcp 8001 100.88.88.104 8000 添加完成 root@localhost:~# forward_port list 当前端口转发规则列表: ---------------------------------------- [TCP] 本地端口: 8000 转发目标: 192.168.2.142:8000 [TCP] 本地端口: 8001 转发目标: 100.88.88.104:8000 root@localhost:~# forward_port del tcp 8001 删除完成 root@localhost:~# forward_port list 当前端口转发规则列表: ---------------------------------------- [TCP] 本地端口: 8000 转发目标: 192.168.2.142:8000
|
脚本代码
以下是 forward_port
脚本的完整代码:
/usr/local/bin/forward_port1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| #!/bin/bash
if [ "$EUID" -ne 0 ]; then echo "请使用 sudo 运行此脚本" exit 1 fi
show_help() { echo "用法:" echo " $0 list # 显示所有端口转发规则" echo " $0 add tcp|udp 本地端口 目标IP 目标端口 # 添加转发规则" echo " $0 del tcp|udp 本地端口 # 删除转发规则" echo "" echo "示例:" echo " $0 add tcp 8080 192.168.1.100 80" echo " $0 del tcp 8080" }
list_forwards() { rules=$(iptables -t nat -L PREROUTING -n --line-numbers | grep "dpt:" | grep "to:")
if [ -z "$rules" ]; then echo "当前没有端口转发规则" return fi
echo "当前端口转发规则列表:" echo "----------------------------------------"
while IFS= read -r line; do protocol=$(echo "$line" | grep -o 'tcp\|udp' | tr '[:lower:]' '[:upper:]') local_port=$(echo "$line" | grep -o 'dpt:[0-9]*' | cut -d':' -f2) target=$(echo "$line" | grep -o 'to:[0-9.]*:[0-9]*' | cut -d':' -f2,3)
if [ ! -z "$protocol" ] && [ ! -z "$local_port" ] && [ ! -z "$target" ]; then target_ip=$(echo "$target" | cut -d':' -f1) target_port=$(echo "$target" | cut -d':' -f2) echo "[$protocol] 本地端口: $local_port 转发目标: $target_ip:$target_port" fi done <<< "$rules" }
check_forward_exists() { local proto=$1 local port=$2
iptables -t nat -L PREROUTING -n | grep "dpt:$port" | grep -q "$proto" return $? }
add_forward() { local proto=$1 local local_port=$2 local target_ip=$3 local target_port=$4
if [[ ! "$proto" =~ ^(tcp|udp)$ ]]; then echo "错误: 协议必须是 tcp 或 udp" return 1 fi
if [[ ! "$local_port" =~ ^[0-9]+$ ]] || [ "$local_port" -lt 1 ] || [ "$local_port" -gt 65535 ]; then echo "错误: 无效的端口号 $local_port" return 1 fi
if [[ ! "$target_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "错误: 无效的 IP 地址 $target_ip" return 1 fi
if [[ ! "$target_port" =~ ^[0-9]+$ ]] || [ "$target_port" -lt 1 ] || [ "$target_port" -gt 65535 ]; then echo "错误: 无效的目标端口号 $target_port" return 1 fi
if check_forward_exists "$proto" "$local_port"; then echo "${proto^^} $local_port 已经有转发规则了" return 1 fi
iptables -t nat -A PREROUTING -p "$proto" --dport "$local_port" -j DNAT --to-destination "$target_ip:$target_port" iptables -t nat -A POSTROUTING -p "$proto" -d "$target_ip" --dport "$target_port" -j MASQUERADE
if [ $? -eq 0 ]; then echo "添加完成" else echo "添加失败" return 1 fi }
del_forward() { local proto=$1 local port=$2
if [[ ! "$proto" =~ ^(tcp|udp)$ ]]; then echo "错误: 协议必须是 tcp 或 udp" return 1 fi
if [[ ! "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then echo "错误: 无效的端口号 $port" return 1 fi
if ! check_forward_exists "$proto" "$port"; then echo "未找到 ${proto^^} 端口 $port 的转发规则" return 1 fi
target_info=$(iptables -t nat -L PREROUTING -n | grep "dpt:$port" | grep "$proto") target_ip=$(echo "$target_info" | grep -o 'to:[0-9.]*:[0-9]*' | cut -d':' -f2) target_port=$(echo "$target_info" | grep -o 'to:[0-9.]*:[0-9]*' | cut -d':' -f3)
iptables -t nat -D PREROUTING -p "$proto" --dport "$port" -j DNAT --to-destination "$target_ip:$target_port" 2>/dev/null iptables -t nat -D POSTROUTING -p "$proto" -d "$target_ip" --dport "$target_port" -j MASQUERADE 2>/dev/null
if [ $? -eq 0 ]; then echo "删除完成" else echo "删除失败" return 1 fi }
case "$1" in list) list_forwards ;; add) if [ $# -ne 5 ]; then echo "错误: add 命令需要4个参数" show_help exit 1 fi add_forward "$2" "$3" "$4" "$5" ;; del) if [ $# -ne 3 ]; then echo "错误: del 命令需要2个参数" show_help exit 1 fi del_forward "$2" "$3" ;; *) show_help exit 1 ;; esac
exit 0
|
脚本使用说明:
forward_port list
: 列出当前所有端口转发规则。
forward_port add tcp|udp 本地端口 目标IP 目标端口
: 添加新的端口转发规则。
tcp|udp
: 指定协议。
本地端口
: 要监听的本地端口。
目标IP
: 要转发的目标 IP 地址。
目标端口
: 要转发的目标端口。
forward_port del tcp|udp 本地端口
: 删除指定的端口转发规则。
tcp|udp
: 指定协议。
本地端口
: 要删除的转发规则对应的本地端口。
总结
本文档介绍了如何在 Linux 系统中配置端口转发,包括手动配置 iptables
规则以及使用提供的 forward_port
脚本进行管理。希望这些内容能够帮助您更好地理解和使用 Linux 的端口转发功能。