main.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. package main
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "flag"
  6. "fmt"
  7. "log"
  8. "net/http"
  9. "os"
  10. "os/signal"
  11. "sync"
  12. "syscall"
  13. "time"
  14. "proxmox-router/internal/api"
  15. "proxmox-router/internal/auth"
  16. "proxmox-router/internal/bridge"
  17. "proxmox-router/internal/bwtest"
  18. "proxmox-router/internal/certs"
  19. "proxmox-router/internal/cli"
  20. "proxmox-router/internal/dhcp"
  21. "proxmox-router/internal/dns"
  22. "proxmox-router/internal/dynamicrouting"
  23. "proxmox-router/internal/firewall"
  24. "proxmox-router/internal/logging"
  25. "proxmox-router/internal/network"
  26. "proxmox-router/internal/routing"
  27. "proxmox-router/internal/services"
  28. "proxmox-router/internal/tools"
  29. "proxmox-router/internal/vpn"
  30. "proxmox-router/internal/vrrp"
  31. "proxmox-router/internal/web"
  32. )
  33. func main() {
  34. addr := flag.String("addr", ":8080", "HTTP service address (e.g. :8080 or :80)")
  35. cliAddr := flag.String("cli-addr", ":8282", "CLI service address for Telnet and debtik-cli (e.g. :8282)")
  36. metaPath := flag.String("meta", "/etc/proxmox-router/metadata.json", "Path to interface metadata storage file")
  37. flag.Parse()
  38. // Initialize Logging Ring Buffer
  39. _ = logging.GetLogger()
  40. // Initialize components
  41. metaMgr := network.NewMetadataManager(*metaPath)
  42. netMgr := network.NewManager(metaMgr)
  43. persistMgr := network.NewPersistenceManager(netMgr)
  44. vpnMgr := vpn.NewManager()
  45. fwMgr := firewall.NewFirewallManager()
  46. routingMgr := routing.NewRoutingManager()
  47. defer routingMgr.Stop()
  48. dynRoutingMgr := dynamicrouting.NewManager("")
  49. bridgeMgr := bridge.NewBridgeManager()
  50. toolsMgr := tools.NewManager()
  51. dhcpMgr := dhcp.NewManager()
  52. dhcpServerMgr := dhcp.NewServerManager()
  53. vrrpMgr := vrrp.NewManager()
  54. bwtestMgr := bwtest.NewManager("")
  55. defer bwtestMgr.Stop()
  56. dnsMgr := dns.NewManager()
  57. authMgr := auth.NewManager("")
  58. servicesMgr := services.NewManager("")
  59. certMgr, err := certs.NewCertManager("")
  60. if err != nil {
  61. log.Fatalf("Failed to initialize certificate manager: %v", err)
  62. }
  63. webHandler := web.Handler()
  64. // Build Unified RouterOS CLI Executor
  65. cliExecutor := cli.NewExecutor(
  66. authMgr,
  67. netMgr,
  68. routingMgr,
  69. dynRoutingMgr,
  70. fwMgr,
  71. dhcpMgr,
  72. dhcpServerMgr,
  73. dnsMgr,
  74. bridgeMgr,
  75. vpnMgr,
  76. vrrpMgr,
  77. bwtestMgr,
  78. servicesMgr,
  79. certMgr,
  80. )
  81. // Determine Telnet & SSH addresses from services config or flags
  82. telnetAddr := *cliAddr
  83. if tSvc, ok := servicesMgr.GetService("telnet"); ok && tSvc.Port > 0 {
  84. telnetAddr = fmt.Sprintf(":%d", tSvc.Port)
  85. }
  86. sshAddr := ":2222"
  87. if sSvc, ok := servicesMgr.GetService("ssh"); ok && sSvc.Port > 0 {
  88. sshAddr = fmt.Sprintf(":%d", sSvc.Port)
  89. }
  90. cliTelnetServer := cli.NewServer(telnetAddr, authMgr, cliExecutor)
  91. cliSSHServer := cli.NewSSHServer(sshAddr, authMgr, cliExecutor)
  92. // Register hooks for dynamic service start/stop & port changes
  93. servicesMgr.RegisterHook("telnet", func(serviceName string, port int, disabled bool) error {
  94. cliTelnetServer.Stop()
  95. if !disabled {
  96. cliTelnetServer.SetAddr(fmt.Sprintf(":%d", port))
  97. go func() {
  98. if err := cliTelnetServer.Start(); err != nil {
  99. log.Printf("[CLI-Telnet] Listener error: %v", err)
  100. }
  101. }()
  102. }
  103. return nil
  104. })
  105. servicesMgr.RegisterHook("ssh", func(serviceName string, port int, disabled bool) error {
  106. cliSSHServer.Stop()
  107. if !disabled {
  108. cliSSHServer.SetAddr(fmt.Sprintf(":%d", port))
  109. go func() {
  110. if err := cliSSHServer.Start(); err != nil {
  111. log.Printf("[CLI-SSH] Listener error: %v", err)
  112. }
  113. }()
  114. }
  115. return nil
  116. })
  117. // Start enabled CLI servers
  118. if tSvc, ok := servicesMgr.GetService("telnet"); !ok || !tSvc.Disabled {
  119. go func() {
  120. if err := cliTelnetServer.Start(); err != nil {
  121. log.Printf("[CLI-Telnet] Server listener error: %v", err)
  122. }
  123. }()
  124. }
  125. defer cliTelnetServer.Stop()
  126. if sSvc, ok := servicesMgr.GetService("ssh"); !ok || !sSvc.Disabled {
  127. go func() {
  128. if err := cliSSHServer.Start(); err != nil {
  129. log.Printf("[CLI-SSH] Server listener error: %v", err)
  130. }
  131. }()
  132. }
  133. defer cliSSHServer.Stop()
  134. // API & Web UI Server
  135. srv := api.NewServer(
  136. netMgr,
  137. persistMgr,
  138. metaMgr,
  139. vpnMgr,
  140. fwMgr,
  141. routingMgr,
  142. dynRoutingMgr,
  143. bridgeMgr,
  144. toolsMgr,
  145. dhcpMgr,
  146. dhcpServerMgr,
  147. vrrpMgr,
  148. bwtestMgr,
  149. dnsMgr,
  150. authMgr,
  151. servicesMgr,
  152. certMgr,
  153. webHandler,
  154. )
  155. // HTTPS (www-ssl) Dynamic Server Listener
  156. var (
  157. httpsServer *http.Server
  158. httpsMu sync.Mutex
  159. httpsRunning bool
  160. )
  161. startOrRestartHTTPS := func(port int, disabled bool) {
  162. httpsMu.Lock()
  163. defer httpsMu.Unlock()
  164. if httpsRunning && httpsServer != nil {
  165. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  166. _ = httpsServer.Shutdown(ctx)
  167. cancel()
  168. httpsRunning = false
  169. httpsServer = nil
  170. }
  171. if disabled {
  172. log.Printf("[HTTPS] Web SSL (www-ssl) listener stopped")
  173. return
  174. }
  175. sslSvc, ok := servicesMgr.GetService("www-ssl")
  176. if !ok || sslSvc.Certificate == "" {
  177. log.Printf("[HTTPS] Cannot start www-ssl: no certificate configured (set certificate=<name>)")
  178. return
  179. }
  180. tlsCert, err := certMgr.GetTLSCertificate(sslSvc.Certificate)
  181. if err != nil {
  182. log.Printf("[HTTPS] Cannot start www-ssl: failed loading certificate %q: %v", sslSvc.Certificate, err)
  183. return
  184. }
  185. tlsConfig := &tls.Config{
  186. Certificates: []tls.Certificate{tlsCert},
  187. GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
  188. curSvc, ok := servicesMgr.GetService("www-ssl")
  189. if ok && curSvc.Certificate != "" {
  190. if c, err := certMgr.GetTLSCertificate(curSvc.Certificate); err == nil {
  191. return &c, nil
  192. }
  193. }
  194. return &tlsCert, nil
  195. },
  196. }
  197. listenAddr := fmt.Sprintf(":%d", port)
  198. newSrv := &http.Server{
  199. Addr: listenAddr,
  200. Handler: srv,
  201. TLSConfig: tlsConfig,
  202. ReadTimeout: 60 * time.Second,
  203. WriteTimeout: 60 * time.Second,
  204. IdleTimeout: 120 * time.Second,
  205. }
  206. httpsServer = newSrv
  207. httpsRunning = true
  208. go func() {
  209. log.Printf("[HTTPS] Web SSL (www-ssl) server listening on %s with certificate %q", listenAddr, sslSvc.Certificate)
  210. if err := newSrv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
  211. log.Printf("[HTTPS] Server error: %v", err)
  212. httpsMu.Lock()
  213. httpsRunning = false
  214. httpsMu.Unlock()
  215. }
  216. }()
  217. }
  218. servicesMgr.RegisterHook("www-ssl", func(serviceName string, port int, disabled bool) error {
  219. startOrRestartHTTPS(port, disabled)
  220. return nil
  221. })
  222. if sslSvc, ok := servicesMgr.GetService("www-ssl"); ok && !sslSvc.Disabled {
  223. startOrRestartHTTPS(sslSvc.Port, sslSvc.Disabled)
  224. }
  225. defer func() {
  226. httpsMu.Lock()
  227. if httpsRunning && httpsServer != nil {
  228. _ = httpsServer.Close()
  229. }
  230. httpsMu.Unlock()
  231. }()
  232. httpServer := &http.Server{
  233. Addr: *addr,
  234. Handler: srv,
  235. ReadTimeout: 60 * time.Second,
  236. WriteTimeout: 60 * time.Second,
  237. IdleTimeout: 120 * time.Second,
  238. }
  239. // Print startup banner
  240. fmt.Println("========================================================")
  241. fmt.Println(" ⚡ Proxmox RouterOS Appliance Controller ⚡ ")
  242. fmt.Println("========================================================")
  243. fmt.Printf(" Web UI & API : http://0.0.0.0%s\n", *addr)
  244. fmt.Printf(" CLI Telnet Service : 0.0.0.0%s (debtik-cli / telnet)\n", telnetAddr)
  245. fmt.Printf(" CLI SSH Service : 0.0.0.0%s (ssh admin@<router-ip> -p 2222)\n", sshAddr)
  246. fmt.Printf(" Metadata Storage : %s\n", *metaPath)
  247. fmt.Printf(" Debian Config Path : %s\n", network.DebianVlansCfgPath)
  248. if ifaces, err := netMgr.ListInterfaces(); err == nil {
  249. fmt.Printf(" Discovered Links : %d interfaces\n", len(ifaces))
  250. for _, i := range ifaces {
  251. fmt.Printf(" - %-10s (%s) [%s] MTU:%d\n", i.Name, i.Type, i.State, i.MTU)
  252. }
  253. }
  254. fmt.Println("========================================================")
  255. fmt.Println(" DebTik Appliance ready. Press Ctrl+C to terminate.")
  256. // Graceful shutdown handling
  257. stopChan := make(chan os.Signal, 1)
  258. signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM)
  259. go func() {
  260. if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  261. log.Fatalf("HTTP server failed: %v", err)
  262. }
  263. }()
  264. <-stopChan
  265. fmt.Println("\nShutting down RouterOS Controller gracefully...")
  266. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  267. defer cancel()
  268. if err := httpServer.Shutdown(ctx); err != nil {
  269. log.Printf("Server shutdown error: %v", err)
  270. }
  271. fmt.Println("RouterOS Controller stopped.")
  272. }