tftp.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package tftp
  2. import (
  3. "errors"
  4. "io"
  5. "log"
  6. "strconv"
  7. "sync"
  8. "time"
  9. tftplib "github.com/pin/tftp/v3"
  10. "imuslab.com/arozos/mod/database"
  11. "imuslab.com/arozos/mod/user"
  12. )
  13. const (
  14. // Maximum file size allowed for TFTP transfer (32MB)
  15. MAX_FILE_SIZE = 32 * 1024 * 1024
  16. )
  17. // Handler is the handler for the TFTP server defined in arozos
  18. type Handler struct {
  19. ServerName string
  20. Port int
  21. ServerRunning bool
  22. userHandler *user.UserHandler
  23. server *tftplib.Server
  24. cancelFunc func()
  25. }
  26. type tftpDriver struct {
  27. userHandler *user.UserHandler
  28. tmpFolder string
  29. connectedUserList *sync.Map
  30. db *database.Database
  31. }
  32. // NewTFTPHandler creates a new handler for TFTP Server
  33. func NewTFTPHandler(userHandler *user.UserHandler, ServerName string, Port int, tmpFolder string) (*Handler, error) {
  34. //Create table for tftp if it doesn't exists
  35. db := userHandler.GetDatabase()
  36. db.NewTable("tftp")
  37. driver := &tftpDriver{
  38. userHandler: userHandler,
  39. tmpFolder: tmpFolder,
  40. connectedUserList: &sync.Map{},
  41. db: db,
  42. }
  43. // Create a new TFTP Server instance
  44. server := tftplib.NewServer(driver.readHandler, driver.writeHandler)
  45. server.SetTimeout(5 * time.Second)
  46. return &Handler{
  47. ServerName: ServerName,
  48. Port: Port,
  49. ServerRunning: false,
  50. userHandler: userHandler,
  51. server: server,
  52. }, nil
  53. }
  54. // Start the TFTP Server
  55. func (h *Handler) Start() error {
  56. if h.server != nil {
  57. addr := ":" + strconv.Itoa(h.Port)
  58. log.Println("[TFTP] Server Started, listening at: " + strconv.Itoa(h.Port))
  59. go func() {
  60. err := h.server.ListenAndServe(addr)
  61. if err != nil {
  62. log.Println("[TFTP] Server error:", err)
  63. }
  64. }()
  65. h.ServerRunning = true
  66. return nil
  67. } else {
  68. return errors.New("TFTP server not initiated")
  69. }
  70. }
  71. // Close the TFTP Server
  72. func (h *Handler) Close() {
  73. if h.server != nil {
  74. h.server.Shutdown()
  75. h.ServerRunning = false
  76. }
  77. }
  78. // readHandler handles TFTP read requests (GET)
  79. func (d *tftpDriver) readHandler(filename string, rf io.ReaderFrom) error {
  80. // Get default user for TFTP access
  81. // Since TFTP doesn't have authentication, we use a configured default user
  82. username := ""
  83. if d.db.KeyExists("tftp", "defaultUser") {
  84. d.db.Read("tftp", "defaultUser", &username)
  85. }
  86. if username == "" {
  87. return errors.New("no default user configured for TFTP access")
  88. }
  89. // Get user info
  90. userinfo, err := d.userHandler.GetUserInfoFromUsername(username)
  91. if err != nil {
  92. return errors.New("default user not found")
  93. }
  94. // Create arozfs adapter
  95. afs := &aofs{
  96. userinfo: userinfo,
  97. tmpFolder: d.tmpFolder,
  98. }
  99. // Open file for reading
  100. file, err := afs.Open(filename)
  101. if err != nil {
  102. log.Printf("[TFTP] READ: Failed to open %s: %v", filename, err)
  103. return err
  104. }
  105. defer file.Close()
  106. // Get file info
  107. fileInfo, err := file.Stat()
  108. if err != nil {
  109. return err
  110. }
  111. // TFTP has a size limit (typically for smaller files)
  112. // We'll allow up to 32MB
  113. if fileInfo.Size() > MAX_FILE_SIZE {
  114. return errors.New("file too large for TFTP transfer")
  115. }
  116. n, err := rf.ReadFrom(file)
  117. if err != nil {
  118. log.Printf("[TFTP] READ: Transfer error for %s: %v", filename, err)
  119. return err
  120. }
  121. log.Printf("[TFTP] READ: Sent %s (%d bytes)", filename, n)
  122. return nil
  123. }
  124. // writeHandler handles TFTP write requests (PUT)
  125. func (d *tftpDriver) writeHandler(filename string, wt io.WriterTo) error {
  126. // Get default user for TFTP access
  127. username := ""
  128. if d.db.KeyExists("tftp", "defaultUser") {
  129. d.db.Read("tftp", "defaultUser", &username)
  130. }
  131. if username == "" {
  132. return errors.New("no default user configured for TFTP access")
  133. }
  134. // Get user info
  135. userinfo, err := d.userHandler.GetUserInfoFromUsername(username)
  136. if err != nil {
  137. return errors.New("default user not found")
  138. }
  139. // Create arozfs adapter
  140. afs := &aofs{
  141. userinfo: userinfo,
  142. tmpFolder: d.tmpFolder,
  143. }
  144. // Check if user can write
  145. file, err := afs.Create(filename)
  146. if err != nil {
  147. log.Printf("[TFTP] WRITE: Failed to create %s: %v", filename, err)
  148. return err
  149. }
  150. defer file.Close()
  151. n, err := wt.WriteTo(file)
  152. if err != nil {
  153. log.Printf("[TFTP] WRITE: Transfer error for %s: %v", filename, err)
  154. return err
  155. }
  156. log.Printf("[TFTP] WRITE: Received %s (%d bytes)", filename, n)
  157. return nil
  158. }