Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 无法接收超时消息_Go_Icmp - Fatal编程技术网

Go 无法接收超时消息

Go 无法接收超时消息,go,icmp,Go,Icmp,我正在做一些测试,基于这样的想法,它引入了一种无需第三方的NAT穿越方法:服务器将ICMP回送请求包发送到固定地址(例如,3.3.3),在该地址,客户端不会返回回送回复,假装是Internet上的一个跃点,向服务器发送ICMP超时数据包,希望服务器前面的NAT将ICMP超时消息转发给服务器。 在我ping到3.3.3.3之后,我在192.168.1.100中运行下面的代码,以侦听Go中的ICMP消息: package main import ( "fmt" "golang.or

我正在做一些测试,基于这样的想法,它引入了一种无需第三方的NAT穿越方法:服务器将ICMP回送请求包发送到固定地址(例如,
3.3.3
),在该地址,客户端不会返回回送回复,假装是Internet上的一个跃点,向服务器发送ICMP超时数据包,希望服务器前面的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)
    }
}
主程序包
进口(
“错误”
“fmt”
“golang.org/x/net/icmp”
“golang.org/x/net/ipv4”
“净额”
“操作系统”
)
func sendTtle(主机字符串)错误{
conn,err:=net.Dial(“ip4:icmp”,主机)
如果错误!=零{
返回错误
}
//原始IP报头
h:=ipv4.Header{
版本:4,
Len:20,
总数:20+8,
TTL:64,
议定书:1,
}
h、 Src=net.ParseIP(主机)
h、 Dst=净解析IP(“3.3.3.3”)
iph,err:=h.Marshal()
如果错误!=零{
fmt.Println(“ip头错误”,错误)
返回错误
}
//8字节的原始数据报数据
echo:=icmp.Message{
类型:ipv4.ICMPTypeEcho,代码:0,
正文:&icmp.Echo{
编号:3456,序号:1,
}}
oriReq,err:=echo.Marshal(无)
如果错误!=零{
返回错误。新建(“封送错误”)
}
数据:=附加(iph、oriReq…)
te:=icmp.Message{
类型:已超出ipv4.ICMPTypeTimeExtered,
代码:0,
正文:&icmp.timeextended{
数据:数据,
}}
如果buf,err:=te.Marshal(nil);err==nil{
fmt.Println(“已发送”)
如果3;,错误:=conn.Write(buf);错误!=nil{
返回错误。新建(“写入错误”)
}
}否则{
返回错误。新建(“封送错误”)
}
归零
}
func main(){
argc:=len(os.Args)
如果argc<2{
fmt.Println(“用法:prpgram+主机”)
返回
}
如果err:=sendTtle(os.Args[1]);err!=nil{
fmt.Println(“未能发送超出TTL的消息:”,错误)
}
}

问题是
192.168.1.100
无法接收消息。可能的原因是什么?

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

  • 首先,您没有获取由发送的回显请求的标识符
    192.168.2.100
    3.3.3
    ,标识符将是唯一的 通过NAPT(如果有)映射到外部查询ID,以便它可以路由 未来的ICMP回显将使用相同的查询ID答复发件人。根据,

    在NAPT设置中,如果ICMP中嵌入的IP消息恰好是 对于TCP、UDP或ICMP查询数据包,您还需要修改 TCP/UDP标头或查询中的适当TU端口号 ICMP查询头中的标识符字段

  • 第二,根据rfc 5508:

    如果NAT设备从私有领域接收到ICMP错误数据包, 并且NAT没有嵌入式有效负载的活动映射, NAT应该静默地丢弃ICMP错误数据包


所以伪造的超过时间的信息无法通过。是关于这方面的更多细节。

否,我将
Dst
设置为
3.3.3
,目的是假装超时消息是由
192.168.2.100
发送到
3.3.3
的回显请求引起的。确定。你的代码对我有用。服务器打印“超出ttl”。您确定192.168.1.100和192.168.2.100的计算机之间存在连接吗?这些机器听起来可能在不同的子网上,所以请确保您可以在它们之间进行路由,并且没有防火墙把事情搞糟。尝试在客户端和服务器上使用tcpdump进行调试,您将看到数据包是否出现,并且看起来应该出现。感谢您的回复。这两个子网之间有连接。路由器似乎丢弃了wireshark的数据包。