Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/net/icmp: icmp ReadFrom cannot read any data on the Android and Linux system #59084

Closed
windyboyy opened this issue Mar 17, 2023 · 4 comments
Closed
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Milestone

Comments

@windyboyy
Copy link

windyboyy commented Mar 17, 2023

The design plan is to package the features implemented in Go language using gomobile, and then implement cross-platform functionality through Flutter plugin, which will eventually be integrated into a Flutter app. Currently, we are implementing a trace feature that obtains the IP of each hop by setting different TTL values. However, we have found that while this works on iOS and Darwin, ReadFrom cannot read any data on the Android system.

import (
	"bytes"
	"fmt"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
	"net"
	"strings"
	"time"
)

func SendIPv4ICMP1(ttl int) error {
	conn, err := icmp.ListenPacket("udp4", "")
	if err != nil {
		return err
	}
	ipaddr, err := net.ResolveIPAddr("ip4", "8.8.8.8")
	if err != nil {
		return err
	}
	addr := &net.UDPAddr{
		IP:   ipaddr.IP,
		Zone: ipaddr.Zone,
	}
	data := make([]byte, packageSize)
	data = append(data, bytes.Repeat([]byte{1}, packageSize)...)
	body := &icmp.Echo{
		ID:   1,
		Seq:  1,
		Data: data,
	}
	msg := &icmp.Message{
		Type: ipv4.ICMPTypeEcho,
		Code: 0,
		Body: body,
	}
	msgBytes, err := msg.Marshal(nil)
	if err != nil {
		return err
	}
	err = conn.IPv4PacketConn().SetControlMessage(ipv4.FlagTTL, true)
	if err != nil {
		return fmt.Errorf("SetControlMessage(),%s", err)
	}
	fmt.Println(fmt.Sprintf("TTL:%d", ttl))
	if err = conn.IPv4PacketConn().SetTTL(ttl); err != nil {
		return fmt.Errorf("conn.IPv4PacketConn().SetTTL()失败,%s", err)
	}
	_, err = conn.WriteTo(msgBytes, addr)
	if err != nil {
		return fmt.Errorf("conn.WriteTo()失败,%s", err)
	}

	for {
		// 包+头
		buf := make([]byte, 1500)
		if err := conn.SetReadDeadline(time.Now().Add(time.Millisecond * 1500)); err != nil {
			return err
		}
		n, src, err := conn.ReadFrom(buf)
		if n > 0 {
			fmt.Println(n)
			fmt.Println(src.String())
		}
		if err != nil {
			if neterr, ok := err.(*net.OpError); ok {
				if neterr.Timeout() {
					fmt.Println("read超时了")
					continue
				}
			}
			return err
		}
		// 结果如8.8.8.8:0
		respAddr := src.String()
		splitSrc := strings.Split(respAddr, ":")
		if len(splitSrc) == 2 {
			respAddr = splitSrc[0]
		}
		x, err := icmp.ParseMessage(protocolICMP, buf)
		if err != nil {
			return fmt.Errorf("error parsing icmp message: %w", err)
		}
		// 超时
		if x.Type == ipv4.ICMPTypeTimeExceeded || x.Type == ipv6.ICMPTypeTimeExceeded {
			switch pkt := x.Body.(type) {
			case *icmp.TimeExceeded:
				// 设置ttl后,一定会返回这个超时内容,头部长度是20,因此从20之后开始解析
				m, err := icmp.ParseMessage(protocolICMP, pkt.Data[20:])
				if err != nil {
					return err
				}
				switch p := m.Body.(type) {
				case *icmp.Echo:
                                          fmt.Println(p.ID)
                                          fmt.Println(respAddr)
				default:
					return fmt.Errorf("invalid ICMP time exceeded and echo reply; type: '%T', '%v'", pkt, pkt)
				}
			default:
				return fmt.Errorf("invalid ICMP time exceeded; type: '%T', '%v'", pkt, pkt)
			}

		}
		// 收到echo reply,证明到达目的ip
		if x.Type == ipv4.ICMPTypeEchoReply || x.Type == ipv6.ICMPTypeEchoReply {
			// echo reply的时候,返回的包不可能比发的包小
			if n < packageSize {
				continue
			}
			switch pkt := x.Body.(type) {
			// 只有到达目的ip,是echo
			case *icmp.Echo:
                                  fmt.Println(respAddr)
			
			default:
				return fmt.Errorf("invalid ICMP echo reply; type: '%T', '%v'", pkt, pkt)
			}
		}
	}
	return nil
}
@windyboyy windyboyy changed the title icmp ReadFrom cannot read any data on the Android system /x/net/icmp:icmp ReadFrom cannot read any data on the Android system Mar 17, 2023
@windyboyy windyboyy changed the title /x/net/icmp:icmp ReadFrom cannot read any data on the Android system x/net/icmp:icmp ReadFrom cannot read any data on the Android system Mar 17, 2023
@gopherbot gopherbot added this to the Unreleased milestone Mar 17, 2023
@windyboyy windyboyy changed the title x/net/icmp:icmp ReadFrom cannot read any data on the Android system x/net/icmp:icmp ReadFrom cannot read any data on the Android and Linux system Mar 17, 2023
@cherrymui cherrymui changed the title x/net/icmp:icmp ReadFrom cannot read any data on the Android and Linux system x/net/icmp: icmp ReadFrom cannot read any data on the Android and Linux system Mar 17, 2023
@cherrymui
Copy link
Member

Could you explain which function does not do what you expected? Is it https://pkg.go.dev/golang.org/x/net/icmp#PacketConn.ReadFrom ? What do you expect to see, and what did you see instead? Thanks.

@cherrymui cherrymui added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Mar 17, 2023
@windyboyy
Copy link
Author

windyboyy commented Mar 20, 2023

你能解释一下哪个功能没有达到你的预期吗?是https://pkg.go.dev/golang.org/x/net/icmp#PacketConn.ReadFrom吗?你期望看到什么,而你看到了什么?谢谢。

Yes,it is https://pkg.go.dev/golang.org/x/net/icmp#PacketConn.ReadFrom.
I use the method IPv4PacketConn().SetTTL(ttl) to incrementally set the TTL value in order to obtain information about each hop in a traceroute. However, when the TTL value is very small, the PacketConn.ReadFrom method does not receive any response. Only when the TTL value is sufficiently large, a response is received. I hope that when the TTL value is small, PacketConn.ReadFrom can return to me a "time exceeded" message along with the response body.
"IPv4PacketConn().SetTTL()" is from ipv4 genericopt.go
My go version is 1.19.3

@windyboyy
Copy link
Author

I saw in the example_test.go method of icmp that for Linux systems, certain things need to be set. Does this mean that the ping implemented in Go language cannot be used directly in Linux or Android systems?
image

@cherrymui
Copy link
Member

Thanks. It looks like you're asking a question about the net/icmp package. We don't really use our issue tracker for questions. You're welcome to ask on a forum rather than on the issue tracker. See https://golang.org/wiki/Questions. Thanks.

@cherrymui cherrymui closed this as not planned Won't fix, can't repro, duplicate, stale Mar 20, 2023
@golang golang locked and limited conversation to collaborators Mar 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

3 participants