oftp.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package main
  2. import (
  3. "os"
  4. "time"
  5. "encoding/json"
  6. "encoding/binary"
  7. "net"
  8. "fmt"
  9. "errors"
  10. )
  11. func (o *Oftp) New(filename string) error {
  12. // Set default values
  13. newOftp := Oftp{
  14. LocalCode: "LOCALCODE",
  15. LocalPassword: "LOCALPWD",
  16. PartnerCode: "1234567890CODE",
  17. PartnerPassword: "SUPERSECRET",
  18. OftpLevel: 4,
  19. OftpBuffer: 512,
  20. OftpDuplex: "S",
  21. OftpCompression: "N",
  22. OftpRestart: "N",
  23. OftpCredit: 7,
  24. OftpAuthentication: "N",
  25. NetworkHost: "localhost",
  26. NetworkPort: 3305,
  27. NetworkTLS: false,
  28. }
  29. f, err := os.Open(filename)
  30. if err != nil {
  31. return err
  32. }
  33. defer f.Close()
  34. d := json.NewDecoder(f)
  35. if err := d.Decode(&newOftp); err != nil {
  36. return err
  37. }
  38. *o = newOftp
  39. return nil
  40. }
  41. func (o Oftp) Call() error {
  42. // 1. Open connection
  43. // 2. Wait for SSRM
  44. // 3. Send SSID
  45. // 4. Wait for SSID
  46. // 5. Validate SSID
  47. // 6. Send ESID
  48. // 1. Open connection
  49. addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort))
  50. if err != nil {
  51. return err
  52. }
  53. conn, err := net.DialTCP("tcp", nil, addr)
  54. if err != nil {
  55. return err
  56. }
  57. defer conn.Close()
  58. fmt.Printf("Connected to %s\n", addr.String())
  59. // 2. Wait for SSRM
  60. headerBuf := make([]byte, 4)
  61. dataBuf := make([]byte, o.OftpBuffer)
  62. // Read STH (header)
  63. readCnt, err := conn.Read(headerBuf)
  64. if err != nil {
  65. conn.Close()
  66. return err
  67. }
  68. length, err := parseSTH(headerBuf[:4])
  69. if err != nil {
  70. conn.Close()
  71. return err
  72. }
  73. fmt.Printf("STH says STB is %d long\n", length)
  74. // Read OFTP command
  75. readCnt, err = conn.Read(dataBuf)
  76. if err != nil {
  77. conn.Close()
  78. return err
  79. }
  80. fmt.Printf("Read %d, should be %d\n", readCnt, length - 4)
  81. if string(dataBuf[:readCnt]) != "IODETTE FTP READY \r" && string(dataBuf[:readCnt]) != "IODETTE FTP READY \n"{
  82. conn.Close()
  83. return errors.New(fmt.Sprintf("Expected SSRM (%x), got %x", "IODETTE FTP READY \r", dataBuf[:readCnt]))
  84. }
  85. // 3. Send SSID
  86. fmt.Println(string(o.LocalSSID()))
  87. writtenCnt, err := conn.Write(o.LocalSSID())
  88. if err != nil {
  89. conn.Close()
  90. return err
  91. }
  92. fmt.Printf("Write %d bytes to %s\n", writtenCnt, addr.String())
  93. // 4. Wait for SSID
  94. // Read STH (header)
  95. readCnt, err = conn.Read(headerBuf)
  96. if err != nil {
  97. conn.Close()
  98. return err
  99. }
  100. length, err = parseSTH(headerBuf[:4])
  101. if err != nil {
  102. conn.Close()
  103. return err
  104. }
  105. fmt.Printf("STH says STB is %d long\n", length)
  106. // Read OFTP command
  107. readCnt, err = conn.Read(dataBuf)
  108. if err != nil {
  109. conn.Close()
  110. return err
  111. }
  112. fmt.Printf("Read %d, should be %d\n", readCnt, length - 4)
  113. // 5. Validate SSID
  114. ESIDCode := o.ValidateSSID(dataBuf[:readCnt]);
  115. if ESIDCode < 0 {
  116. // If ESID is received, disconnect
  117. conn.Close()
  118. return err
  119. }
  120. // 6. Send ESID
  121. fmt.Println(string(o.ESID(ESIDCode)))
  122. writtenCnt, err = conn.Write(o.ESID(ESIDCode))
  123. if err != nil {
  124. conn.Close()
  125. return err
  126. }
  127. fmt.Printf("Write %d bytes to %s\n", writtenCnt, addr.String())
  128. // Wait for partner to disconnect
  129. conn.SetReadDeadline(time.Now().Add(10 * time.Second))
  130. conn.Read(dataBuf)
  131. conn.Close()
  132. return nil
  133. }
  134. func (o Oftp) LocalSSID() []byte {
  135. dataBuf := [61]byte{}
  136. copy(dataBuf[0:1], "X")
  137. copy(dataBuf[1:2], fmt.Sprintf("%d", o.OftpLevel))
  138. copy(dataBuf[2:27], o.LocalCode)
  139. copy(dataBuf[27:35], o.LocalPassword)
  140. copy(dataBuf[35:40], fmt.Sprintf("%05d", o.OftpBuffer))
  141. copy(dataBuf[40:41], o.OftpDuplex)
  142. copy(dataBuf[41:42], o.OftpCompression)
  143. copy(dataBuf[42:43], o.OftpRestart)
  144. copy(dataBuf[43:44], "N")
  145. copy(dataBuf[44:47], fmt.Sprintf("%03d", o.OftpCredit))
  146. copy(dataBuf[47:48], o.OftpAuthentication)
  147. copy(dataBuf[60:61], "\r")
  148. sth := buildSTH(len(dataBuf))
  149. stb := []byte{}
  150. stb = append(stb, sth...)
  151. stb = append(stb, dataBuf[:]...)
  152. return stb
  153. }
  154. func (o Oftp) ESID(code int) []byte {
  155. dataBuf := [7]byte{}
  156. copy(dataBuf[0:1], "F")
  157. copy(dataBuf[1:3], fmt.Sprintf("%02d", code))
  158. copy(dataBuf[3:6], fmt.Sprintf("%03d", 0))
  159. copy(dataBuf[6:7], "\r")
  160. sth := buildSTH(len(dataBuf))
  161. stb := []byte{}
  162. stb = append(stb, sth...)
  163. stb = append(stb, dataBuf[:]...)
  164. return stb
  165. }
  166. func (o Oftp) ValidateSSID(SSIDBytes []byte) int {
  167. // Validate cmd, code and password only
  168. fmt.Println(string(SSIDBytes))
  169. cmdByte := string(SSIDBytes[0:1])
  170. if cmdByte != "X" {
  171. return -1
  172. }
  173. codeBytes := string(SSIDBytes[2:27])
  174. if codeBytes != fmt.Sprintf("%-25s", o.PartnerCode) {
  175. return 3
  176. }
  177. passwordBytes := string(SSIDBytes[27:35])
  178. if passwordBytes != fmt.Sprintf("%-8s", o.PartnerPassword) {
  179. return 4
  180. }
  181. return 0
  182. }
  183. func parseSTH(sth []byte) (int32, error) {
  184. sth[0] = 0
  185. length := binary.BigEndian.Uint32(sth)
  186. return int32(length), nil
  187. }
  188. func buildSTH(length int) []byte {
  189. sth := make([]byte, 4)
  190. sth[0] = 16
  191. lengthBytes := make([]byte, 4)
  192. binary.BigEndian.PutUint32(lengthBytes, uint32(length + 4))
  193. copy(sth[1:4], lengthBytes[1:4])
  194. return sth
  195. }