oftp.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. package main
  2. import (
  3. "crypto/tls"
  4. "encoding/binary"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "net"
  9. "os"
  10. "strconv"
  11. "time"
  12. )
  13. func (o *Oftp) New(filename string) error {
  14. // Set default values
  15. newOftp := Oftp{
  16. LocalCode: "LOCALCODE",
  17. LocalPassword: "LOCALPWD",
  18. PartnerCode: "1234567890CODE",
  19. PartnerPassword: "SUPERSECRET",
  20. OftpLevel: 4,
  21. OftpBuffer: 512,
  22. OftpDuplex: "S",
  23. OftpCompression: "N",
  24. OftpRestart: "N",
  25. OftpCredit: 7,
  26. OftpAuthentication: "N",
  27. NetworkHost: "localhost",
  28. NetworkPort: 3305,
  29. NetworkTimeout: 10,
  30. NetworkTLS: false,
  31. }
  32. f, err := os.Open(filename)
  33. if err != nil {
  34. return err
  35. }
  36. defer f.Close()
  37. d := json.NewDecoder(f)
  38. if err := d.Decode(&newOftp); err != nil {
  39. return err
  40. }
  41. *o = newOftp
  42. return nil
  43. }
  44. func (o Oftp) Call() error {
  45. // 1. Open connection
  46. // 2. Wait for SSRM
  47. // 3. Send SSID
  48. // 4. Wait for SSID
  49. // 5. Validate SSID
  50. // 6. Send ESID
  51. // 1. Open connection
  52. var conn net.Conn
  53. var err error
  54. if o.NetworkTLS {
  55. netDialer := &net.Dialer{
  56. Timeout: time.Duration(o.NetworkTimeout) * time.Second,
  57. }
  58. tlsConfig := &tls.Config{
  59. InsecureSkipVerify: true,
  60. }
  61. conn, err = tls.DialWithDialer(netDialer, "tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort), tlsConfig)
  62. if err != nil {
  63. return fmt.Errorf("Error connecting: %s", err)
  64. }
  65. defer conn.Close()
  66. } else {
  67. conn, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort), time.Duration(o.NetworkTimeout)*time.Second)
  68. if err != nil {
  69. return fmt.Errorf("Error connecting: %s", err)
  70. }
  71. defer conn.Close()
  72. }
  73. fmt.Printf("Connected to %s:%d\n", o.NetworkHost, o.NetworkPort)
  74. // 2. Wait for SSRM
  75. headerBuf := make([]byte, 4)
  76. dataBuf := make([]byte, o.OftpBuffer)
  77. // Read STH (header)
  78. conn.SetReadDeadline(time.Now().Add(time.Duration(o.NetworkTimeout) * time.Second))
  79. readCnt, err := conn.Read(headerBuf)
  80. if err != nil {
  81. conn.Close()
  82. return fmt.Errorf("Error reading SSRM stream header: %s", err)
  83. }
  84. _, err = parseSTH(headerBuf[:4])
  85. if err != nil {
  86. conn.Close()
  87. return fmt.Errorf("Error parsing SSRM stream header: %s", err)
  88. }
  89. // Read OFTP command
  90. conn.SetReadDeadline(time.Now().Add(time.Duration(o.NetworkTimeout) * time.Second))
  91. readCnt, err = conn.Read(dataBuf)
  92. if err != nil {
  93. conn.Close()
  94. return fmt.Errorf("Error reading SSRM: %s", err)
  95. }
  96. if string(dataBuf[:readCnt]) != "IODETTE FTP READY \r" && string(dataBuf[:readCnt]) != "IODETTE FTP READY \n" {
  97. conn.Close()
  98. return errors.New(fmt.Sprintf("Expected SSRM (%x), got %x", "IODETTE FTP READY \r", dataBuf[:readCnt]))
  99. }
  100. fmt.Printf("Received SSRM (%d)\n", readCnt)
  101. fmt.Printf("%x\n", o.LocalSSID())
  102. // 3. Send SSID
  103. conn.SetWriteDeadline(time.Now().Add(time.Duration(o.NetworkTimeout) * time.Second))
  104. writtenCnt, err := conn.Write(o.LocalSSID())
  105. if err != nil {
  106. conn.Close()
  107. return fmt.Errorf("Error writing SSID: %s", err)
  108. }
  109. fmt.Printf("Sent SSID (%d)\n", writtenCnt)
  110. // 4. Wait for SSID
  111. // Read STH (header)
  112. conn.SetReadDeadline(time.Now().Add(time.Duration(o.NetworkTimeout) * time.Second))
  113. readCnt, err = conn.Read(headerBuf)
  114. if err != nil {
  115. conn.Close()
  116. return fmt.Errorf("Error reading SSID stream header: %s", err)
  117. }
  118. _, err = parseSTH(headerBuf[:4])
  119. if err != nil {
  120. conn.Close()
  121. return fmt.Errorf("Error parsing SSID: %s", err)
  122. }
  123. // Read OFTP command
  124. conn.SetReadDeadline(time.Now().Add(time.Duration(o.NetworkTimeout) * time.Second))
  125. readCnt, err = conn.Read(dataBuf)
  126. if err != nil {
  127. conn.Close()
  128. return fmt.Errorf("Error reading SSID: %s", err)
  129. }
  130. // 5. Validate SSID
  131. ESIDCode := o.ValidateSSID(dataBuf[:readCnt])
  132. if ESIDCode < 0 {
  133. fmt.Println(ESIDCode)
  134. var err error
  135. if ESIDCode > -100 {
  136. // ESID error, disconnect
  137. err = errors.New(fmt.Sprintf("Received negative ESID with reason code %d", ESIDCode*-1))
  138. } else {
  139. err = errors.New("Bad non-ESID reply to SSID")
  140. }
  141. conn.Close()
  142. return err
  143. }
  144. fmt.Printf("Received SSID (%d)\n", readCnt)
  145. // 6. Send ESID
  146. conn.SetWriteDeadline(time.Now().Add(time.Duration(o.NetworkTimeout) * time.Second))
  147. writtenCnt, err = conn.Write(o.ESID(ESIDCode))
  148. if err != nil {
  149. conn.Close()
  150. return fmt.Errorf("Error writing ESID: %s", err)
  151. }
  152. fmt.Printf("Sent ESID (%d) with code %d\n", writtenCnt, ESIDCode)
  153. // Wait for partner to disconnect
  154. conn.SetReadDeadline(time.Now().Add(10 * time.Second))
  155. conn.Read(dataBuf)
  156. conn.Close()
  157. fmt.Println("Disconnected")
  158. if ESIDCode != 0 {
  159. return errors.New(fmt.Sprintf("Ended session with ESID reason code %d", ESIDCode))
  160. }
  161. return nil
  162. }
  163. func (o Oftp) LocalSSID() []byte {
  164. dataBuf := [61]byte{}
  165. copy(dataBuf[0:1], "X")
  166. copy(dataBuf[1:2], fmt.Sprintf("%d", o.OftpLevel))
  167. copy(dataBuf[2:27], fmt.Sprintf("%-25s", o.LocalCode))
  168. copy(dataBuf[27:35], fmt.Sprintf("%-8s", o.LocalPassword))
  169. copy(dataBuf[35:40], fmt.Sprintf("%05d", o.OftpBuffer))
  170. copy(dataBuf[40:41], o.OftpDuplex)
  171. copy(dataBuf[41:42], o.OftpCompression)
  172. copy(dataBuf[42:43], o.OftpRestart)
  173. copy(dataBuf[43:44], "N")
  174. copy(dataBuf[44:47], fmt.Sprintf("%03d", o.OftpCredit))
  175. if o.OftpLevel > 4 {
  176. copy(dataBuf[47:48], o.OftpAuthentication)
  177. copy(dataBuf[48:52], fmt.Sprintf("%-4s", ""))
  178. } else {
  179. copy(dataBuf[47:52], fmt.Sprintf("%-5s", ""))
  180. }
  181. copy(dataBuf[52:60], fmt.Sprintf("%-8s", ""))
  182. copy(dataBuf[60:61], "\r")
  183. sth := buildSTH(len(dataBuf))
  184. stb := []byte{}
  185. stb = append(stb, sth...)
  186. stb = append(stb, dataBuf[:]...)
  187. return stb
  188. }
  189. func (o Oftp) ESID(code int) []byte {
  190. dataBuf := [7]byte{}
  191. copy(dataBuf[0:1], "F")
  192. copy(dataBuf[1:3], fmt.Sprintf("%02d", code))
  193. copy(dataBuf[3:6], fmt.Sprintf("%03d", 0))
  194. copy(dataBuf[6:7], "\r")
  195. sth := buildSTH(len(dataBuf))
  196. stb := []byte{}
  197. stb = append(stb, sth...)
  198. stb = append(stb, dataBuf[:]...)
  199. return stb
  200. }
  201. func (o Oftp) ValidateSSID(SSIDBytes []byte) int {
  202. // Validate cmd, code and password only
  203. cmdByte := string(SSIDBytes[0:1])
  204. if cmdByte == "F" {
  205. ESIDCodeStr := string(SSIDBytes[1:3])
  206. ESIDCodeInt, _ := strconv.Atoi(ESIDCodeStr)
  207. return -1 * ESIDCodeInt
  208. }
  209. if cmdByte != "X" {
  210. return -100
  211. }
  212. codeBytes := string(SSIDBytes[2:27])
  213. if codeBytes != fmt.Sprintf("%-25s", o.PartnerCode) {
  214. return 3
  215. }
  216. passwordBytes := string(SSIDBytes[27:35])
  217. if passwordBytes != fmt.Sprintf("%-8s", o.PartnerPassword) {
  218. return 4
  219. }
  220. return 0
  221. }
  222. func parseSTH(sth []byte) (int32, error) {
  223. sth[0] = 0
  224. length := binary.BigEndian.Uint32(sth)
  225. return int32(length), nil
  226. }
  227. func buildSTH(length int) []byte {
  228. sth := make([]byte, 4)
  229. sth[0] = 16
  230. lengthBytes := make([]byte, 4)
  231. binary.BigEndian.PutUint32(lengthBytes, uint32(length+4))
  232. copy(sth[1:4], lengthBytes[1:4])
  233. return sth
  234. }