Example #1
0
func (self *HikarianIcmp) Run() {
	if self.mode == "decrypt" {
		clientConn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
		if err != nil {
			log.Fatal(err)
		}
		defer clientConn.Close()
		for {
			buf := make([]byte, 1024)
			nr, caddr, err := clientConn.ReadFrom(buf)
			request, err := icmp.ParseMessage(ProtocolICMP, buf)
			if err != nil {
				log.Println("parse icmp request error: ", err.Error())
				return
			}
			if request.Code == 0 {
				return
			}

			body, err := request.Body.Marshal(ProtocolICMP)
			if err != nil {
				log.Println("marshal body error: ", err.Error())
				continue
			}
			hash := binary.BigEndian.Uint16(body[0:2]) + binary.BigEndian.Uint16(body[2:4])
			dataChannel := self.DataChannelPool.Get(hash)
			if dataChannel == nil {
				dataChannel = make(chan []byte)
				self.DataChannelPool.Set(hash, dataChannel)
				go self.transportServer(clientConn, caddr, dataChannel)
			}
			if request.Code == MagicCode {
				log.Println("receive magic")
				dataChannel <- body[:nr-4]
			}
		}
	} else if self.mode == "encrypt" {
		client, err := net.ResolveTCPAddr("tcp", self.client)
		if err != nil {
			log.Fatalln("resolve client address error: ", err.Error())
		}
		l, err := net.ListenTCP("tcp", client)
		if err != nil {
			log.Fatal(err)
		}
		defer l.Close()
		for {
			clientConn, err := l.AcceptTCP()
			if err != nil {
				log.Println("accept error: ", err.Error())
				continue
			}
			defer clientConn.Close()
			go self.transportClient(clientConn)
		}
	}
}
Example #2
0
// Monitor clients going in/out of sleep mode via ICMP unreachable packets.
func sleepMonitor() {
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Printf("error listening for udp - sending data to all ports for all connected clients. err: %s", err)
		return
	}
	go icmpEchoSender(c)
	defer c.Close()
	for {
		buf := make([]byte, 1500)
		n, peer, err := c.ReadFrom(buf)
		if err != nil {
			log.Printf("%s\n", err.Error())
			continue
		}
		msg, err := icmp.ParseMessage(1, buf[:n])
		if err != nil {
			continue
		}

		ip := peer.String()

		// Look for echo replies, mark it as received.
		if msg.Type == ipv4.ICMPTypeEchoReply {
			pingResponse[ip] = stratuxClock.Time
			continue // No further processing needed.
		}

		// Only deal with ICMP Unreachable packets (since that's what iOS and Android seem to be sending whenever the apps are not available).
		if msg.Type != ipv4.ICMPTypeDestinationUnreachable {
			continue
		}
		// Packet parsing.
		mb, err := msg.Body.Marshal(1)
		if err != nil {
			continue
		}
		if len(mb) < 28 {
			continue
		}

		// The unreachable port.
		port := (uint16(mb[26]) << 8) | uint16(mb[27])
		ipAndPort := ip + ":" + strconv.Itoa(int(port))

		netMutex.Lock()
		p, ok := outSockets[ipAndPort]
		if !ok {
			// Can't do anything, the client isn't even technically connected.
			netMutex.Unlock()
			continue
		}
		p.LastUnreachable = stratuxClock.Time
		outSockets[ipAndPort] = p
		netMutex.Unlock()
	}
}
Example #3
0
func (p *Pinger) processPacket(recv *packet) error {
	var bytes []byte
	var proto int
	if p.ipv4 {
		if p.network == "ip" {
			bytes = ipv4Payload(recv.bytes)
		} else {
			bytes = recv.bytes
		}
		proto = protocolICMP
	} else {
		bytes = recv.bytes
		proto = protocolIPv6ICMP
	}

	var m *icmp.Message
	var err error
	if m, err = icmp.ParseMessage(proto, bytes[:recv.nbytes]); err != nil {
		return fmt.Errorf("Error parsing icmp message")
	}

	if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
		// Not an echo reply, ignore it
		return nil
	}

	outPkt := &Packet{
		Nbytes: recv.nbytes,
		IPAddr: p.ipaddr,
	}

	switch pkt := m.Body.(type) {
	case *icmp.Echo:
		outPkt.Rtt = time.Since(bytesToTime(pkt.Data[:timeSliceLength]))
		outPkt.Seq = pkt.Seq
		p.PacketsRecv += 1
	default:
		// Very bad, not sure how this can happen
		return fmt.Errorf("Error, invalid ICMP echo reply. Body type: %T, %s",
			pkt, pkt)
	}

	p.rtts = append(p.rtts, outPkt.Rtt)
	handler := p.OnRecv
	if handler != nil {
		handler(outPkt)
	}

	return nil
}
Example #4
0
func main() {
	timeout := 5
	t1 := time.Now()
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		checkError(err, "listen err, ")
	}
	c.SetDeadline(t1.Add(time.Second * time.Duration(timeout)))
	defer c.Close()

	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Fatal(err)
	}
	// Send ICMP echo and start timer
	starttime := time.Now()
	if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(targetIP)}); err != nil {
		log.Fatalf("WriteTo err, %s", err)
	}

	rb := make([]byte, 1500)
	// Look for ICMP response and stop time
	n, peer, err := c.ReadFrom(rb)
	stoptime := time.Now()
	if err != nil {
		log.Fatal(err)
	}
	//rm, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
	rm, err := icmp.ParseMessage(1, rb[:n])
	if err != nil {
		log.Fatal(err)
	}
	switch rm.Type {
	case ipv4.ICMPTypeEchoReply:
		log.Printf("got reflection from %v", peer)
		log.Printf("ICMP echo request sent on ", starttime)
		log.Printf("ICMP echo response received on ", stoptime)
	default:
		log.Printf("got %+v; want echo reply", rm)
	}
}
Example #5
0
func ping(listener *icmp.PacketConn, message icmp.Message, raddr net.Addr, timeout time.Duration) (Pong, error) {
	data, err := message.Marshal(nil)
	if err != nil {
		return Pong{}, err
	}
	_, err = listener.WriteTo(data, raddr)
	if err != nil {
		return Pong{}, err
	}
	now := time.Now()
	done := make(chan Pong)
	go func() {
		for {
			buf := make([]byte, 10000)
			// bufio
			n, peer, err := listener.ReadFrom(buf)
			if err != nil {
				return
			}
			since := time.Since(now)
			input, err := icmp.ParseMessage(protocolICMP, buf[:n])
			if err != nil {
				return
			}
			if input.Type != ipv4.ICMPTypeEchoReply {
				continue
			}
			echo := input.Body.(*icmp.Echo)
			pong := Pong{
				Peer: peer,
				ID:   echo.ID,
				Seq:  echo.Seq,
				Data: echo.Data,
				Size: n,
				RTT:  since,
			}
			done <- pong
			return
		}
	}()
	select {
	case pong := <-done:
		return pong, nil
	case <-time.After(timeout):
		return Pong{}, errors.New("Timeout")
	}
}
Example #6
0
func ExamplePacketConn_nonPrivilegedPing() {
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		log.Println("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		log.Println("not supported on", runtime.GOOS)
		return
	}

	c, err := icmp.ListenPacket("udp6", "fe80::1%en0")
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	wm := icmp.Message{
		Type: ipv6.ICMPTypeEchoRequest, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := c.WriteTo(wb, &net.UDPAddr{IP: net.ParseIP("ff02::1"), Zone: "en0"}); err != nil {
		log.Fatal(err)
	}

	rb := make([]byte, 1500)
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		log.Fatal(err)
	}
	rm, err := icmp.ParseMessage(58, rb[:n])
	if err != nil {
		log.Fatal(err)
	}
	switch rm.Type {
	case ipv6.ICMPTypeEchoReply:
		log.Printf("got reflection from %v", peer)
	default:
		log.Printf("got %+v; want echo reply", rm)
	}
}
Example #7
0
// This checks if we can convert an URL to an IP
func testDNS(pr *pingResponse, pi pingInfo, conn *icmp.PacketConn) {
	start := time.Now()
	msg := createMessage()

	msg_bytes, err := msg.Marshal(nil)
	if err != nil {
		emsg := "Could not marshal the message to []byte."
		logger.WriteString(emsg)
		pr.err = errors.New(emsg)
		return
	}

	ip, _ := net.LookupHost(pi.externalurl)

	if _, err := conn.WriteTo(msg_bytes, &net.UDPAddr{IP: net.ParseIP(ip[0]), Zone: "en0"}); err != nil {
		emsg := "Could not write to the internal ip address: " + ip[0]
		logger.WriteString(emsg)
		pr.external_url = false
		pr.err = errors.New(emsg)
		return
	}

	pr.external_url = true

	response := make([]byte, 1500)
	count, peer, err := conn.ReadFrom(response)
	if err != nil {
		emsg := "Could not read the response."
		logger.WriteString(emsg)
		pr.external_url = false
		pr.err = errors.New(emsg)
		return
	}

	_, err = icmp.ParseMessage(protocolICMP, response[:count])
	if err != nil {
		emsg := "Could not parse the message received."
		logger.WriteString(emsg)
		pr.external_url = false
		pr.err = errors.New(emsg)
		return
	}

	logger.WriteString("Response " + strconv.Itoa(sequence) + " received from " + peer.String() +
		" after " + time.Now().Sub(start).String())
}
Example #8
0
func TestMarshalAndParseMessageForIPv4(t *testing.T) {
	for i, tt := range marshalAndParseMessageForIPv4Tests {
		b, err := tt.Marshal(nil)
		if err != nil {
			t.Fatal(err)
		}
		m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
		if err != nil {
			t.Fatal(err)
		}
		if m.Type != tt.Type || m.Code != tt.Code {
			t.Errorf("#%v: got %v; want %v", i, m, &tt)
		}
		if !reflect.DeepEqual(m.Body, tt.Body) {
			t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body)
		}
	}
}
Example #9
0
func TestMarshalAndParseMultipartMessageForIPv4(t *testing.T) {
	for i, tt := range marshalAndParseMultipartMessageForIPv4Tests {
		b, err := tt.Marshal(nil)
		if err != nil {
			t.Fatal(err)
		}
		if b[5] != 32 {
			t.Errorf("#%v: got %v; want 32", i, b[5])
		}
		m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
		if err != nil {
			t.Fatal(err)
		}
		if m.Type != tt.Type || m.Code != tt.Code {
			t.Errorf("#%v: got %v; want %v", i, m, &tt)
		}
		switch m.Type {
		case ipv4.ICMPTypeDestinationUnreachable:
			got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach)
			if !reflect.DeepEqual(got.Extensions, want.Extensions) {
				t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
			}
			if len(got.Data) != 128 {
				t.Errorf("#%v: got %v; want 128", i, len(got.Data))
			}
		case ipv4.ICMPTypeTimeExceeded:
			got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded)
			if !reflect.DeepEqual(got.Extensions, want.Extensions) {
				t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
			}
			if len(got.Data) != 128 {
				t.Errorf("#%v: got %v; want 128", i, len(got.Data))
			}
		case ipv4.ICMPTypeParameterProblem:
			got, want := m.Body.(*icmp.ParamProb), tt.Body.(*icmp.ParamProb)
			if !reflect.DeepEqual(got.Extensions, want.Extensions) {
				t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
			}
			if len(got.Data) != 128 {
				t.Errorf("#%v: got %v; want 128", i, len(got.Data))
			}
		}
	}
}
Example #10
0
func (i *ICMP) Read() ([]byte, error) {
	buf := make([]byte, 10000)
	n, _, err := i.listener.ReadFrom(buf)
	if err != nil {
		return nil, err
	}
	input, err := icmp.ParseMessage(_PROTOCOL_ICMP, buf[:n])
	if err != nil {
		return nil, err
	}
	if input.Type != ipv4.ICMPTypeEchoReply {
		return nil, nil
	}
	echo, ok := input.Body.(*icmp.Echo)
	if !ok {
		return nil, nil
	}
	return echo.Data, nil
}
Example #11
0
func TestMarshalAndParseMessageForIPv6(t *testing.T) {
	pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1"))
	for i, tt := range marshalAndParseMessageForIPv6Tests {
		for _, psh := range [][]byte{pshicmp, nil} {
			b, err := tt.Marshal(psh)
			if err != nil {
				t.Fatal(err)
			}
			m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b)
			if err != nil {
				t.Fatal(err)
			}
			if m.Type != tt.Type || m.Code != tt.Code {
				t.Errorf("#%v: got %v; want %v", i, m, &tt)
			}
			if !reflect.DeepEqual(m.Body, tt.Body) {
				t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body)
			}
		}
	}
}
Example #12
0
func TestMarshalAndParseMultipartMessageForIPv6(t *testing.T) {
	pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1"))
	for i, tt := range marshalAndParseMultipartMessageForIPv6Tests {
		for _, psh := range [][]byte{pshicmp, nil} {
			b, err := tt.Marshal(psh)
			if err != nil {
				t.Fatal(err)
			}
			if b[4] != 16 {
				t.Errorf("#%v: got %v; want 16", i, b[4])
			}
			m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b)
			if err != nil {
				t.Fatal(err)
			}
			if m.Type != tt.Type || m.Code != tt.Code {
				t.Errorf("#%v: got %v; want %v", i, m, &tt)
			}
			switch m.Type {
			case ipv6.ICMPTypeDestinationUnreachable:
				got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach)
				if !reflect.DeepEqual(got.Extensions, want.Extensions) {
					t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
				}
				if len(got.Data) != 128 {
					t.Errorf("#%v: got %v; want 128", i, len(got.Data))
				}
			case ipv6.ICMPTypeTimeExceeded:
				got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded)
				if !reflect.DeepEqual(got.Extensions, want.Extensions) {
					t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
				}
				if len(got.Data) != 128 {
					t.Errorf("#%v: got %v; want 128", i, len(got.Data))
				}
			}
		}
	}
}
Example #13
0
func ExamplePacketConn_nonPrivilegedPing() {
	c, err := icmp.ListenPacket("udp6", "fe80::1%en0")
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	wm := icmp.Message{
		Type: ipv6.ICMPTypeEchoRequest, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := c.WriteTo(wb, &net.UDPAddr{IP: net.ParseIP("ff02::1"), Zone: "en0"}); err != nil {
		log.Fatal(err)
	}

	rb := make([]byte, 1500)
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		log.Fatal(err)
	}
	rm, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n])
	if err != nil {
		log.Fatal(err)
	}
	switch rm.Type {
	case ipv6.ICMPTypeEchoReply:
		log.Printf("got reflection from %v", peer)
	default:
		log.Printf("got %+v; want echo reply", rm)
	}
}
Example #14
0
func (p *Ping) parseMessage(r Reply, ssmap map[int]int64) bool {

	stop := time.Now().UnixNano()

	rep, err := icmp.ParseMessage(iana.ProtocolICMP, r.bytes)
	if err != nil {
		fmt.Printf("* Reply error from %s: icmp_seq=%d -> %s\n", r.addr, p.sends, r.bytes)
		return false
	}

	var seq int
	switch pkt := rep.Body.(type) {
	case *icmp.Echo:
		if !(pkt.ID == p.id && pkt.Seq <= p.sends && bytes.Equal(pkt.Data, p.data)) {
			fmt.Printf("* Wrong data %d bytes from %s (ID=[%d,%d], Seq=[%d,%d]): icmp_seq=%d\n",
				r.size, r.addr, pkt.ID, p.id, pkt.Seq, p.sends, p.sends)
			return false
		}
		seq = pkt.Seq
	default:
		fmt.Printf("* Not echo received from %s: icmp_seq=%d\n", r.size, r.addr, p.sends)
		return false
	}

	if v, ok := ssmap[seq]; !ok {
		fmt.Printf("* Duplicated packet received from %s: icmp_seq=%d\n", r.addr, p.sends)
		return false
	} else {
		rtt := stop - v
		delete(ssmap, seq)
		fmt.Printf("%d bytes from %s: icmp_seq=%d time=%.2f ms\n",
			r.size, r.addr, p.sends, float64(rtt)/float64(time.Millisecond))
	}

	return true
}
Example #15
0
func (p *Pinger) procRecv(bytes []byte, ra net.Addr, ctx *context) {
	var ipaddr *net.IPAddr
	switch adr := ra.(type) {
	case *net.IPAddr:
		ipaddr = adr
	case *net.UDPAddr:
		ipaddr = &net.IPAddr{IP: adr.IP, Zone: adr.Zone}
	default:
		return
	}

	addr := ipaddr.String()
	p.mu.Lock()
	_, ok := p.addrs[addr]
	p.mu.Unlock()

	if !ok {
		return
	}

	var proto int
	if isIPv4(ipaddr.IP) {
		if p.network == "ip" {
			bytes = ipv4Payload(bytes)
		}
		proto = ProtocolICMP
	} else if isIPv6(ipaddr.IP) {
		proto = ProtocolIPv6ICMP
	} else {
		return
	}

	var m *icmp.Message
	var err error
	if m, err = icmp.ParseMessage(proto, bytes); err != nil {
		return
	}

	if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
		return
	}

	var rtt time.Duration
	switch pkt := m.Body.(type) {
	case *icmp.Echo:
		if pkt.ID == p.id && pkt.Seq == p.seq {
			rtt = time.Since(bytesToTime(pkt.Data[:TimeSliceLength]))
		}
	default:
		return
	}

	if 0 == rtt {
		return
	}

	p.mu.Lock()
	delete(p.sent, addr)
	if len(p.sent) == 0 && !p.done {
		p.done = true
		close(ctx.done)
	}
	p.mu.Unlock()

	if p.OnRecv != nil {
		p.OnRecv(ipaddr, rtt)
	}
}
Example #16
0
// pingIcmp performs a ping to a destination. It select between ipv4 or ipv6 ping based
// on the format of the destination ip.
func (r Runner) pingIcmp() (err error) {
	var (
		icmpType icmp.Type
		network  string
	)

	if strings.Contains(r.Parameters.Destination, ":") {
		network = "ip6:ipv6-icmp"
		icmpType = ipv6.ICMPTypeEchoRequest
	} else {
		network = "ip4:icmp"
		icmpType = ipv4.ICMPTypeEcho
	}

	c, err := net.Dial(network, r.Parameters.Destination)
	if err != nil {
		return fmt.Errorf("Dial failed: %v", err)
	}
	c.SetDeadline(time.Now().Add(time.Duration(r.Parameters.Timeout) * time.Second))
	defer c.Close()

	// xid is the process ID.
	// Get process ID and make sure it fits in 16bits.
	xid := os.Getpid() & 0xffff
	// Sequence number of the packet.
	xseq := 0
	packet := icmp.Message{
		Type: icmpType, // Type of icmp message
		Code: 0,        // icmp query messages use code 0
		Body: &icmp.Echo{
			ID:   xid,  // Packet id
			Seq:  xseq, // Sequence number of the packet
			Data: bytes.Repeat([]byte("Ping!Ping!Ping!"), 3),
		},
	}

	wb, err := packet.Marshal(nil)

	if err != nil {
		return fmt.Errorf("Connection failed: %v", err)
	}

	if _, err := c.Write(wb); err != nil {
		return fmt.Errorf("Conn.Write Error: %v", err)
	}

	rb := make([]byte, 1500)

	if _, err := c.Read(rb); err != nil {
		// If connection timed out, we return E_Timeout
		if e := err.(*net.OpError).Timeout(); e {
			return fmt.Errorf(E_Timeout)
		}
		if strings.Contains(err.Error(), "connection refused") {
			return fmt.Errorf(E_ConnRefused)
		}
		return fmt.Errorf("Conn.Read failed: %v", err)
	}

	_, err = icmp.ParseMessage(icmpType.Protocol(), rb)
	if err != nil {
		return fmt.Errorf("ParseICMPMessage failed: %v", err)
	}

	return
}
Example #17
0
func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
	switch runtime.GOOS {
	case "nacl", "plan9", "windows":
		t.Skipf("not supported on %s", runtime.GOOS)
	}
	if m, ok := nettest.SupportsRawIPSocket(); !ok {
		t.Skip(m)
	}
	ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
	if ifi == nil {
		t.Skipf("not available on %s", runtime.GOOS)
	}

	c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	dst, err := net.ResolveIPAddr("ip4", "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	p := ipv4.NewPacketConn(c)
	defer p.Close()
	cf := ipv4.FlagDst | ipv4.FlagInterface
	if runtime.GOOS != "solaris" {
		// Solaris never allows to modify ICMP properties.
		cf |= ipv4.FlagTTL
	}

	for i, toggle := range []bool{true, false, true} {
		wb, err := (&icmp.Message{
			Type: ipv4.ICMPTypeEcho, Code: 0,
			Body: &icmp.Echo{
				ID: os.Getpid() & 0xffff, Seq: i + 1,
				Data: []byte("HELLO-R-U-THERE"),
			},
		}).Marshal(nil)
		if err != nil {
			t.Fatal(err)
		}
		if err := p.SetControlMessage(cf, toggle); err != nil {
			if nettest.ProtocolNotSupported(err) {
				t.Logf("not supported on %s", runtime.GOOS)
				continue
			}
			t.Fatal(err)
		}
		p.SetTTL(i + 1)
		if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
			t.Fatal(err)
		}
		if n, err := p.WriteTo(wb, nil, dst); err != nil {
			t.Fatal(err)
		} else if n != len(wb) {
			t.Fatalf("got %v; want %v", n, len(wb))
		}
		rb := make([]byte, 128)
	loop:
		if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
			t.Fatal(err)
		}
		if n, _, _, err := p.ReadFrom(rb); err != nil {
			switch runtime.GOOS {
			case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket
				t.Logf("not supported on %s", runtime.GOOS)
				continue
			}
			t.Fatal(err)
		} else {
			m, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
			if err != nil {
				t.Fatal(err)
			}
			if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
				// On Linux we must handle own sent packets.
				goto loop
			}
			if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
				t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
			}
		}
	}
}
Example #18
0
func TestRawConnReadWriteUnicastICMP(t *testing.T) {
	switch runtime.GOOS {
	case "nacl", "plan9", "windows":
		t.Skipf("not supported on %s", runtime.GOOS)
	}
	if m, ok := nettest.SupportsRawIPSocket(); !ok {
		t.Skip(m)
	}
	ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
	if ifi == nil {
		t.Skipf("not available on %s", runtime.GOOS)
	}

	c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	dst, err := net.ResolveIPAddr("ip4", "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	r, err := ipv4.NewRawConn(c)
	if err != nil {
		t.Fatal(err)
	}
	defer r.Close()
	cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface

	for i, toggle := range []bool{true, false, true} {
		wb, err := (&icmp.Message{
			Type: ipv4.ICMPTypeEcho, Code: 0,
			Body: &icmp.Echo{
				ID: os.Getpid() & 0xffff, Seq: i + 1,
				Data: []byte("HELLO-R-U-THERE"),
			},
		}).Marshal(nil)
		if err != nil {
			t.Fatal(err)
		}
		wh := &ipv4.Header{
			Version:  ipv4.Version,
			Len:      ipv4.HeaderLen,
			TOS:      i + 1,
			TotalLen: ipv4.HeaderLen + len(wb),
			TTL:      i + 1,
			Protocol: 1,
			Dst:      dst.IP,
		}
		if err := r.SetControlMessage(cf, toggle); err != nil {
			if nettest.ProtocolNotSupported(err) {
				t.Logf("not supported on %s", runtime.GOOS)
				continue
			}
			t.Fatal(err)
		}
		if err := r.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
			t.Fatal(err)
		}
		if err := r.WriteTo(wh, wb, nil); err != nil {
			t.Fatal(err)
		}
		rb := make([]byte, ipv4.HeaderLen+128)
	loop:
		if err := r.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
			t.Fatal(err)
		}
		if _, b, _, err := r.ReadFrom(rb); err != nil {
			switch runtime.GOOS {
			case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket
				t.Logf("not supported on %s", runtime.GOOS)
				continue
			}
			t.Fatal(err)
		} else {
			m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
			if err != nil {
				t.Fatal(err)
			}
			if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
				// On Linux we must handle own sent packets.
				goto loop
			}
			if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
				t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
			}
		}
	}
}
Example #19
0
func ExamplePacketConn_tracingIPPacketRoute() {
	// Tracing an IP packet route to www.google.com.

	const host = "www.google.com"
	ips, err := net.LookupIP(host)
	if err != nil {
		log.Fatal(err)
	}
	var dst net.IPAddr
	for _, ip := range ips {
		if ip.To4() != nil {
			dst.IP = ip
			fmt.Printf("using %v for tracing an IP packet route to %s\n", dst.IP, host)
			break
		}
	}
	if dst.IP == nil {
		log.Fatal("no A record found")
	}

	c, err := net.ListenPacket(fmt.Sprintf("ip4:%d", iana.ProtocolICMP), "0.0.0.0") // ICMP for IPv4
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()
	p := ipv4.NewPacketConn(c)

	if err := p.SetControlMessage(ipv4.FlagTTL|ipv4.FlagSrc|ipv4.FlagDst|ipv4.FlagInterface, true); err != nil {
		log.Fatal(err)
	}
	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID:   os.Getpid() & 0xffff,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}

	rb := make([]byte, 1500)
	for i := 1; i <= 64; i++ { // up to 64 hops
		wm.Body.(*icmp.Echo).Seq = i
		wb, err := wm.Marshal(nil)
		if err != nil {
			log.Fatal(err)
		}
		if err := p.SetTTL(i); err != nil {
			log.Fatal(err)
		}

		// In the real world usually there are several
		// multiple traffic-engineered paths for each hop.
		// You may need to probe a few times to each hop.
		begin := time.Now()
		if _, err := p.WriteTo(wb, nil, &dst); err != nil {
			log.Fatal(err)
		}
		if err := p.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
			log.Fatal(err)
		}
		n, cm, peer, err := p.ReadFrom(rb)
		if err != nil {
			if err, ok := err.(net.Error); ok && err.Timeout() {
				fmt.Printf("%v\t*\n", i)
				continue
			}
			log.Fatal(err)
		}
		rm, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
		if err != nil {
			log.Fatal(err)
		}
		rtt := time.Since(begin)

		// In the real world you need to determine whether the
		// received message is yours using ControlMessage.Src,
		// ControlMessage.Dst, icmp.Echo.ID and icmp.Echo.Seq.
		switch rm.Type {
		case ipv4.ICMPTypeTimeExceeded:
			names, _ := net.LookupAddr(peer.String())
			fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm)
		case ipv4.ICMPTypeEchoReply:
			names, _ := net.LookupAddr(peer.String())
			fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm)
			return
		default:
			log.Printf("unknown ICMP message: %+v\n", rm)
		}
	}
}
Example #20
0
func (p *Pinger) procRecv(recv *packet, queue map[string]*net.IPAddr) {
	var ipaddr *net.IPAddr
	switch adr := recv.addr.(type) {
	case *net.IPAddr:
		ipaddr = adr
	case *net.UDPAddr:
		ipaddr = &net.IPAddr{IP: adr.IP, Zone: adr.Zone}
	default:
		return
	}

	addr := ipaddr.String()
	p.mu.Lock()
	if _, ok := p.addrs[addr]; !ok {
		p.mu.Unlock()
		return
	}
	p.mu.Unlock()

	var bytes []byte
	var proto int
	if isIPv4(ipaddr.IP) {
		if p.network == "ip" {
			bytes = ipv4Payload(recv.bytes)
		} else {
			bytes = recv.bytes
		}
		proto = ProtocolICMP
	} else if isIPv6(ipaddr.IP) {
		bytes = recv.bytes
		proto = ProtocolIPv6ICMP
	} else {
		return
	}

	var m *icmp.Message
	var err error
	if m, err = icmp.ParseMessage(proto, bytes); err != nil {
		return
	}

	if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
		return
	}

	var rtt time.Duration
	switch pkt := m.Body.(type) {
	case *icmp.Echo:
		p.mu.Lock()
		if pkt.ID == p.id && pkt.Seq == p.seq {
			rtt = time.Since(bytesToTime(pkt.Data[:TimeSliceLength]))
		}
		p.mu.Unlock()
	default:
		return
	}

	if _, ok := queue[addr]; ok {
		delete(queue, addr)
		p.mu.Lock()
		handler := p.OnRecv
		p.mu.Unlock()
		if handler != nil {
			handler(ipaddr, rtt)
		}
	}
}
Example #21
0
func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
	switch runtime.GOOS {
	case "freebsd": // due to a bug on loopback marking
		// See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065.
		t.Skipf("not supported on %s", runtime.GOOS)
	case "nacl", "plan9", "windows":
		t.Skipf("not supported on %s", runtime.GOOS)
	}
	if !supportsIPv6 {
		t.Skip("ipv6 is not supported")
	}
	if m, ok := nettest.SupportsRawIPSocket(); !ok {
		t.Skip(m)
	}
	ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
	if ifi == nil {
		t.Skipf("not available on %s", runtime.GOOS)
	}

	for _, tt := range packetConnReadWriteMulticastICMPTests {
		c, err := net.ListenPacket("ip6:ipv6-icmp", "::")
		if err != nil {
			t.Fatal(err)
		}
		defer c.Close()

		pshicmp := icmp.IPv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, tt.grp.IP)
		p := ipv6.NewPacketConn(c)
		defer p.Close()
		if tt.src == nil {
			if err := p.JoinGroup(ifi, tt.grp); err != nil {
				t.Fatal(err)
			}
			defer p.LeaveGroup(ifi, tt.grp)
		} else {
			if err := p.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil {
				switch runtime.GOOS {
				case "freebsd", "linux":
				default: // platforms that don't support MLDv2 fail here
					t.Logf("not supported on %s", runtime.GOOS)
					continue
				}
				t.Fatal(err)
			}
			defer p.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src)
		}
		if err := p.SetMulticastInterface(ifi); err != nil {
			t.Fatal(err)
		}
		if _, err := p.MulticastInterface(); err != nil {
			t.Fatal(err)
		}
		if err := p.SetMulticastLoopback(true); err != nil {
			t.Fatal(err)
		}
		if _, err := p.MulticastLoopback(); err != nil {
			t.Fatal(err)
		}

		cm := ipv6.ControlMessage{
			TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
			Src:          net.IPv6loopback,
			IfIndex:      ifi.Index,
		}
		cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU

		var f ipv6.ICMPFilter
		f.SetAll(true)
		f.Accept(ipv6.ICMPTypeEchoReply)
		if err := p.SetICMPFilter(&f); err != nil {
			t.Fatal(err)
		}

		var psh []byte
		for i, toggle := range []bool{true, false, true} {
			if toggle {
				psh = nil
				if err := p.SetChecksum(true, 2); err != nil {
					// Solaris never allows to
					// modify ICMP properties.
					if runtime.GOOS != "solaris" {
						t.Fatal(err)
					}
				}
			} else {
				psh = pshicmp
				// Some platforms never allow to
				// disable the kernel checksum
				// processing.
				p.SetChecksum(false, -1)
			}
			wb, err := (&icmp.Message{
				Type: ipv6.ICMPTypeEchoRequest, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: i + 1,
					Data: []byte("HELLO-R-U-THERE"),
				},
			}).Marshal(psh)
			if err != nil {
				t.Fatal(err)
			}
			if err := p.SetControlMessage(cf, toggle); err != nil {
				if nettest.ProtocolNotSupported(err) {
					t.Logf("not supported on %s", runtime.GOOS)
					continue
				}
				t.Fatal(err)
			}
			if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
				t.Fatal(err)
			}
			cm.HopLimit = i + 1
			if n, err := p.WriteTo(wb, &cm, tt.grp); err != nil {
				t.Fatal(err)
			} else if n != len(wb) {
				t.Fatalf("got %v; want %v", n, len(wb))
			}
			rb := make([]byte, 128)
			if n, _, _, err := p.ReadFrom(rb); err != nil {
				switch runtime.GOOS {
				case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket
					t.Logf("not supported on %s", runtime.GOOS)
					continue
				}
				t.Fatal(err)
			} else {
				if m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n]); err != nil {
					t.Fatal(err)
				} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
					t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
				}
			}
		}
	}
}
Example #22
0
func TestRawConnReadWriteMulticastICMP(t *testing.T) {
	if testing.Short() {
		t.Skip("to avoid external network")
	}
	if m, ok := nettest.SupportsRawIPSocket(); !ok {
		t.Skip(m)
	}
	ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
	if ifi == nil {
		t.Skipf("not available on %s", runtime.GOOS)
	}

	for _, tt := range rawConnReadWriteMulticastICMPTests {
		c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
		if err != nil {
			t.Fatal(err)
		}
		defer c.Close()

		r, err := ipv4.NewRawConn(c)
		if err != nil {
			t.Fatal(err)
		}
		defer r.Close()
		if tt.src == nil {
			if err := r.JoinGroup(ifi, tt.grp); err != nil {
				t.Fatal(err)
			}
			defer r.LeaveGroup(ifi, tt.grp)
		} else {
			if err := r.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil {
				switch runtime.GOOS {
				case "freebsd", "linux":
				default: // platforms that don't support IGMPv2/3 fail here
					t.Logf("not supported on %s", runtime.GOOS)
					continue
				}
				t.Fatal(err)
			}
			defer r.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src)
		}
		if err := r.SetMulticastInterface(ifi); err != nil {
			t.Fatal(err)
		}
		if _, err := r.MulticastInterface(); err != nil {
			t.Fatal(err)
		}
		if err := r.SetMulticastLoopback(true); err != nil {
			t.Fatal(err)
		}
		if _, err := r.MulticastLoopback(); err != nil {
			t.Fatal(err)
		}
		cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface

		for i, toggle := range []bool{true, false, true} {
			wb, err := (&icmp.Message{
				Type: ipv4.ICMPTypeEcho, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: i + 1,
					Data: []byte("HELLO-R-U-THERE"),
				},
			}).Marshal(nil)
			if err != nil {
				t.Fatal(err)
			}
			wh := &ipv4.Header{
				Version:  ipv4.Version,
				Len:      ipv4.HeaderLen,
				TOS:      i + 1,
				TotalLen: ipv4.HeaderLen + len(wb),
				Protocol: 1,
				Dst:      tt.grp.IP,
			}
			if err := r.SetControlMessage(cf, toggle); err != nil {
				if nettest.ProtocolNotSupported(err) {
					t.Logf("not supported on %s", runtime.GOOS)
					continue
				}
				t.Fatal(err)
			}
			if err := r.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
				t.Fatal(err)
			}
			r.SetMulticastTTL(i + 1)
			if err := r.WriteTo(wh, wb, nil); err != nil {
				t.Fatal(err)
			}
			rb := make([]byte, ipv4.HeaderLen+128)
			if rh, b, _, err := r.ReadFrom(rb); err != nil {
				t.Fatal(err)
			} else {
				m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
				if err != nil {
					t.Fatal(err)
				}
				switch {
				case (rh.Dst.IsLoopback() || rh.Dst.IsLinkLocalUnicast() || rh.Dst.IsGlobalUnicast()) && m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1
				case rh.Dst.IsMulticast() && m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0
				default:
					t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
				}
			}
		}
	}
}
Example #23
0
func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
	switch runtime.GOOS {
	case "nacl", "plan9", "solaris", "windows":
		t.Skipf("not supported on %s", runtime.GOOS)
	}
	if m, ok := nettest.SupportsRawIPSocket(); !ok {
		t.Skip(m)
	}
	ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
	if ifi == nil {
		t.Skipf("not available on %s", runtime.GOOS)
	}

	for _, tt := range packetConnReadWriteMulticastICMPTests {
		c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
		if err != nil {
			t.Fatal(err)
		}
		defer c.Close()

		p := ipv4.NewPacketConn(c)
		defer p.Close()
		if tt.src == nil {
			if err := p.JoinGroup(ifi, tt.grp); err != nil {
				t.Fatal(err)
			}
			defer p.LeaveGroup(ifi, tt.grp)
		} else {
			if err := p.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil {
				switch runtime.GOOS {
				case "freebsd", "linux":
				default: // platforms that don't support IGMPv2/3 fail here
					t.Logf("not supported on %s", runtime.GOOS)
					continue
				}
				t.Fatal(err)
			}
			defer p.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src)
		}
		if err := p.SetMulticastInterface(ifi); err != nil {
			t.Fatal(err)
		}
		if _, err := p.MulticastInterface(); err != nil {
			t.Fatal(err)
		}
		if err := p.SetMulticastLoopback(true); err != nil {
			t.Fatal(err)
		}
		if _, err := p.MulticastLoopback(); err != nil {
			t.Fatal(err)
		}
		cf := ipv4.FlagDst | ipv4.FlagInterface
		if runtime.GOOS != "solaris" {
			// Solaris never allows to modify ICMP properties.
			cf |= ipv4.FlagTTL
		}

		for i, toggle := range []bool{true, false, true} {
			wb, err := (&icmp.Message{
				Type: ipv4.ICMPTypeEcho, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: i + 1,
					Data: []byte("HELLO-R-U-THERE"),
				},
			}).Marshal(nil)
			if err != nil {
				t.Fatal(err)
			}
			if err := p.SetControlMessage(cf, toggle); err != nil {
				if nettest.ProtocolNotSupported(err) {
					t.Logf("not supported on %s", runtime.GOOS)
					continue
				}
				t.Fatal(err)
			}
			if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil {
				t.Fatal(err)
			}
			p.SetMulticastTTL(i + 1)
			if n, err := p.WriteTo(wb, nil, tt.grp); err != nil {
				t.Fatal(err)
			} else if n != len(wb) {
				t.Fatalf("got %v; want %v", n, len(wb))
			}
			rb := make([]byte, 128)
			if n, _, _, err := p.ReadFrom(rb); err != nil {
				t.Fatal(err)
			} else {
				m, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
				if err != nil {
					t.Fatal(err)
				}
				switch {
				case m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1
				case m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0
				default:
					t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
				}
			}
		}
	}
}
Example #24
0
func doPing(tt pingTest, seq int) error {
	c, err := icmp.ListenPacket(tt.network, tt.address)
	if err != nil {
		return err
	}
	defer c.Close()

	dst, err := googleAddr(c, tt.protocol)
	if err != nil {
		return err
	}

	if tt.protocol == iana.ProtocolIPv6ICMP {
		var f ipv6.ICMPFilter
		f.SetAll(true)
		f.Accept(ipv6.ICMPTypeDestinationUnreachable)
		f.Accept(ipv6.ICMPTypePacketTooBig)
		f.Accept(ipv6.ICMPTypeTimeExceeded)
		f.Accept(ipv6.ICMPTypeParameterProblem)
		f.Accept(ipv6.ICMPTypeEchoReply)
		if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
			return err
		}
	}

	wm := icmp.Message{
		Type: tt.mtype, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		return err
	}
	if n, err := c.WriteTo(wb, dst); err != nil {
		return err
	} else if n != len(wb) {
		return fmt.Errorf("got %v; want %v", n, len(wb))
	}

	rb := make([]byte, 1500)
	if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
		return err
	}
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		return err
	}
	rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
	if err != nil {
		return err
	}
	switch rm.Type {
	case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
		return nil
	default:
		return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
	}
}
Example #25
0
func probeICMP(target string, w http.ResponseWriter, module Module) (success bool) {
	deadline := time.Now().Add(module.Timeout)
	socket, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Errorf("Error listening to socket: %s", err)
		return
	}
	defer socket.Close()

	ip, err := net.ResolveIPAddr("ip4", target)
	if err != nil {
		log.Errorf("Error resolving address %s: %s", target, err)
		return
	}

	seq := getICMPSequence()
	pid := os.Getpid() & 0xffff

	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID: pid, Seq: int(seq),
			Data: []byte("Prometheus Blackbox Exporter"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", target, err)
		return
	}
	if _, err := socket.WriteTo(wb, ip); err != nil {
		log.Errorf("Error writing to socker for %s: %s", target, err)
		return
	}

	rb := make([]byte, 1500)
	if err := socket.SetReadDeadline(deadline); err != nil {
		log.Errorf("Error setting socket deadline for %s: %s", target, err)
		return
	}
	for {
		n, peer, err := socket.ReadFrom(rb)
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
				log.Infof("Timeout reading from socket for %s: %s", target, err)
				return
			}
			log.Errorf("Error reading from socket for %s: %s", target, err)
			continue
		}
		if peer.String() != ip.String() {
			continue
		}
		rm, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
		if err != nil {
			log.Warnf("Error parsing ICMP message for %s: %s", target, err)
			continue
		}
		if rm.Type == ipv4.ICMPTypeEchoReply {
			// The ICMP package does not support unmarshalling
			// messages, so assume this is the right sequence number.
			success = true
			return
		}
	}
	return
}
Example #26
0
File: ping.go Project: conoro/netx
func (this *Pinger) receiver() {
	defer func() {
		// Let's recover from panic
		if r := recover(); r != nil {
			glog.Errorf("Recovering from panic: %v", r)
		}

		this.wg.Done()
		close(this.reschan)
		this.Stop()
	}()

	rb := make([]byte, ipv4.HeaderLen+icmpHeaderSize+this.Size)

	var tempDelay time.Duration // how long to sleep on accept failure

loop:
	for {
		rh, b, _, err := this.rconn.ReadFrom(rb)
		if err != nil {
			select {
			case <-this.done:
				break loop

			default:
			}

			// Borrowed from go1.3.3/src/pkg/net/http/server.go:1699
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := this.MaxRTT; tempDelay > max {
					tempDelay = max
				}
				glog.Errorf("Accept error: %v; retrying in %v", err, tempDelay)
				time.Sleep(tempDelay)
				continue
			}

			break loop
		}

		m, err := icmp.ParseMessage(ProtocolICMP, b)
		if err != nil {
			// Hm...bad message?
			continue
		}

		if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho {
			// On Linux we must handle own sent packets.
			continue
		}

		if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 {
			glog.Errorf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0)
			continue
		}

		// Echo Reply
		er, ok := m.Body.(*icmp.Echo)
		if !ok {
			glog.Errorf("Error type requireing m.Body to *icmp.Echo")
			continue
		}

		if er.ID != int(this.pid) || er.Seq > int(this.seqnum) {
			glog.Debugf("%d != %d, %d != %d", er.ID, this.pid, er.Seq, this.seqnum)
			continue
		}

		rtt := time.Since(time.Unix(0, int64(binary.BigEndian.Uint64(er.Data))))

		src := make(net.IP, len(rh.Src))
		copy(src, rh.Src)

		dst := make(net.IP, len(rh.Dst))
		copy(dst, rh.Dst)

		pr := &PingResult{
			TOS:  rh.TOS,
			TTL:  rh.TTL,
			Type: m.Type,
			Code: m.Code,
			ID:   er.ID,
			Seq:  er.Seq,
			RTT:  rtt,
			Src:  src,
			Dst:  dst,
			Size: len(er.Data),
		}
		this.mu.Lock()
		this.results[src.String()] = pr
		this.mu.Unlock()

		this.reschan <- pr
	}

	for ip, pr := range this.results {
		if pr == nil {
			this.reschan <- &PingResult{
				Src: net.ParseIP(ip),
				ID:  int(this.pid),
				Seq: int(this.seqnum),
				Err: fmt.Errorf("%s: Request timed out for seq %d", ip, this.seqnum),
			}
		}
	}
}
Example #27
0
func doPing(host string, tt *Ping, seq int) error {
	c, err := icmp.ListenPacket(tt.network, tt.address)
	if err != nil {
		return err
	}
	defer c.Close()

	dst, err := getAddr(host, c, tt.protocol)
	if err != nil {
		return err
	}

	now := time.Now()
	today := now.Truncate(24*time.Hour).UnixNano() / 1000000
	transmitTime := uint32(now.UnixNano()/1000000 - today)
	wm := icmp.Message{
		Type: tt.mtype,
		Code: 0,
		Body: &Timestamp{
			ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
			OriginTimestamp: transmitTime,
		},
	}

	wb, err := wm.Marshal(nil)
	if err != nil {
		return err
	}
	if n, err := c.WriteTo(wb, dst); err != nil {
		return err
	} else if n != len(wb) {
		return fmt.Errorf("got %v; want %v", n, len(wb))
	}

	rb := make([]byte, 1500)
	if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
		return err
	}
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		return err
	}
	receivedTime := time.Now().UnixNano()/1000000 - today
	rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
	if err != nil {
		return err
	}
	switch rm.Type {
	case ipv4.ICMPTypeTimestampReply:
		b, _ := rm.Body.Marshal(iana.ProtocolICMP)
		ts, err := ParseTimestamp(b)
		if err != nil {
			fmt.Errorf("ParseTimestamp error: %s", err)
		}
		remoteReceiveTime := int64(ts.ReceiveTimestamp)
		rtt := int64(math.Abs(float64(remoteReceiveTime - int64(transmitTime) + receivedTime - int64(ts.TransmitTimestamp))))
		delta := rtt/2 + int64(transmitTime) - remoteReceiveTime
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 4, 0, '\t', 0)
		fmt.Fprintf(w, "ICMP timestamp:\tOriginate=%d Receive=%d Transmit=%d\n", ts.OriginTimestamp, ts.ReceiveTimestamp, ts.TransmitTimestamp)
		fmt.Fprintf(w, "ICMP timestamp RTT:\ttsrtt=%d\n", rtt)
		fmt.Fprintf(w, "Time difference:\tdelta=%d\n", delta)
		w.Flush()
		return nil
	default:
		return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
	}
}
Example #28
0
func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
	switch runtime.GOOS {
	case "nacl", "plan9", "solaris", "windows":
		t.Skipf("not supported on %q", runtime.GOOS)
	}
	if !supportsIPv6 {
		t.Skip("ipv6 is not supported")
	}
	if os.Getuid() != 0 {
		t.Skip("must be root")
	}

	c, err := net.ListenPacket("ip6:ipv6-icmp", "::1")
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	p := ipv6.NewPacketConn(c)
	defer p.Close()

	dst, err := net.ResolveIPAddr("ip6", "::1")
	if err != nil {
		t.Fatal(err)
	}

	pshicmp := icmp.IPv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP)
	cm := ipv6.ControlMessage{
		TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
		Src:          net.IPv6loopback,
	}
	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
	ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
	if ifi != nil {
		cm.IfIndex = ifi.Index
	}

	var f ipv6.ICMPFilter
	f.SetAll(true)
	f.Accept(ipv6.ICMPTypeEchoReply)
	if err := p.SetICMPFilter(&f); err != nil {
		t.Fatal(err)
	}

	var psh []byte
	for i, toggle := range []bool{true, false, true} {
		if toggle {
			psh = nil
			if err := p.SetChecksum(true, 2); err != nil {
				t.Fatal(err)
			}
		} else {
			psh = pshicmp
			// Some platforms never allow to disable the
			// kernel checksum processing.
			p.SetChecksum(false, -1)
		}
		wb, err := (&icmp.Message{
			Type: ipv6.ICMPTypeEchoRequest, Code: 0,
			Body: &icmp.Echo{
				ID: os.Getpid() & 0xffff, Seq: i + 1,
				Data: []byte("HELLO-R-U-THERE"),
			},
		}).Marshal(psh)
		if err != nil {
			t.Fatal(err)
		}
		if err := p.SetControlMessage(cf, toggle); err != nil {
			if nettest.ProtocolNotSupported(err) {
				t.Skipf("not supported on %q", runtime.GOOS)
			}
			t.Fatal(err)
		}
		cm.HopLimit = i + 1
		if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
			t.Fatal(err)
		}
		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
			t.Fatal(err)
		} else if n != len(wb) {
			t.Fatalf("got %v; want %v", n, len(wb))
		}
		rb := make([]byte, 128)
		if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil {
			t.Fatal(err)
		}
		if n, cm, _, err := p.ReadFrom(rb); err != nil {
			switch runtime.GOOS {
			case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket
				t.Logf("not supported on %q", runtime.GOOS)
				continue
			}
			t.Fatal(err)
		} else {
			t.Logf("rcvd cmsg: %v", cm)
			if m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n]); err != nil {
				t.Fatal(err)
			} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
				t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
			}
		}
	}
}
Example #29
0
func TestPingGoogle(t *testing.T) {
	if testing.Short() {
		t.Skip("to avoid external network")
	}
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		t.Skipf("not supported on %q", runtime.GOOS)
	}

	for i, tt := range pingGoogleTests {
		if tt.network[:2] == "ip" && os.Getuid() != 0 {
			continue
		}
		c, err := icmp.ListenPacket(tt.network, tt.address)
		if err != nil {
			t.Error(err)
			continue
		}
		defer c.Close()

		dst, err := googleAddr(c, tt.protocol)
		if err != nil {
			t.Error(err)
			continue
		}

		wm := icmp.Message{
			Type: tt.mtype, Code: 0,
			Body: &icmp.Echo{
				ID: os.Getpid() & 0xffff, Seq: 1 << uint(i),
				Data: []byte("HELLO-R-U-THERE"),
			},
		}
		wb, err := wm.Marshal(nil)
		if err != nil {
			t.Error(err)
			continue
		}
		if n, err := c.WriteTo(wb, dst); err != nil {
			t.Error(err, dst)
			continue
		} else if n != len(wb) {
			t.Errorf("got %v; want %v", n, len(wb))
			continue
		}

		rb := make([]byte, 1500)
		n, peer, err := c.ReadFrom(rb)
		if err != nil {
			t.Error(err)
			continue
		}
		rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
		if err != nil {
			t.Error(err)
			continue
		}
		switch rm.Type {
		case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
			t.Logf("got reflection from %v", peer)
		default:
			t.Errorf("got %+v; want echo reply", rm)
		}
	}
}
Example #30
0
func (p *Pinger) listenIpv4() {
	if p.conn == nil {
		panic("conn doesnt exist")
	}
	log.Printf("starting rawSocket listener\n")
	rb := make([]byte, 1500)
	pkt := EchoResponse{}
	var readErr error
	var data []byte
	ipconn, ok := p.conn.(*net.IPConn)
	if !ok {
		panic("connection is not IPConn")
	}
	file, err := ipconn.File()
	if err != nil {
		panic(err.Error())
	}
	defer file.Close()
	fd := file.Fd()

	var pktTime time.Time
	recvTime := syscall.Timeval{}
	for {
		if p.conn == nil {
			break
		}
		n, peer, err := p.conn.ReadFrom(rb)
		if err != nil {
			readErr = err
			break
		}
		_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.SIOCGSTAMP), uintptr(unsafe.Pointer(&recvTime)))
		err = nil
		if errno != 0 {
			err = errno
		}
		if err == nil {
			pktTime = time.Unix(0, recvTime.Nano())
		} else {
			pktTime = time.Now()
		}

		rm, err := icmp.ParseMessage(ProtocolICMP, rb[:n])
		if err != nil {
			fmt.Println(err.Error())
			continue
		}
		if rm.Type == ipv4.ICMPTypeEchoReply {
			data = rm.Body.(*icmp.Echo).Data
			if len(data) < 9 {
				log.Printf("go-pinger: invalid data payload from %s. Expected at least 9bytes got %d", peer.String(), len(data))
				continue
			}
			pkt = EchoResponse{
				Peer:     peer.String(),
				Seq:      rm.Body.(*icmp.Echo).Seq,
				Id:       rm.Body.(*icmp.Echo).ID,
				Received: pktTime,
			}
			if p.Debug {
				log.Printf("go-pinger: recieved pkt. %s\n", pkt.String())
			}
			select {
			case p.packetChan <- pkt:
			default:
				log.Printf("go-pinger: droped echo response due to blocked packetChan. %s\n", pkt.String())
			}
		}
	}
	if p.Debug {
		log.Printf("listen loop ended.")
	}
	p.m.Lock()
	if p.running {
		log.Println(readErr.Error())
		p.Stop()
		p.start()
	}
	p.m.Unlock()
}