无法接收超时消息
Posted
技术标签:
【中文标题】无法接收超时消息【英文标题】:cannot receive time exceeded message 【发布时间】:2017-06-26 05:45:52 【问题描述】:我正在根据pwnat的思想做一些测试,它介绍了一种无第三方NAT穿越的方法:服务器将ICMP echo请求包发送到固定地址(例如3.3.3.3
),其中没有echo回复不会返回,客户端伪装成互联网上的一跳,向服务端发送ICMP Time Exceeded报文,期望服务端的NAT转发ICMP超时报文给服务端.
在我 ping 到 3.3.3.3
之后,我在 192.168.1.100
中运行以下代码以在 Go 中侦听 ICMP 消息:
package main
import (
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
func main()
c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil
fmt.Println("listen error", err)
rb := make([]byte, 1500)
for
n, _, err := c.ReadFrom(rb)
if err != nil
fmt.Printf("read err: %s\n", err)
reply, err := icmp.ParseMessage(1, rb[:n])
if err != nil
fmt.Println("parse icmp err:", err)
return
switch reply.Type
case ipv4.ICMPTypeTimeExceeded:
if _, ok := reply.Body.(*icmp.TimeExceeded); ok
// internet header(20 bytes) plus the first 64 bits of the original datagram's data
//fmt.Println("recv id ", binary.BigEndian.Uint16(timeExceed.Data[22:24]))
fmt.Printf("ttl exceeded\n")
default:
还有一个在192.168.2.100
中运行的程序,用于向192.168.1.100
发送伪造的超时消息:
package main
import (
"errors"
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"net"
"os"
)
func sendTtle(host string) error
conn, err := net.Dial("ip4:icmp", host)
if err != nil
return err
// original IP header
h := ipv4.Header
Version: 4,
Len: 20,
TotalLen: 20 + 8,
TTL: 64,
Protocol: 1,
h.Src = net.ParseIP(host)
h.Dst = net.ParseIP("3.3.3.3")
iph, err := h.Marshal()
if err != nil
fmt.Println("ip header error", err)
return err
// 8 bytes of original datagram's data
echo := icmp.Message
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo
ID: 3456, Seq: 1,
oriReq, err := echo.Marshal(nil)
if err != nil
return errors.New("Marshal error")
data := append(iph, oriReq...)
te := icmp.Message
Type: ipv4.ICMPTypeTimeExceeded,
Code: 0,
Body: &icmp.TimeExceeded
Data: data,
if buf, err := te.Marshal(nil); err == nil
fmt.Println("sent")
if _, err := conn.Write(buf); err != nil
return errors.New("write error")
else
return errors.New("Marshal error")
return nil
func main()
argc := len(os.Args)
if argc < 2
fmt.Println("usage: prpgram + host")
return
if err := sendTtle(os.Args[1]); err != nil
fmt.Println("failed to send TTL exceeded message: ", err)
问题是192.168.1.100
收不到消息。可能的原因是什么?
【问题讨论】:
不,我将Dst
设置为3.3.3.3
是为了假装超时消息是由192.168.2.100
发送到3.3.3.3
的回显请求引起的。
好的。你的代码对我有用。服务器打印“ttl 超出”。你确定你的机器在 192.168.1.100 和 192.168.2.100 之间有连接吗?这些机器听起来好像它们可能位于不同的子网中,因此请确保您可以在它们之间进行路由,并且没有防火墙将事情搞砸。尝试在客户端和服务器上使用 tcpdump 进行调试,您将看到数据包是否出现,并且看起来应该出现。
感谢您的回复。两个子网之间存在连接。路由器似乎丢弃了来自wireshark的数据包。
【参考方案1】:
您的代码没有问题。如果您在同一个网络中运行代码(我的意思是不涉及 NAT/路由器),程序将按预期收到超时消息。原因是 pwnat 使用的理论现在已经行不通了。
首先,您没有得到由
192.168.2.100
到 3.3.3.3
,标识符将是唯一的
通过 NAPT(如果有)映射到外部查询 ID,以便它可以路由
未来的 ICMP Echo 以相同的查询 ID 回复发送者。根据rfc 3022 ICMP error packet modifications section,
在 NAPT 设置中,如果嵌入在 ICMP 中的 IP 消息恰好是 TCP、UDP 或 ICMP 查询数据包,您还需要修改 TCP/UDP 标头或查询中的适当 TU 端口号 ICMP 查询标头中的标识符字段。
其次,根据 rfc 5508:
如果 NAT 设备从私有领域收到 ICMP 错误数据包, 并且 NAT 没有嵌入有效负载的活动映射, NAT 应该静默丢弃 ICMP 错误数据包。
所以伪造的超时消息不会通过。 Here 对此有更多详细信息。
【讨论】:
以上是关于无法接收超时消息的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有超时/死锁的情况下在PROMELA进程中发送和接收?
从渲染器接收消息超时:0.100 条日志消息使用 ChromeDriver 和 Chrome v80 通过 Selenium Java