dsstjqsr631426 2017-02-08 14:36
浏览 236
已采纳

无法收到超过时间的消息

I'm doing some tests based on the idea of pwnat, it introduced a method for NAT traversal without 3rd party: the server sends ICMP echo request packets to the fixed address(for example, 3.3.3.3) where no echo replies won't be returned from, the client, pretending to be a hop on the Internet, sends an ICMP Time Exceeded packet to the server, expect the NAT in the front of the server to forward the ICMP time exceeded message to the server.
After I pinged to 3.3.3.3, then I run the code below in 192.168.1.100 to listen ICMP messages in Go:

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
", 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
")
            }
        default:
        }
    }
}

and a program which runs in 192.168.2.100 to send forged time exceeded message to 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)
    }
}

the problem is 192.168.1.100 cannot receive the message. What're the possible reasons?

  • 写回答

1条回答 默认 最新

  • douciping4283 2017-02-08 15:38
    关注

    Your code has no problem. If you run your code in the same network(I mean no NAT/router involvement), the program will receive time exceeded message as expected. The reason is the theory pwnat uses doesn't work nowadays.

    • First, you didn't get the identifier of the echo request sent by 192.168.2.100 to 3.3.3.3, the identifier will be uniquely mapped to an external query ID by NAPT(if any) so that it can route future ICMP Echo Replies with the same query ID to the sender. According to rfc 3022 ICMP error packet modifications section,

      In a NAPT setup, if the IP message embedded within ICMP happens to be a TCP, UDP or ICMP Query packet, you will also need to modify the appropriate TU port number within the TCP/UDP header or the Query Identifier field in the ICMP Query header.

    • Second, according to rfc 5508:

      If a NAT device receives an ICMP Error packet from the private realm, and the NAT does not have an active mapping for the embedded payload, the NAT SHOULD silently drop the ICMP Error packet.

    So the forged time exceeded message wouldn't get through. Here is more details about this.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器