如何通过Linux网关使用iptables转发端口

介绍

NAT,或网络地址转换,是为了重定向到另一个地址的数据包压延的总称。 通常,这用于允许流量超越网络边界。 实现NAT的主机通常可以访问两个或更多网络,并配置为在它们之间路由流量。

端口转发是转发针对特定端口的请求到另一台主机,网络或端口的过程。 由于该过程修改了分组在传输中的目的地,所以它被认为是一种NAT操作。

在本指南中,我们将演示如何使用iptables使用NAT技术端口转发到防火墙后面的主机。 如果您已配置了专用网络,但仍希望通过指定的网关计算机允许某些流量进入​​,则此功能非常有用。 我们将使用两个Ubuntu 14.04主机来演示这一点。

先决条件和目标

要遵循本指南,您将需要在启用了专用网络的同一数据中心中安装两个Ubuntu 14.04主机。 在每一个这样的机器,你需要建立一个非root用户帐户sudo权限。 你可以学习如何创建一个用户sudo按照我们的权限的Ubuntu 14.04服务器初始设置指南

第一个主机将用作我们的专用网络的防火墙和路由器。 为了演示的目的,第二台主机将配置一个只能使用其私有接口访问的Web服务器。 我们将配置防火墙机器将在其公共接口上接收的请求转发到Web服务器,它将在其私有接口上到达。

主机详细信息

在开始之前,我们需要了解我们的两个服务器使用的接口和地址。

查找网络详细信息

要获取自己的系统的详细信息,请先查找网络接口。 您可以通过键入以下内容在计算机上找到接口以及与之相关联的地址:

ip -4 addr show scope global
Sample Output2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 198.51.100.45/18 brd 45.55.191.255 scope global eth0
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.1.5/16 brd 10.132.255.255 scope global eth1
       valid_lft forever preferred_lft forever

上面的高亮输出显示两个接口( eth0eth1 )和(分配给每个地址192.51.100.45192.168.1.5分别)。 要找出这些接口中的哪个是您的公共接口,请键入:

ip route show | grep default
Outputdefault via 111.111.111.111 dev eth0

示出的接口( eth0在本实施例)将连接到默认网关的接口。 这几乎肯定是你的公共接口。

在每台计算机上查找这些值,并使用它们正确遵循本指南。

本指南的示例数据

为了更容易遵循,我们将在本教程中使用以下虚拟地址和接口分配。 请替换您自己的值,如下所示:

Web服务器网络详细信息:

  • 公网IP地址: 203.0.113.2
  • 专用IP地址: 192.0.2.2
  • 公共接口: eth0
  • 专用接口: eth1

防火墙网络详细信息:

  • 公网IP地址: 203.0.113.15
  • 专用IP地址: 192.0.2.15
  • 公共接口: eth0
  • 专用接口: eth1

设置Web服务器

我们将从我们的Web服务器主机开始。 与你的登录sudo用户开始。

安装Nginx

我们将完成第一道工序是安装Nginx我们的Web服务器主机上,并且锁定下来,以便它只听其专用接口。 这将确保我们的Web服务器只有在我们正确设置端口转发时才可用。

通过更新本地包缓存,并使用开始apt下载和安装软件:

sudo apt-get update
sudo apt-get install nginx

限制Nginx到专用网络

安装Nginx后,我们将打开默认的服务器块配置文件,以确保它只侦听私有接口。 现在打开文件:

sudo nano /etc/nginx/sites-enabled/default

在内部,发现listen指令。 你应该在配置的顶部连续两次找到它:

/ etc / nginx / sites-enabled / default
server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    . . .
}

在第一次listen指令,添加Web服务器的私有IP地址和一个冒号仅领先的80告诉Nginx的只在专用接口上聆听。 我们只在本指南中演示IPv4转发,因此我们可以删除为IPv6配置的第二个listen指令。

在我们的示例中,我们修改listen指令看起来像这样:

/ etc / nginx / sites-enabled / default
server {
    listen 192.0.2.2:80 default_server;

    . . .
}

保存并在完成后关闭文件。 键入以下内容来测试文件是否有语法错误:

sudo nginx -t

如果未显示任何错误,请重新启动Nginx以启用新配置:

sudo service nginx restart

验证网络限制

在这一点上,验证我们对Web服务器的访问权限非常有用。

从我们的防火墙服务器,如果我们试图从私营接口访问我们的网站服务器,它应该工作:

curl --connect-timeout 5 192.0.2.2
Output<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
. . .

如果我们尝试使用公共接口,我们将看到我们无法连接:

curl --connect-timeout 5 203.0.113.2
curl: (7) Failed to connect to 203.0.113.2 port 80: Connection refused

这正是我们期望发生的。

配置防火墙转发端口80

现在,我们可以在防火墙机器上实现端口转发。

在内核中启用转发

我们需要做的第一件事是在内核级别启用流量转发。 默认情况下,大多数系统已关闭转发。

要仅为此会话打开端口转发,请键入:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

要打开端口转发永久,你将不得不修改/etc/sysctl.conf文件。 打开该文件sudo通过键入权限:

sudo nano /etc/sysctl.conf

在里面,找到并取消注释看起来像这样的行:

/etc/sysctl.conf
net.ipv4.ip_forward=1

保存并在完成后关闭文件。 您可以通过键入以下内容在此文件中应用设置:

sudo sysctl -p
sudo sysctl --system

设置基本防火墙

我们将使用防火墙本指南作为本教程中的规则的基本框架。 现在在防火墙机器上运行指南,以便设置。 完成后,您将有:

  • 安装iptables-persistent
  • 保存设置成默认规则/etc/iptables/rules.v4
  • 学习了如何添加或编辑规则文件或使用调整规则iptables命令

当您设置基本防火墙后,请继续下面,以便我们可以调整它的端口转发。

添加转发规则

我们要配置我们的防火墙,以便流入我们的公共接口(交通eth0端口80)转发给我们的私有接口( eth1 )。

我们的基本防火墙有一个我们的FORWARD链设置为DROP默认的流量。 我们需要添加允许我们将连接转发到我们的Web服务器的规则。 为了安全起见,我们将相当紧密地锁定它,以便只允许转发的连接。

FORWARD链中,我们将接受发往端口80的新的连接,是根据我们的公共接口到来,前往我们的专用接口。 新连接由所识别的conntrack延伸和将具体通过一个TCP SYN分组来表示:

sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT

这将让第一个数据包,意味着建立一个连接,通过防火墙。 我们还需要允许来自该连接的两个方向的任何后续流量。 要允许ESTABLISHEDRLEATED我们的公共和私有接口之间的流量,请键入:

iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

我们可以仔细检查,我们对政策FORWARD链设为DROP通过键入:

sudo iptables -P FORWARD DROP

在这一点上,我们已经允许我们的公共和私人接口之间的某些流量通过我们的防火墙继续。 但是,我们还没有配置实际上将告诉规则iptables如何翻译和指挥交通。

正确添加NAT规则到数据包

接下来,我们将添加将告诉规则iptables如何路由流量。 我们需要按顺序执行两个独立的操作对iptables正确改变数据包,使客户端可以与Web服务器通信。

第一次运行,被称为DNAT ,将发生在PREROUTING的链nat表。 DNAT是为了使其能够为它在网络之间传递正确路由改变一个数据包的目的地址的操作。 公共网络上的客户端将连接到我们的防火墙服务器,并且不知道我们的专用网络拓扑。 我们需要改变每个数据包的目的地址,以便当它在我们的专用网络上发送时,它知道如何正确到达我们的网络服务器。

因为我们只配置端口转发,而不是在每个到达我们的防火墙的数据包上执行NAT,我们将要匹配我们规则上的端口80。 我们将与瞄准80端口到我们的服务器的私有IP地址(包192.0.2.2在我们的例子):

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.0.2.2

这照顾了一半的图片。 数据包应该正确路由到我们的Web服务器。 然而,现在,分组仍将具有客户端的原始地址作为源地址。 服务器将尝试直接向该地址发送回复,这将无法建立合法的TCP连接。

注意
在DigitalOcean上,离开具有不同源地址的Droplet的数据包实际上将被虚拟机管理程序丢弃,因此,在这个阶段,您的数据包将永远不会到达Web服务器(我们将通过实现SNAT来解决这个问题)。 这是一种反欺骗措施,用于防止攻击,其中通过伪造请求中的源地址来请求将大量数据发送到受害者的计算机。 要了解更多信息,查看该在我们的社区反应

要配置正确的路由,我们还需要修改数据包的源地址,使其在到达Web服务器的路由中离开防火墙。 我们需要修改源地址到我们的防火墙服务器的私有IP地址( 192.0.2.15在我们的例子)。 然后,该答复将被发送回防火墙,然后防火墙可以将其按预期转发回客户端。

要启用此功能,我们将添加一个规则到POSTROUTING的连锁nat表,数据包在网络上发送权利之前被评估。 我们将通过IP地址和端口匹配发往我们的Web服务器的数据包:

sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 192.0.2.2 -j SNAT --to-source 192.0.2.15

一旦这个规则到位,我们的网络服务器应该可以通过指向我们的网络浏览器在我们的防火墙机器的公共地址:

curl 203.0.113.15
Output<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
. . .

我们的端口转发设置完成。

调整永久规则集

现在我们已经设置了端口转发,我们可以将其保存到我们的永久规则集。

如果你不在乎失去的是在当前的规则集中的意见,只需要使用iptables-persistent服务,以节省您的规则:

sudo service iptables-persistent save

如果您想在文件中保留评论,请打开它并手动编辑:

sudo nano /etc/iptables/rules.v4

您将需要调整的配置filter表的FORWARD添加的链规则。 您还需要调整其配置部分nat表,以便您可以添加您PREROUTINGPOSTROUTING规则。 对于我们的例子,它看起来像这样:

/etc/iptables/rules.v4
*filter
# Allow all outgoing, but drop incoming and forwarding packets by default
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Custom per-protocol chains
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]

# Acceptable UDP traffic

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT

# Acceptable ICMP traffic

# Boilerplate acceptance policy
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT

# Drop invalid packets
-A INPUT -m conntrack --ctstate INVALID -j DROP

# Pass traffic to protocol-specific chains
## Only allow new connections (established and related should already be handled)
## For TCP, additionally only allow new SYN packets since that is the only valid
## method for establishing a new TCP connection
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP

# Reject anything that's fallen through to this point
## Try to be protocol-specific w/ rejection message
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable

# Rules to forward port 80 to our web server

# Web server network details:

# * Public IP Address: 203.0.113.2
# * Private IP Address: 192.0.2.2
# * Public Interface: eth0
# * Private Interface: eth1
# 
# Firewall network details:
# 
# * Public IP Address: 203.0.113.15
# * Private IP Address: 192.0.2.15
# * Public Interface: eth0
# * Private Interface: eth1
-A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
-A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# End of Forward filtering rules

# Commit the changes

COMMIT

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Rules to translate requests for port 80 of the public interface
# so that we can forward correctly to the web server using the
# private interface.

# Web server network details:

# * Public IP Address: 203.0.113.2
# * Private IP Address: 192.0.2.2
# * Public Interface: eth0
# * Private Interface: eth1
# 
# Firewall network details:
# 
# * Public IP Address: 203.0.113.15
# * Private IP Address: 192.0.2.15
# * Public Interface: eth0
# * Private Interface: eth1
-A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.0.2.2
-A POSTROUTING -d 192.0.2.2 -o eth1 -p tcp --dport 80 -j SNAT --to-source 192.0.2.15
# End of NAT translations for web server traffic
COMMIT

*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

添加上述内容后,保存并关闭文件,并调整值以反映您自己的网络环境。

通过键入测试规则文件的语法:

sudo iptables-restore -t < /etc/iptables/rules.v4

如果未检测到错误,请加载规则集:

sudo service iptables-persistent reload

测试您的Web服务器是否仍然可以通过防火墙的公共IP地址访问:

curl 203.0.113.15

这应该像以前一样工作。

结论

现在,你应该熟悉Linux服务器上转发端口iptables 该过程包括允许在内核级转发,设置访问以允许在防火墙系统上的两个接口之间转发特定端口的流量,以及配置NAT规则以使得分组可以被正确路由。 这似乎是一个笨拙的过程,但它也体现了灵活性netfilter包过滤框架和iptables防火墙。 这可用于伪装您的专用网络拓扑,同时允许服务流量通过您的网关防火墙机器自由流动。

赞(52) 打赏
未经允许不得转载:优客志 » 系统运维
分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏