【问题标题】: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的数据包。

标签: go icmp


【解决方案1】:

您的代码没有问题。如果您在同一个网络中运行代码(我的意思是不涉及 NAT/路由器),程序将按预期收到超时消息。原因是 pwnat 使用的理论现在已经行不通了。

  • 首先,您没有得到由 192.168.2.1003.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 对此有更多详细信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 2016-03-27
    相关资源
    最近更新 更多