当前位置: 首页 > 知识库问答 >
问题:

macos - mac pfctl 可以实现 dnat 吗?

韩麒
2024-12-23

我 iptables 有这样一个命令。

sudo iptables -t nat -A OUTPUT -d 172.13.0.99 -p tcp --dport 8080 -j DNAT --to-destination 公网ip:80

这样当我请求 172.13.0.99 8080 端口的,时候就会将请求转发到 公网ip 对应的 80 端口上去。实际上这个 ip 172.13.0.99 是不存在的。
然后我找了很多资料,在 mac 下要用 pfctl。都是 rdr 实现。

rdr pass inet proto tcp from any to any port 8080 -> 公网ip port 80

这样实现后,访问本地 ip 或者 172.13.0.99 的 8080 都无法访问到 公网ip 对应的 80 端口。但是到将 公网ip 改成本机 ip,这条规则又是生效的。

在 v2ex 看到有人说 pfctl 只能 nat 本机。

想问问有类似经历的朋友吗,分享给我一下。

结论

经过几位大佬(还有 sf 社区外的)帮助和多次测试,最终得到结论是:pf 无法 nat 到非本机 IP 上。因此上面的 iptables 规则无法直接转化成 pf rdr 来使用。

最终使用了 Seven 大佬的建议。在本地将 lo 网卡的 ip 做别名,加一个 tcp 反向代理,通过别名 ip 来访问反向代理,间接实现了类似 iptables 所表达的功能。

感谢 @水蒸气、@Seven 两位大佬对我的帮助。

共有3个答案

小牛23036
2024-12-23

可参考这篇文章
macOS 下做 DNAT
在 Mac 上没有 iptables,但你可以使用 Mac 自带的 pf(Packet Filter)来实现类似的端口转发功能。以下是具体步骤:

1.启用 IP 转发:
启用后注意这里如果只能本机可以看我下面的补充

sudo sysctl -w net.inet.ip.forwarding=1

2.创建 PF 配置文件: 创建一个新的 PF 配置文件,例如 /etc/pf.anchors/http,内容如下:

rdr pass on lo0 inet proto tcp from any to 172.13.0.99 port 8080 -> 公网ip port 80

3.修改主 PF 配置文件: 编辑 /etc/pf.conf 文件,添加以下内容:

rdr-anchor "http-forwarding"
load anchor "http-forwarding" from "/etc/pf.anchors/http"

4.验证配置: 使用以下命令验证配置文件是否正确:

sudo pfctl -vnf /etc/pf.anchors/http

5.启用 PF 服务: 启用 PF 服务并加载配置:

sudo pfctl -ef /etc/pf.conf

这样,当你在本地访问 172.13.0.99:8080 时,流量会被重定向到指定的公网 IP 的 80 端口。

补充

  1. pf 的 NAT 限制:
  2. pf 只能对本机 IP 进行 NAT 转发
  3. 不能像 iptables 那样对任意目标 IP (比如不存在的 172.13.0.99) 进行 DNAT
  4. iptables vs pf 的主要区别:

    # iptables 可以这样做
    sudo iptables -t nat -A OUTPUT -d 172.13.0.99 -p tcp --dport 8080 -j DNAT --to-destination 公网ip:80
    
    # pf 只能对本机 IP 做转发
    rdr pass on lo0 inet proto tcp from any to 172.13.0.99 port 8080 -> 公网ip port 80

可以将上面步骤1.启用 IP 转发: 这一步之后为网络接口配置别名: 你可以将 172.13.0.99 配置为本地网络接口的别名。这样,pf 会将其视为本地地址,从而允许重定向。以下是具体步骤:

sudo ifconfig lo0 alias 172.13.0.99
拓拔嘉运
2024-12-23

DNAT用于将目的地址重定向到另一个IP地址,就像Linux的iptables -t nat -A PREROUTING。你的规则不生效,可能是因为系统不允许IP转发:

sudo sysctl -w net.inet.ip.forwarding=1 # 启用IP转发

添加DNAT规则:
/etc/pf.anchors/目录下创建web文件,输入这些内容:

rdr pass on 网络接口 inet proto tcp from any to 172.13.0.99 port 8080 -> 公网ip port 80

将其中的汉字换成你需要的接口和IP。并且在/etc/pf.conf中添加对anchor的引用:

rdr-anchor "web"
load anchor "web" from "/etc/pf.anchors/web"

加载配置并启用PF:

sudo pfctl -f /etc/pf.conf
sudo pfctl -e
水飞掣
2024-12-23
**是的,`pfctl` 在 macOS 上可以通过 `rdr` 规则实现类似 `iptables` 的 DNAT 功能,但有一些限制和需要注意的地方。**

在 macOS 上,`pfctl` 使用 `rdr` 规则来实现目的地址转换(DNAT)。然而,`pfctl` 的 `rdr` 规则默认情况下只适用于目标地址为本地接口地址或广播地址的数据包。这意味着,如果你尝试将流量重定向到非本地 IP 地址(如你例子中的 `172.13.0.99`),它不会按预期工作,除非这个 IP 地址被配置为本地接口的一部分(例如,通过别名接口)。

为了解决这个问题,你可以尝试以下方法:

1. **配置别名接口**:
   你可以为网络接口配置一个别名,将 `172.13.0.99` 分配给这个别名。然后,你可以使用 `rdr` 规则将流量从这个别名接口重定向到公网 IP。

2. **使用 `lo0`(回环接口)**:
   如果 `172.13.0.99` 只是一个内部使用的 IP 地址,并不需要在网络上实际存在,你可以考虑将它添加到 `lo0` 接口(回环接口)。这样,所有发往 `172.13.0.99` 的流量都会通过 `lo0`,然后你可以使用 `rdr` 规则将其重定向到公网 IP。

3. **调整 `rdr` 规则**:
   确保你的 `rdr` 规则正确无误,并且适用于你的网络配置。例如:

rdr pass inet proto tcp from any to any port 8080 -> 公网ip port 80


这条规则本身看起来是正确的,但它可能不会生效,因为 `172.13.0.99` 不是本地接口的一部分。如果你已经将其添加到某个接口,确保该接口是活动的,并且规则中的 "from any to any" 部分是符合你需求的(这可能允许所有来源的流量被重定向,这可能不是你想要的,具体取决于你的安全需求)。

4. **检查防火墙日志**:
使用 `pfctl -s all` 或查看系统日志来检查是否有任何相关的防火墙日志条目,这可能会提供为什么规则没有按预期工作的线索。

5. **考虑使用其他工具**:
如果 `pfctl` 的限制太多,或者你需要更复杂的网络流量管理功能,你可能需要考虑使用其他工具,如 `nftables`(在 Linux 上更常见,但可以通过一些努力在 macOS 上运行)或商业防火墙解决方案。

总之,`pfctl` 在 macOS 上确实可以实现 DNAT 功能,但有一些限制和配置要求。你可能需要调整你的网络配置或规则以满足你的需求。
 类似资料:
  • 我需要在macOS上运行旧版本的JDK 7。 我看过“如何在Mac OSX上使用JDK 7?”在“JavaVirtualMachine”中:如何在Mac OSX上使用JDK 7? 还查看了:“OpenJDK”:https://openjdk.java.net/ 知道在哪里可以找到macOS的JDK 7吗?

  • 在OOP中,抽象是当我们只向用户提供有用的细节,并隐藏所有实现细节时。那么,如果我有一个接口,并且我在一个类中实现它,那么这是如何实现抽象的呢?我读了这篇关于“如何使用接口实现100%的抽象”的文章 如果这个问题听起来离题或者含糊不清,那么它真的是,我想知道的是oop中的抽象是如何与接口相关的。

  • 我计划开发一个基于web的聊天应用程序,它接收ReSTful请求,将它们转换为XMPP,并将它们发送到XMPP服务器。 在这种基于聊天的应用程序中使用WebSocket看起来很有希望,因为事件(或响应)可以异步传递。但是,如果我使用WebSocket作为从浏览器传输请求的底层协议,这仍然可以被视为ReSTful设计吗?如果是的话,URI、动词(GET、POST…)是怎样的,websocket消息中

  • 问题内容: 我有一个包含5000多个数据记录的网格。这些数据每天都在增长。当我用网格加载页面时,网格显示数据几乎要花一分钟,我必须一次显示10行。 然后可以使用此jqGrid实现延迟加载吗? 这是我生成JSon字符串的操作: 这是带有jqGrid的页面: 请参阅下面的查询: 我在上述操作中设置的限制金额。该值为10。 问题答案: 好的,所以这是一个基于JPA的部分答案(但是我想让它适应Hibern

  • 老师们五一假期快乐 有没有老师做过类似的业务

  • 我的文件夹大小为。 删除所有内容安全吗?这些文件会自动重新生成吗?

  • 问题内容: 这与java中的最终接口有关。在讨论中,有一个关于接口的最终概念是模棱两可的。最终接口是否意味着它不能具有子接口?这是否意味着它无法实现? 这个问题是第一个问题:您是否可以编写一个最终接口,以便编译器阻止您实现它? 问题答案: 正如我将展示的,可以使用代理来实现上面的接口。更有意义的问题是,为什么要尝试创建无法实现的界面?即使从哲学角度来说,它似乎也很肤浅。 这不会在编译或运行时产生错