Linux 本地端口转发到其他机器(附带管理脚本)

本文介绍了Linux系统端口转发的原理和操作,包括如何使用iptables配置基础防火墙规则、添加/删除端口转发规则,以及通过forward_port脚本便捷管理转发条目。

端口转发原理

端口转发(Port Forwarding), 也称为端口映射(Port Mapping),是一种网络技术,它允许将网络流量从一个 IP 地址和端口重定向到另一个 IP 地址和端口。 在 Linux 系统中, 我们通常使用 iptables 工具来实现端口转发。


基础防火墙规则配置

在开始配置端口转发之前,我们需要先配置一些基础的防火墙规则,包括开启 IP 转发、允许转发流量和配置 NAT 表。

command
1
2
3
echo 1 > /proc/sys/net/ipv4/ip_forward           # 开启 IP 转发
iptables -A FORWARD -j ACCEPT # 允许转发
iptables -t nat -A POSTROUTING -j MASQUERADE # 配置 NAT 表

解释:

  • 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 端口。

command
1
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 端口的规则。

command
1
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
1
iptables -t nat -L -n

解释:

  • -t nat: 指定查看 NAT 表。
  • -L: 列出规则。
  • -n: 使用数字格式显示 IP 地址和端口,而不是使用主机名和服务名。

端口转发管理脚本

为了方便管理端口转发规则,我们提供了一个 forward_port 脚本。 该脚本可以帮助您更方便地添加、删除和查看转发规则。


使用方法

以下是一些脚本的使用示例:

command
1
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_port
1
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

# 检查是否具有 root 权限
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() {
# 获取 PREROUTING 规则
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

# 获取目标地址信息用于删除 POSTROUTING 规则
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 的端口转发功能。

作者

默吟

发布于

2025-01-12

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×