【发布时间】: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的数据包。