diff --git a/main.go b/main.go index 6da8d56..dd1f80a 100644 --- a/main.go +++ b/main.go @@ -19,9 +19,12 @@ var localSID uint32 var remoteSID uint32 var sendSeq uint16 var authSendSeq uint16 +var authInnerSendSeq uint16 var authID [6]byte var randIDByteForPktSeven [1]byte var expectedPkt7ReplySeq uint16 +var reauthSent bool +var lastReauthAt time.Time func send(d []byte) { _, err := conn.Write(d) @@ -97,6 +100,7 @@ func sendPkt6() { } func sendPktLogin() { + // The reply to the login packet will contain a 6 bytes long auth ID with the first 2 bytes set to our randID. var randID [2]byte _, err := rand.Read(randID[:]) if err != nil { @@ -105,8 +109,8 @@ func sendPktLogin() { send([]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), - 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, byte(authSendSeq), - byte(authSendSeq >> 8), 0x00, randID[0], randID[1], 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, byte(authInnerSendSeq), + byte(authInnerSendSeq >> 8), 0x00, randID[0], randID[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -115,13 +119,23 @@ func sendPktLogin() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x3f, 0x55, 0x5c, 0x3f, 0x25, 0x77, 0x58, // pass: beerbeer 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x69, 0x63, 0x6f, 0x6d, 0x2d, 0x70, 0x63, 0x00, // icom-pc + 0x69, 0x63, 0x6f, 0x6d, 0x2d, 0x70, 0x63, 0x00, // icom-pc in plain text 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + authSendSeq++ + authInnerSendSeq++ } func sendPktReauth() { + var magic byte + + if reauthSent { + magic = 0x05 + } else { + magic = 0x02 + } + // Example request from PC: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, // 0xbb, 0x41, 0x3f, 0x2b, 0xe6, 0xb2, 0x7b, 0x7b, // 0x00, 0x00, 0x00, 0x30, 0x01, 0x05, 0x00, 0x02, @@ -138,23 +152,27 @@ func sendPktReauth() { // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - send([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(sendSeq), byte(sendSeq >> 8), + send([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(authSendSeq), byte(authSendSeq >> 8), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), - 0x00, 0x00, 0x00, 0x30, 0x01, 0x05, 0x00, byte(authSendSeq), - byte(authSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5], + 0x00, 0x00, 0x00, 0x30, 0x01, magic, 0x00, byte(authInnerSendSeq), + byte(authInnerSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + reauthSent = true + authSendSeq++ + authInnerSendSeq++ + lastReauthAt = time.Now() } func sendDisconnect() { send([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(sendSeq), byte(sendSeq >> 8), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), - 0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, byte(authSendSeq), - byte(authSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5], + 0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, byte(authInnerSendSeq), + byte(authInnerSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -165,15 +183,16 @@ func sendDisconnect() { } func sendRequestSerialAndAudio() { - send([]byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00, byte(sendSeq), byte(sendSeq >> 8), + log.Print("requesting serial and audio stream") + send([]byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00, byte(authSendSeq), byte(authSendSeq >> 8), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID), - 0x00, 0x00, 0x00, 0x80, 0x01, 0x03, 0x00, byte(authSendSeq), - byte(authSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5], + 0x00, 0x00, 0x00, 0x80, 0x01, 0x03, 0x00, byte(authInnerSendSeq), + byte(authInnerSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01, // The last 5 bytes from this row can be acquired from a reply starting with 0xa8 pr 0x90 + 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01, // The last 5 bytes from this row can be acquired from a reply starting with 0xa8 or 0x90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00, // IC-705 + 0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00, // IC-705 in plain text 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -183,6 +202,8 @@ func sendRequestSerialAndAudio() { 0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0xc3, 0x52, 0x00, 0x00, 0xc3, 0x53, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + authSendSeq++ + authInnerSendSeq++ } func main() { @@ -196,14 +217,15 @@ func main() { if err != nil { log.Fatal(err) } - conn, err = net.DialUDP("udp", nil, raddr) + laddr := net.UDPAddr{ + Port: int(connectPort), + } + conn, err = net.DialUDP("udp", &laddr, raddr) if err != nil { log.Fatal(err) } - // Constructing the local session ID by combining the local IP address and port. - laddr := conn.LocalAddr().(*net.UDPAddr) - localSID = binary.BigEndian.Uint32(laddr.IP[len(laddr.IP)-4:])<<16 | uint32(laddr.Port&0xffff) + localSID = uint32(time.Now().Unix()) log.Debugf("using session id %.8x", localSID) sendPkt3() @@ -216,7 +238,7 @@ func main() { // Expecting a Pkt4 answer. // Example answer from radio: 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x7d, 0x45, 0x7a, 0x1d, 0xf6, 0xe9, 0x0b r, _ := read() - if bytes.Equal(r[:8], []byte{0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}) { + if len(r) == 16 && bytes.Equal(r[:8], []byte{0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}) { remoteSID = binary.BigEndian.Uint32(r[8:12]) break } @@ -224,16 +246,27 @@ func main() { log.Debugf("got remote session id %.8x", remoteSID) - sendSeq = 1 authSendSeq = 1 + authInnerSendSeq = 0x50 sendPkt6() - sendPktLogin() - authSendSeq++ + for { + // Expecting a Pkt6 answer. + r, _ := read() + if len(r) == 16 && bytes.Equal(r[:8], []byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00}) { + remoteSID = binary.BigEndian.Uint32(r[8:12]) + break + } + } + + sendPktLogin() + sendSeq = 5 + + var authOk bool var lastPingAt time.Time - var lastReauthAt time.Time var lastStatusLog time.Time var errCount int + var gotFirstReauthAnswer bool _, err = rand.Read(randIDByteForPktSeven[:]) if err != nil { @@ -263,14 +296,22 @@ func main() { // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - if len(r) == 96 && bytes.Equal(r[:8], []byte{0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}) { - if bytes.Equal(r[48:52], []byte{0xff, 0xff, 0xff, 0xfe}) { - log.Fatal("invalid user/password") - } else { - copy(authID[:], r[26:32]) - log.Print("auth ok") + if !authOk { + if len(r) == 96 && bytes.Equal(r[:8], []byte{0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}) { + if bytes.Equal(r[48:52], []byte{0xff, 0xff, 0xff, 0xfe}) { + log.Fatal("invalid user/password") + } else { + authOk = true + copy(authID[:], r[26:32]) + log.Print("auth ok") + + sendPktReauth() + time.AfterFunc(time.Second*3, sendRequestSerialAndAudio) + } } + continue } + if len(r) == 21 && bytes.Equal(r[1:6], []byte{0x00, 0x00, 0x00, 0x07, 0x00}) { gotSeq := binary.LittleEndian.Uint16(r[6:8]) if r[16] == 0x00 { // This is a pkt7 request from the radio. @@ -299,6 +340,27 @@ func main() { gotSeq := binary.LittleEndian.Uint16(r[6:8]) send([]byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, byte(gotSeq), byte(gotSeq >> 8), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)}) } + // if len(r) == 144 && bytes.Equal(r[:6], []byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00}) { + // } + if !gotFirstReauthAnswer && len(r) == 64 && bytes.Equal(r[:6], []byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00}) { // TODO + gotFirstReauthAnswer = true + } + if len(r) == 80 && bytes.Equal(r[:6], []byte{0x50, 0x00, 0x00, 0x00, 0x00, 0x00}) && bytes.Equal(r[48:51], []byte{0xff, 0xff, 0xff}) { + // Example answer from radio: 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + // 0x86, 0x1f, 0x2f, 0xcc, 0x03, 0x03, 0x89, 0x29, + // 0x00, 0x00, 0x00, 0x40, 0x02, 0x03, 0x00, 0x52, + // 0x00, 0x00, 0xf8, 0xad, 0x06, 0x8d, 0xda, 0x7b, + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + // 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01, + // 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + log.Error("reauth failed") + sendDisconnect() + os.Exit(1) + } if time.Since(lastPingAt) >= 100*time.Millisecond { sendPkt7(nil, sendSeq) @@ -306,10 +368,8 @@ func main() { sendSeq++ lastPingAt = time.Now() - if time.Since(lastReauthAt) >= 60*time.Second { + if authOk && time.Since(lastReauthAt) >= 60*time.Second { sendPktReauth() - authSendSeq++ - lastReauthAt = time.Now() } if time.Since(lastStatusLog) >= 10*time.Second {