๐Ÿ“ฆ dsymonds / plugmon

๐Ÿ“„ ping.go ยท 103 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103package main

import (
	"bytes"
	"log"
	"net"
	"strings"
)

func main() {
	conn, err := net.ListenUDP("udp4", &net.UDPAddr{})
	if err != nil {
		log.Fatalf("net.ListenUDP: %v", err)
	}
	laddr := conn.LocalAddr().(*net.UDPAddr)
	msg := []byte{
		// These first 32 bytes will be echoed back.
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x0a, 0x00, 0x00, 0x00,
		0xe1, 0x07, // yyyy, little endian
		0x05, 0x0c, 0x01, 0x06, // ss, mm, hh, ?
		0x1d, 0x04, // dd mm
		0x00, 0x00, 0x00, 0x00,
		laddr.IP[0], laddr.IP[1], laddr.IP[2], laddr.IP[3],
		byte(laddr.Port & 0xff), byte(laddr.Port >> 8),
		0x00, 0x00,

		// dunno what the rest is for
		0x6c, 0xc1, 0x00, 0x00, 0x00, 0x00, // 6c -> 108 (dec)
		0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
	dst := &net.UDPAddr{
		IP:   net.IPv4(255, 255, 255, 255),
		Port: 80,
	}
	log.Printf("sending %d byte message: %x", len(msg), msg)
	if _, err := conn.WriteToUDP(msg, dst); err != nil {
		log.Fatalf("conn.WriteToUDP: %v", err)
	}
	var scratch [1 << 10]byte
	n, raddr, err := conn.ReadFrom(scratch[:])
	if err != nil {
		log.Fatalf("conn.ReadFrom: %v", err)
	}
	b := scratch[:n]
	log.Printf("got back %d bytes from %s: %x", n, raddr, b)

	d := decode(msg, b)
	log.Printf("* %q (MAC %s, IP %s)", d.name, d.mac, d.ip)
	log.Printf("  unknown1: %x", d.unknown1)
	log.Printf("  unknown2: %x", d.unknown2)
}

func decode(req, b []byte) *data {
	if len(b) != 128 {
		log.Fatalf("bad response length %d (want 128)", len(b))
	}
	if !bytes.Equal(req[:32], b[:32]) {
		log.Fatalf("first 32 bytes of response isn't an echo\n req[:32] = %x\nresp[:32] = %x", req[:32], b[:32])
	}

	// next returns the next n bytes from b.
	next := func(n int) []byte {
		x := b[:n]
		b = b[n:]
		return x
	}
	rev := func(b []byte) []byte {
		for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 {
			b[i], b[j] = b[j], b[i]
		}
		return b
	}

	d := new(data)

	// Drop the first 32 bytes. They echo the request.
	next(32)

	d.unknown1 = next(4)  // offset=32
	d.unknown2 = next(18) // offset=36

	// Next 4 are the reversed IP of the switch.
	d.ip = rev(next(4)) // offset=54

	// Next 6 are the reversed MAC.
	d.mac = rev(next(6)) // offset=60

	// The remainder is the switch's name,
	// padded with zero bytes.
	d.name = strings.TrimRight(string(b), "\x00")

	return d
}

type data struct {
	unknown1 []byte
	unknown2 []byte
	ip       net.IP
	mac      net.HardwareAddr
	name     string
}