| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- package main
- import (
- "crypto/tls"
- "encoding/binary"
- "encoding/json"
- "errors"
- "fmt"
- "net"
- "os"
- "strconv"
- "time"
- )
- func (o *Oftp) New(filename string) error {
- // Set default values
- newOftp := Oftp{
- LocalCode: "LOCALCODE",
- LocalPassword: "LOCALPWD",
- PartnerCode: "1234567890CODE",
- PartnerPassword: "SUPERSECRET",
- OftpLevel: 4,
- OftpBuffer: 512,
- OftpDuplex: "S",
- OftpCompression: "N",
- OftpRestart: "N",
- OftpCredit: 7,
- OftpAuthentication: "N",
- NetworkHost: "localhost",
- NetworkPort: 3305,
- NetworkTimeout: 10,
- NetworkTLS: false,
- }
- f, err := os.Open(filename)
- if err != nil {
- return err
- }
- defer f.Close()
- d := json.NewDecoder(f)
- if err := d.Decode(&newOftp); err != nil {
- return err
- }
- *o = newOftp
- return nil
- }
- func (o Oftp) Call() error {
- // 1. Open connection
- // 2. Wait for SSRM
- // 3. Send SSID
- // 4. Wait for SSID
- // 5. Validate SSID
- // 6. Send ESID
- // 1. Open connection
- var conn net.Conn
- var err error
- if o.NetworkTLS {
- netDialer := &net.Dialer{
- Timeout: time.Duration(o.NetworkTimeout) * time.Second,
- }
- tlsConfig := &tls.Config{
- InsecureSkipVerify: true,
- }
- conn, err = tls.DialWithDialer(netDialer, "tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort), tlsConfig)
- if err != nil {
- return err
- }
- defer conn.Close()
- } else {
- conn, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", o.NetworkHost, o.NetworkPort), time.Duration(o.NetworkTimeout)*time.Second)
- if err != nil {
- return err
- }
- defer conn.Close()
- }
- fmt.Printf("Connected to %s:%d\n", o.NetworkHost, o.NetworkPort)
- // 2. Wait for SSRM
- headerBuf := make([]byte, 4)
- dataBuf := make([]byte, o.OftpBuffer)
- // Read STH (header)
- readCnt, err := conn.Read(headerBuf)
- if err != nil {
- conn.Close()
- return err
- }
- _, err = parseSTH(headerBuf[:4])
- if err != nil {
- conn.Close()
- return err
- }
- // Read OFTP command
- readCnt, err = conn.Read(dataBuf)
- if err != nil {
- conn.Close()
- return err
- }
- if string(dataBuf[:readCnt]) != "IODETTE FTP READY \r" && string(dataBuf[:readCnt]) != "IODETTE FTP READY \n" {
- conn.Close()
- return errors.New(fmt.Sprintf("Expected SSRM (%x), got %x", "IODETTE FTP READY \r", dataBuf[:readCnt]))
- }
- fmt.Printf("Received SSRM (%d)\n", readCnt)
- // 3. Send SSID
- writtenCnt, err := conn.Write(o.LocalSSID())
- if err != nil {
- conn.Close()
- return err
- }
- fmt.Printf("Sent SSID (%d)\n", writtenCnt)
- // 4. Wait for SSID
- // Read STH (header)
- readCnt, err = conn.Read(headerBuf)
- if err != nil {
- conn.Close()
- return err
- }
- _, err = parseSTH(headerBuf[:4])
- if err != nil {
- conn.Close()
- return err
- }
- // Read OFTP command
- readCnt, err = conn.Read(dataBuf)
- if err != nil {
- conn.Close()
- return err
- }
- // 5. Validate SSID
- ESIDCode := o.ValidateSSID(dataBuf[:readCnt])
- if ESIDCode < 0 {
- fmt.Println(ESIDCode)
- var err error
- if ESIDCode > -100 {
- // ESID error, disconnect
- err = errors.New(fmt.Sprintf("Received negative ESID with reason code %d", ESIDCode*-1))
- } else {
- err = errors.New("Bad non-ESID reply to SSID")
- }
- conn.Close()
- return err
- }
- fmt.Printf("Received SSID (%d)\n", readCnt)
- // 6. Send ESID
- writtenCnt, err = conn.Write(o.ESID(ESIDCode))
- if err != nil {
- conn.Close()
- return err
- }
- fmt.Printf("Sent ESID (%d) with code %d\n", writtenCnt, ESIDCode)
- // Wait for partner to disconnect
- conn.SetReadDeadline(time.Now().Add(10 * time.Second))
- conn.Read(dataBuf)
- conn.Close()
- fmt.Println("Disconnected")
- if ESIDCode != 0 {
- return errors.New(fmt.Sprintf("Ended session with ESID reason code %d", ESIDCode))
- }
- return nil
- }
- func (o Oftp) LocalSSID() []byte {
- dataBuf := [61]byte{}
- copy(dataBuf[0:1], "X")
- copy(dataBuf[1:2], fmt.Sprintf("%d", o.OftpLevel))
- copy(dataBuf[2:27], o.LocalCode)
- copy(dataBuf[27:35], o.LocalPassword)
- copy(dataBuf[35:40], fmt.Sprintf("%05d", o.OftpBuffer))
- copy(dataBuf[40:41], o.OftpDuplex)
- copy(dataBuf[41:42], o.OftpCompression)
- copy(dataBuf[42:43], o.OftpRestart)
- copy(dataBuf[43:44], "N")
- copy(dataBuf[44:47], fmt.Sprintf("%03d", o.OftpCredit))
- copy(dataBuf[47:48], o.OftpAuthentication)
- copy(dataBuf[60:61], "\r")
- sth := buildSTH(len(dataBuf))
- stb := []byte{}
- stb = append(stb, sth...)
- stb = append(stb, dataBuf[:]...)
- return stb
- }
- func (o Oftp) ESID(code int) []byte {
- dataBuf := [7]byte{}
- copy(dataBuf[0:1], "F")
- copy(dataBuf[1:3], fmt.Sprintf("%02d", code))
- copy(dataBuf[3:6], fmt.Sprintf("%03d", 0))
- copy(dataBuf[6:7], "\r")
- sth := buildSTH(len(dataBuf))
- stb := []byte{}
- stb = append(stb, sth...)
- stb = append(stb, dataBuf[:]...)
- return stb
- }
- func (o Oftp) ValidateSSID(SSIDBytes []byte) int {
- // Validate cmd, code and password only
- cmdByte := string(SSIDBytes[0:1])
- if cmdByte == "F" {
- ESIDCodeStr := string(SSIDBytes[1:3])
- ESIDCodeInt, _ := strconv.Atoi(ESIDCodeStr)
- return -1 * ESIDCodeInt
- }
- if cmdByte != "X" {
- return -100
- }
- codeBytes := string(SSIDBytes[2:27])
- if codeBytes != fmt.Sprintf("%-25s", o.PartnerCode) {
- return 3
- }
- passwordBytes := string(SSIDBytes[27:35])
- if passwordBytes != fmt.Sprintf("%-8s", o.PartnerPassword) {
- return 4
- }
- return 0
- }
- func parseSTH(sth []byte) (int32, error) {
- sth[0] = 0
- length := binary.BigEndian.Uint32(sth)
- return int32(length), nil
- }
- func buildSTH(length int) []byte {
- sth := make([]byte, 4)
- sth[0] = 16
- lengthBytes := make([]byte, 4)
- binary.BigEndian.PutUint32(lengthBytes, uint32(length+4))
- copy(sth[1:4], lengthBytes[1:4])
- return sth
- }
|