diff --git a/README.md b/README.md index 1c197fe..ff7f714 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,6 @@ go install https://github.com/nonoo/kappanhang - Make sure network settings (on the Icom IC-705 in: `Menu -> Set -> WLAN set -> Remote settings`) are the following: - **Network control** is turned on. - - **Network user 1** username is `beer` and the password is `beerbeer`. - These are fixed as the password encoding of the RS-BA1 protocol has not - been decrypted yet. See [passcode.txt](passcode.txt) for more information. - **UDP ports** are on their default values: - Control port: `50001` - Serial port: `50002` @@ -48,7 +45,9 @@ You can get the available command line parameters with the `-h` command line argument. If no command line arguments are set, then the app will try to connect to the -host **ic-705** (ic-705.local or ic-705.localdomain). +host **ic-705** (ic-705.local or ic-705.localdomain) with the username `beer` +and password `beerbeer`. You can set the username with the `-u` and the +password with the `-p` command line arguments. After it is connected and logged in: diff --git a/args.go b/args.go index 3a5f328..4846c66 100644 --- a/args.go +++ b/args.go @@ -10,6 +10,8 @@ import ( var verboseLog bool var connectAddress string +var username string +var password string var serialTCPPort uint16 var enableSerialDevice bool var rigctldModel uint @@ -22,6 +24,8 @@ func parseArgs() { h := getopt.BoolLong("help", 'h', "display help") v := getopt.BoolLong("verbose", 'v', "Enable verbose (debug) logging") a := getopt.StringLong("address", 'a', "IC-705", "Connect to address") + u := getopt.StringLong("username", 'u', "beer", "Username") + p := getopt.StringLong("password", 'p', "beerbeer", "Password") t := getopt.Uint16Long("serial-tcp-port", 't', 4533, "Expose radio's serial port on this TCP port") s := getopt.BoolLong("enable-serial-device", 's', "Expose radio's serial port as a virtual serial port") m := getopt.UintLong("rigctld-model", 'm', 3085, "rigctld model number") @@ -40,6 +44,8 @@ func parseArgs() { verboseLog = *v connectAddress = *a + username = *u + password = *p serialTCPPort = *t enableSerialDevice = *s rigctldModel = *m diff --git a/controlstream.go b/controlstream.go index 1ac8452..8a6fbf5 100644 --- a/controlstream.go +++ b/controlstream.go @@ -43,6 +43,8 @@ func (s *controlStream) sendPktLogin() error { if _, err := rand.Read(authStartID[:]); err != nil { return err } + usernameEncoded := passcode(username) + passwordEncoded := passcode(password) p := []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, byte(s.common.localSID >> 24), byte(s.common.localSID >> 16), byte(s.common.localSID >> 8), byte(s.common.localSID), byte(s.common.remoteSID >> 24), byte(s.common.remoteSID >> 16), byte(s.common.remoteSID >> 8), byte(s.common.remoteSID), @@ -52,10 +54,14 @@ func (s *controlStream) sendPktLogin() error { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer - 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, + usernameEncoded[0], usernameEncoded[1], usernameEncoded[2], usernameEncoded[3], + usernameEncoded[4], usernameEncoded[5], usernameEncoded[6], usernameEncoded[7], + usernameEncoded[8], usernameEncoded[9], usernameEncoded[10], usernameEncoded[11], + usernameEncoded[12], usernameEncoded[13], usernameEncoded[14], usernameEncoded[15], + passwordEncoded[0], passwordEncoded[1], passwordEncoded[2], passwordEncoded[3], + passwordEncoded[4], passwordEncoded[5], passwordEncoded[6], passwordEncoded[7], + passwordEncoded[8], passwordEncoded[9], passwordEncoded[10], passwordEncoded[11], + passwordEncoded[12], passwordEncoded[13], passwordEncoded[14], passwordEncoded[15], 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, @@ -107,6 +113,7 @@ func (s *controlStream) sendRequestSerialAndAudio() error { txSeqBufLengthMs := uint16(txSeqBufLength.Milliseconds()) + usernameEncoded := passcode(username) p := []byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, byte(s.common.localSID >> 24), byte(s.common.localSID >> 16), byte(s.common.localSID >> 8), byte(s.common.localSID), byte(s.common.remoteSID >> 24), byte(s.common.remoteSID >> 16), byte(s.common.remoteSID >> 8), byte(s.common.remoteSID), @@ -120,8 +127,10 @@ func (s *controlStream) sendRequestSerialAndAudio() error { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + usernameEncoded[0], usernameEncoded[1], usernameEncoded[2], usernameEncoded[3], + usernameEncoded[4], usernameEncoded[5], usernameEncoded[6], usernameEncoded[7], + usernameEncoded[8], usernameEncoded[9], usernameEncoded[10], usernameEncoded[11], + usernameEncoded[12], usernameEncoded[13], usernameEncoded[14], usernameEncoded[15], 0x01, 0x01, 0x04, 0x04, 0x00, 0x00, byte(audioSampleRate >> 8), byte(audioSampleRate & 0xff), 0x00, 0x00, byte(audioSampleRate >> 8), byte(audioSampleRate & 0xff), 0x00, 0x00, byte(serialStreamPort >> 8), byte(serialStreamPort & 0xff), @@ -341,7 +350,7 @@ func (s *controlStream) init() error { return err } if bytes.Equal(r[48:52], []byte{0xff, 0xff, 0xff, 0xfe}) { - return errors.New("invalid user/password") + return errors.New("invalid username/password") } s.common.pkt7.startPeriodicSend(&s.common, 2, false) diff --git a/main.go b/main.go index 23ada92..1f97dca 100644 --- a/main.go +++ b/main.go @@ -58,6 +58,9 @@ func runControlStream(osSignal chan os.Signal) (requireWait, shouldExit bool, ex if err := ctrl.init(); err != nil { log.Error(err) ctrl.deinit() + if strings.Contains(err.Error(), "invalid username/password") { + return false, true, 1 + } return } diff --git a/passcode.go b/passcode.go new file mode 100644 index 0000000..5096cbd --- /dev/null +++ b/passcode.go @@ -0,0 +1,107 @@ +package main + +var sequence = map[int]byte{ + 32: 0x47, + 33: 0x5d, + 34: 0x4c, + 35: 0x42, + 36: 0x66, + 37: 0x20, + 38: 0x23, + 39: 0x46, + 40: 0x4e, + 41: 0x57, + 42: 0x45, + 43: 0x3d, + 44: 0x67, + 45: 0x76, + 46: 0x60, + 47: 0x41, + 48: 0x62, + 49: 0x39, + 50: 0x59, + 51: 0x2d, + 52: 0x68, + 53: 0x7e, + 54: 0x7c, + 55: 0x65, + 56: 0x7d, + 57: 0x49, + 58: 0x29, + 59: 0x72, + 60: 0x73, + 61: 0x78, + 62: 0x21, + 63: 0x6e, + 64: 0x5a, + 65: 0x5e, + 66: 0x4a, + 67: 0x3e, + 68: 0x71, + 69: 0x2c, + 70: 0x2a, + 71: 0x54, + 72: 0x3c, + 73: 0x3a, + 74: 0x63, + 75: 0x4f, + 76: 0x43, + 77: 0x75, + 78: 0x27, + 79: 0x79, + 80: 0x5b, + 81: 0x35, + 82: 0x70, + 83: 0x48, + 84: 0x6b, + 85: 0x56, + 86: 0x6f, + 87: 0x34, + 88: 0x32, + 89: 0x6c, + 90: 0x30, + 91: 0x61, + 92: 0x6d, + 93: 0x7b, + 94: 0x2f, + 95: 0x4b, + 96: 0x64, + 97: 0x38, + 98: 0x2b, + 99: 0x2e, + 100: 0x50, + 101: 0x40, + 102: 0x3f, + 103: 0x55, + 104: 0x33, + 105: 0x37, + 106: 0x25, + 107: 0x77, + 108: 0x24, + 109: 0x26, + 110: 0x74, + 111: 0x6a, + 112: 0x28, + 113: 0x53, + 114: 0x4d, + 115: 0x69, + 116: 0x22, + 117: 0x5c, + 118: 0x44, + 119: 0x31, + 120: 0x36, + 121: 0x58, + 122: 0x3b, + 123: 0x7a, + 124: 0x51, + 125: 0x5f, + 126: 0x52, +} + +func passcode(s string) (res []byte) { + res = make([]byte, 16) + for i := 0; i < len(s) && i < len(res); i++ { + res[i] = sequence[int(s[i])+i] + } + return res +} diff --git a/passcode.txt b/passcode.txt deleted file mode 100644 index 990b6d3..0000000 --- a/passcode.txt +++ /dev/null @@ -1,101 +0,0 @@ -The following coding is used by the Icom software for encoding usernames and -passwords in login packets. Columns are: ASCII decimal, character, encoded -character. This listing is only valid for the first character. Subsequent -characters are encoded to different values, and the algorithm is currently -unknown. - -32 space 0x47 -33 ! 0x5d -34 " 0x4c -35 # 0x42 -36 $ 0x66 -37 % 0x20 -38 & 0x23 -39 ' 0x46 -40 ( 0x4e -41 ) 0x57 -42 * 0x45 -43 + 0x3d -44 , 0x67 -45 - 0x76 -46 . 0x60 -47 / 0x41 -48 0 0x62 -49 1 0x39 -50 2 0x59 -51 3 0x2d -52 4 0x68 -53 5 0x7e -54 6 0x7c -55 7 0x65 -56 8 0x7d -57 9 0x49 -58 : 0x29 -59 ; 0x72 -60 < 0x73 -61 = 0x78 -62 > 0x21 -63 ? 0x6e -64 @ 0x5a -65 A 0x5e -66 B 0x4a -67 C 0x3e -68 D 0x71 -69 E 0x2c -70 F 0x2a -71 G 0x54 -72 H 0x3c -73 I 0x3a -74 J 0x63 -75 K 0x4f -76 L 0x43 -77 M 0x75 -78 N 0x27 -79 O 0x79 -80 P 0x5b -81 Q 0x35 -82 R 0x70 -83 S 0x48 -84 T 0x6b -85 U 0x56 -86 V 0x6f -87 W 0x34 -88 X 0x32 -89 Y 0x6c -90 Z 0x30 -91 [ 0x61 -92 \ 0x6d -93 ] 0x7b -94 ^ 0x2f -95 _ 0x4b -96 ` 0x64 -97 a 0x38 -98 b 0x2b -99 c 0x2e -100 d 0x50 -101 e 0x40 -102 f 0x3f -103 g 0x55 -104 h 0x33 -105 i 0x37 -106 j 0x25 -107 k 0x77 -108 l 0x24 -109 m 0x26 -110 n 0x74 -111 o 0x6a -112 p 0x28 -113 q 0x53 -114 r 0x4d -115 s 0x69 -116 t 0x22 -117 u 0x5c -118 v 0x44 -119 w 0x31 -120 x 0x36 -121 y 0x58 -122 z 0x3b -123 { 0x7a -124 | 0x51 -125 } 0x5f -126 ~ 0x52 diff --git a/pkt0.go b/pkt0.go index 6fd898a..c9aa4ff 100644 --- a/pkt0.go +++ b/pkt0.go @@ -36,7 +36,7 @@ func (p *pkt0Type) retransmitRange(s *streamCommon, start, end uint16) error { return err } } else { - log.Debug(s.name+"/can't retransmit #", start, " - not found") + log.Debug(s.name+"/can't retransmit #", start, " - not found ") // Sending an idle with the requested seqnum. if err := p.sendIdle(s, false, start); err != nil {