github.com/aitjcize/Overlord@v0.0.0-20240314041920-104a804cf5e8/overlord/overlord.go (about) 1 // Copyright 2015 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package overlord 6 7 import ( 8 "encoding/json" 9 "errors" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "log" 14 "net" 15 "net/http" 16 "os" 17 "path/filepath" 18 "runtime" 19 "sort" 20 "strconv" 21 "strings" 22 "sync" 23 "time" 24 25 socketio "github.com/googollee/go-socket.io" 26 "github.com/gorilla/mux" 27 "github.com/gorilla/websocket" 28 uuid "github.com/satori/go.uuid" 29 ) 30 31 const ( 32 systemAppDir = "../share/overlord" 33 ldInterval = 5 34 ) 35 36 // SpawnTerminalCmd is an overlord intend to launch a terminal. 37 type SpawnTerminalCmd struct { 38 Sid string // Session ID 39 TtyDevice string // Termainl device to open 40 } 41 42 // SpawnShellCmd is an overlord intend to launch a shell command. 43 type SpawnShellCmd struct { 44 Sid string // Session ID 45 Command string // Command to execute 46 } 47 48 // SpawnFileCmd is an overlord intend to perform file transfer. 49 type SpawnFileCmd struct { 50 Sid string // Session ID 51 TerminalSid string // Target terminal's session ID 52 Action string // Action, download or upload 53 Filename string // File to perform action on 54 Dest string // Destination, use for upload 55 Perm int // File permissions to set 56 CheckOnly bool // Check permission only (writable?) 57 } 58 59 // SpawnModeForwarderCmd is an overlord intend to perform port forwarding. 60 type SpawnModeForwarderCmd struct { 61 Sid string // Session ID 62 Port int // Port to forward 63 } 64 65 // ConnectLogcatCmd is an overlord intend to connect to a logcat session. 66 type ConnectLogcatCmd struct { 67 Conn *websocket.Conn 68 } 69 70 // webSocketContext is used for maintaining the session information of 71 // WebSocket requests. When requests come from Web Server, we create a new 72 // WebSocketConext to store the session ID and WebSocket connection. ConnServer 73 // will request a new terminal connection with the given session ID. 74 // This way, the ConnServer can retrieve the connresponding webSocketContext 75 // with it's the given session ID and get the WebSocket. 76 type webSocketContext struct { 77 Sid string // Session ID 78 Conn *websocket.Conn // WebSocket connection 79 } 80 81 // newWebsocketContext create webSocketContext object. 82 func newWebsocketContext(conn *websocket.Conn) *webSocketContext { 83 return &webSocketContext{ 84 Sid: uuid.NewV4().String(), 85 Conn: conn, 86 } 87 } 88 89 // TLSCerts stores the TLS certificate filenames. 90 type TLSCerts struct { 91 Cert string // cert.pem filename 92 Key string // key.pem filename 93 } 94 95 // Overlord type is the main context for storing the overlord server state. 96 type Overlord struct { 97 bindAddr string // Bind address 98 port int // Port number to listen to 99 lanDiscInterface string // Network interface used for broadcasting LAN discovery packet 100 lanDisc bool // Enable LAN discovery broadcasting 101 auth bool // Enable HTTP basic authentication 102 certs *TLSCerts // TLS certificate 103 linkTLS bool // Enable TLS between ghost and overlord 104 htpasswdPath string // Path to .htpasswd file 105 agents map[string]*ConnServer // Normal ghost agents 106 logcats map[string]map[string]*ConnServer // logcat clients 107 wsctxs map[string]*webSocketContext // (sid, webSocketContext) mapping 108 downloads map[string]*ConnServer // Download file agents 109 uploads map[string]*ConnServer // Upload file agents 110 ioserver *socketio.Server // SocketIO server handle 111 agentsMu sync.Mutex // Mutex for agents 112 logcatsMu sync.Mutex // Mutex for logcats 113 wsctxsMu sync.Mutex // Mutex for wsctxs 114 downloadsMu sync.Mutex // Mutex for downloads 115 uploadsMu sync.Mutex // Mutex for uploads 116 ioserverMu sync.Mutex // Mutex for ioserver 117 } 118 119 // NewOverlord creates an Overlord object. 120 func NewOverlord( 121 bindAddr string, port int, 122 lanDiscInterface string, 123 lanDisc bool, auth bool, 124 certsString string, linkTLS bool, htpasswdPath string) *Overlord { 125 126 var certs *TLSCerts 127 if certsString != "" { 128 parts := strings.Split(certsString, ",") 129 if len(parts) != 2 { 130 log.Fatalf("TLSCerts: invalid TLS certs argument") 131 } else { 132 certs = &TLSCerts{parts[0], parts[1]} 133 } 134 } 135 if !filepath.IsAbs(htpasswdPath) { 136 execPath, err := os.Executable() 137 if err != nil { 138 log.Fatalln(err) 139 } 140 execDir := filepath.Dir(execPath) 141 htpasswdPath, err = filepath.Abs(filepath.Join(execDir, htpasswdPath)) 142 if err != nil { 143 log.Fatalln(err) 144 } 145 } 146 return &Overlord{ 147 bindAddr: bindAddr, 148 port: port, 149 lanDiscInterface: lanDiscInterface, 150 lanDisc: lanDisc, 151 auth: auth, 152 certs: certs, 153 linkTLS: linkTLS, 154 htpasswdPath: htpasswdPath, 155 agents: make(map[string]*ConnServer), 156 logcats: make(map[string]map[string]*ConnServer), 157 wsctxs: make(map[string]*webSocketContext), 158 downloads: make(map[string]*ConnServer), 159 uploads: make(map[string]*ConnServer), 160 } 161 } 162 163 // Register a client. 164 func (ovl *Overlord) Register(conn *ConnServer) (*websocket.Conn, error) { 165 msg, err := json.Marshal(map[string]interface{}{ 166 "mid": conn.Mid, 167 "sid": conn.Sid, 168 }) 169 if err != nil { 170 return nil, err 171 } 172 173 var wsconn *websocket.Conn 174 175 switch conn.Mode { 176 case ModeControl: 177 ovl.agentsMu.Lock() 178 if _, ok := ovl.agents[conn.Mid]; ok { 179 ovl.agentsMu.Unlock() 180 return nil, errors.New("duplicate machine ID: " + conn.Mid) 181 } 182 ovl.agents[conn.Mid] = conn 183 ovl.agentsMu.Unlock() 184 ovl.ioserver.BroadcastTo("monitor", "agent joined", string(msg)) 185 case ModeTerminal, ModeShell, ModeForward: 186 ovl.wsctxsMu.Lock() 187 ctx, ok := ovl.wsctxs[conn.Sid] 188 if !ok { 189 ovl.wsctxsMu.Unlock() 190 return nil, errors.New("client " + conn.Sid + " registered without context") 191 } 192 wsconn = ctx.Conn 193 ovl.wsctxsMu.Unlock() 194 case ModeLogcat: 195 ovl.logcatsMu.Lock() 196 if _, ok := ovl.logcats[conn.Mid]; !ok { 197 ovl.logcats[conn.Mid] = make(map[string]*ConnServer) 198 } 199 if _, ok := ovl.logcats[conn.Mid][conn.Sid]; ok { 200 ovl.logcatsMu.Unlock() 201 return nil, errors.New("duplicate session ID: " + conn.Sid) 202 } 203 ovl.logcats[conn.Mid][conn.Sid] = conn 204 ovl.logcatsMu.Unlock() 205 ovl.ioserver.BroadcastTo("monitor", "logcat joined", string(msg)) 206 case ModeFile: 207 // Do nothing, we wait until 'request_to_download' call from client to 208 // send the message to the browser 209 default: 210 return nil, errors.New("Unknown client mode") 211 } 212 213 var id string 214 if conn.Mode == ModeControl { 215 id = conn.Mid 216 } else { 217 id = conn.Sid 218 } 219 220 log.Printf("%s %s registered\n", ModeStr(conn.Mode), id) 221 222 return wsconn, nil 223 } 224 225 // Unregister a client. 226 func (ovl *Overlord) Unregister(conn *ConnServer) { 227 msg, err := json.Marshal(map[string]interface{}{ 228 "mid": conn.Mid, 229 "sid": conn.Sid, 230 }) 231 232 if err != nil { 233 panic(err) 234 } 235 236 switch conn.Mode { 237 case ModeControl: 238 ovl.ioserver.BroadcastTo("monitor", "agent left", string(msg)) 239 ovl.agentsMu.Lock() 240 delete(ovl.agents, conn.Mid) 241 ovl.agentsMu.Unlock() 242 case ModeLogcat: 243 ovl.logcatsMu.Lock() 244 if _, ok := ovl.logcats[conn.Mid]; ok { 245 ovl.ioserver.BroadcastTo("monitor", "logcat left", string(msg)) 246 delete(ovl.logcats[conn.Mid], conn.Sid) 247 if len(ovl.logcats[conn.Mid]) == 0 { 248 delete(ovl.logcats, conn.Mid) 249 } 250 } 251 ovl.logcatsMu.Unlock() 252 case ModeFile: 253 ovl.downloadsMu.Lock() 254 if _, ok := ovl.downloads[conn.Sid]; ok { 255 delete(ovl.downloads, conn.Sid) 256 } 257 ovl.downloadsMu.Unlock() 258 ovl.uploadsMu.Lock() 259 if _, ok := ovl.uploads[conn.Sid]; ok { 260 delete(ovl.uploads, conn.Sid) 261 } 262 ovl.uploadsMu.Unlock() 263 default: 264 ovl.wsctxsMu.Lock() 265 if _, ok := ovl.wsctxs[conn.Sid]; ok { 266 delete(ovl.wsctxs, conn.Sid) 267 } 268 ovl.wsctxsMu.Unlock() 269 } 270 271 var id string 272 if conn.Mode == ModeControl { 273 id = conn.Mid 274 } else { 275 id = conn.Sid 276 } 277 log.Printf("%s %s unregistered\n", ModeStr(conn.Mode), id) 278 } 279 280 // AddWebsocketContext adds an websocket context to the overlord state. 281 func (ovl *Overlord) AddWebsocketContext(wc *webSocketContext) { 282 ovl.wsctxsMu.Lock() 283 ovl.wsctxs[wc.Sid] = wc 284 ovl.wsctxsMu.Unlock() 285 } 286 287 // RegisterDownloadRequest registers a file download request. 288 func (ovl *Overlord) RegisterDownloadRequest(conn *ConnServer) { 289 // Use session ID as download session ID instead of machine ID, so a machine 290 // can have multiple download at the same time 291 ovl.ioserver.BroadcastTo(conn.TerminalSid, "file download", string(conn.Sid)) 292 ovl.downloadsMu.Lock() 293 ovl.downloads[conn.Sid] = conn 294 ovl.downloadsMu.Unlock() 295 } 296 297 // RegisterUploadRequest registers a file upload request. 298 func (ovl *Overlord) RegisterUploadRequest(conn *ConnServer) { 299 // Use session ID as upload session ID instead of machine ID, so a machine 300 // can have multiple upload at the same time 301 ovl.ioserver.BroadcastTo(conn.TerminalSid, "file upload", string(conn.Sid)) 302 ovl.uploadsMu.Lock() 303 ovl.uploads[conn.Sid] = conn 304 ovl.uploadsMu.Unlock() 305 } 306 307 // Handle TCP Connection. 308 func (ovl *Overlord) handleConnection(conn net.Conn) { 309 handler := NewConnServer(ovl, conn) 310 go handler.Listen() 311 } 312 313 // InitSocketIOServer initializes the Socket.io server. 314 func (ovl *Overlord) InitSocketIOServer() { 315 server, err := socketio.NewServer(nil) 316 if err != nil { 317 log.Fatalln(err) 318 } 319 320 server.On("connection", func(so socketio.Socket) { 321 so.Join("monitor") 322 }) 323 324 server.On("error", func(so socketio.Socket, err error) { 325 log.Println("error:", err) 326 }) 327 328 // Client initiated subscription 329 server.On("subscribe", func(so socketio.Socket, name string) { 330 so.Join(name) 331 }) 332 333 // Client initiated unsubscription 334 server.On("unsubscribe", func(so socketio.Socket, name string) { 335 so.Leave(name) 336 }) 337 338 ovl.ioserver = server 339 } 340 341 // GetAppDir returns the overlord application directory. 342 func (ovl *Overlord) GetAppDir() string { 343 execPath, err := os.Executable() 344 if err != nil { 345 log.Fatalln(err) 346 } 347 execDir := filepath.Dir(execPath) 348 349 appDir, err := filepath.Abs(filepath.Join(execDir, "app")) 350 if err != nil { 351 log.Fatalln(err) 352 } 353 354 if _, err := os.Stat(appDir); err != nil { 355 // Try system install directory 356 appDir, err = filepath.Abs(filepath.Join(execDir, systemAppDir, "app")) 357 if err != nil { 358 log.Fatalln(err) 359 } 360 if _, err := os.Stat(appDir); err != nil { 361 log.Fatalln("Can not find app directory") 362 } 363 } 364 return appDir 365 } 366 367 // GetAppNames return the name of overlord apps. 368 func (ovl *Overlord) GetAppNames(ignoreSpecial bool) ([]string, error) { 369 var appNames []string 370 371 isSpecial := func(target string) bool { 372 for _, name := range []string{"common", "upgrade", "third_party"} { 373 if name == target { 374 return true 375 } 376 } 377 return false 378 } 379 380 apps, err := ioutil.ReadDir(ovl.GetAppDir()) 381 if err != nil { 382 return nil, nil 383 } 384 385 for _, app := range apps { 386 if !app.IsDir() || (ignoreSpecial && isSpecial(app.Name())) { 387 continue 388 } 389 appNames = append(appNames, app.Name()) 390 } 391 return appNames, nil 392 } 393 394 type byMid []map[string]interface{} 395 396 func (a byMid) Len() int { return len(a) } 397 func (a byMid) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 398 func (a byMid) Less(i, j int) bool { 399 return a[i]["mid"].(string) < a[j]["mid"].(string) 400 } 401 402 // RegisterHTTPHandlers register handlers for http routes. 403 func (ovl *Overlord) RegisterHTTPHandlers() { 404 var upgrader = websocket.Upgrader{ 405 ReadBufferSize: bufferSize, 406 WriteBufferSize: bufferSize, 407 Subprotocols: []string{"binary"}, 408 CheckOrigin: func(r *http.Request) bool { 409 return true 410 }, 411 } 412 413 // Helper function for writing error message to WebSocket 414 WebSocketSendError := func(ws *websocket.Conn, err string) { 415 log.Println(err) 416 msg := websocket.FormatCloseMessage(websocket.CloseProtocolError, err) 417 ws.WriteMessage(websocket.CloseMessage, msg) 418 ws.Close() 419 } 420 421 GhostConnectHandler := func(w http.ResponseWriter, r *http.Request) { 422 conn, err := upgrader.Upgrade(w, r, nil) 423 if err != nil { 424 log.Println(err) 425 return 426 } 427 428 log.Printf("Incoming connection from %s", conn.UnderlyingConn().RemoteAddr()) 429 cs := NewConnServer(ovl, conn.UnderlyingConn()) 430 cs.Listen() 431 } 432 433 // List all apps available on Overlord. 434 AppsListHandler := func(w http.ResponseWriter, r *http.Request) { 435 w.Header().Set("Content-Type", "application/json") 436 437 apps, err := ovl.GetAppNames(true) 438 if err != nil { 439 w.Write([]byte(fmt.Sprintf(`{"error": "%s"}`, err))) 440 } 441 442 result, err := json.Marshal(map[string][]string{"apps": apps}) 443 if err != nil { 444 w.Write([]byte(fmt.Sprintf(`{"error": "%s"}`, err))) 445 } else { 446 w.Write(result) 447 } 448 } 449 450 // List all agents connected to the Overlord. 451 AgentsListHandler := func(w http.ResponseWriter, r *http.Request) { 452 w.Header().Set("Content-Type", "application/json") 453 var data = make([]map[string]interface{}, 0) 454 ovl.agentsMu.Lock() 455 for _, agent := range ovl.agents { 456 data = append(data, map[string]interface{}{ 457 "mid": agent.Mid, 458 "sid": agent.Sid, 459 "properties": agent.Properties, 460 }) 461 } 462 ovl.agentsMu.Unlock() 463 sort.Sort(byMid(data)) 464 465 result, err := json.Marshal(data) 466 if err != nil { 467 w.Write([]byte(fmt.Sprintf(`{"error": "%s"}`, err))) 468 } else { 469 w.Write(result) 470 } 471 } 472 473 // Agent upgrade request handler. 474 AgentsUpgradeHandler := func(w http.ResponseWriter, r *http.Request) { 475 ovl.agentsMu.Lock() 476 for _, agent := range ovl.agents { 477 err := agent.SendUpgradeRequest() 478 if err != nil { 479 w.Write([]byte(fmt.Sprintf("Failed to send upgrade request for `%s'.\n", 480 agent.Mid))) 481 } 482 } 483 ovl.agentsMu.Unlock() 484 w.Write([]byte(`{"status": "success"}`)) 485 } 486 487 // List all logcat clients connected to the Overlord. 488 LogcatsListHandler := func(w http.ResponseWriter, r *http.Request) { 489 w.Header().Set("Content-Type", "application/json") 490 var data = make([]map[string]interface{}, 0) 491 ovl.logcatsMu.Lock() 492 for mid, logcats := range ovl.logcats { 493 var sids []string 494 for sid := range logcats { 495 sids = append(sids, sid) 496 } 497 data = append(data, map[string]interface{}{ 498 "mid": mid, 499 "sids": sids, 500 }) 501 } 502 ovl.logcatsMu.Unlock() 503 504 result, err := json.Marshal(data) 505 if err != nil { 506 w.Write([]byte(fmt.Sprintf(`{"error": "%s"}`, err))) 507 } else { 508 w.Write(result) 509 } 510 } 511 512 // Logcat request handler. 513 // We directly send the WebSocket connection to ConnServer for forwarding 514 // the log stream. 515 LogcatHandler := func(w http.ResponseWriter, r *http.Request) { 516 log.Printf("Logcat request from %s\n", r.RemoteAddr) 517 518 conn, err := upgrader.Upgrade(w, r, nil) 519 if err != nil { 520 log.Println(err) 521 return 522 } 523 524 vars := mux.Vars(r) 525 mid := vars["mid"] 526 sid := vars["sid"] 527 528 ovl.logcatsMu.Lock() 529 if logcats, ok := ovl.logcats[mid]; ok { 530 ovl.logcatsMu.Unlock() 531 if logcat, ok := logcats[sid]; ok { 532 logcat.Command <- ConnectLogcatCmd{conn} 533 } else { 534 WebSocketSendError(conn, "No client with sid "+sid) 535 } 536 } else { 537 ovl.logcatsMu.Unlock() 538 WebSocketSendError(conn, "No client with mid "+mid) 539 } 540 } 541 542 // TTY stream request handler. 543 // We first create a webSocketContext to store the connection, then send a 544 // command to Overlord to client to spawn a terminal connection. 545 AgentTtyHandler := func(w http.ResponseWriter, r *http.Request) { 546 log.Printf("Terminal request from %s\n", r.RemoteAddr) 547 conn, err := upgrader.Upgrade(w, r, nil) 548 if err != nil { 549 log.Println(err) 550 return 551 } 552 553 var ttyDevice string 554 555 vars := mux.Vars(r) 556 mid := vars["mid"] 557 if _ttyDevice, ok := r.URL.Query()["tty_device"]; ok { 558 ttyDevice = _ttyDevice[0] 559 } 560 561 ovl.agentsMu.Lock() 562 if agent, ok := ovl.agents[mid]; ok { 563 ovl.agentsMu.Unlock() 564 wc := newWebsocketContext(conn) 565 ovl.AddWebsocketContext(wc) 566 agent.Command <- SpawnTerminalCmd{wc.Sid, ttyDevice} 567 if res := <-agent.Response; res != "" { 568 WebSocketSendError(conn, res) 569 } 570 } else { 571 ovl.agentsMu.Unlock() 572 WebSocketSendError(conn, "No client with mid "+mid) 573 } 574 } 575 576 // Shell command request handler. 577 // We first create a webSocketContext to store the connection, then send a 578 // command to ConnServer to client to spawn a shell connection. 579 ModeShellHandler := func(w http.ResponseWriter, r *http.Request) { 580 log.Printf("Shell request from %s\n", r.RemoteAddr) 581 582 conn, err := upgrader.Upgrade(w, r, nil) 583 if err != nil { 584 log.Println(err) 585 return 586 } 587 588 vars := mux.Vars(r) 589 mid := vars["mid"] 590 ovl.agentsMu.Lock() 591 if agent, ok := ovl.agents[mid]; ok { 592 ovl.agentsMu.Unlock() 593 if command, ok := r.URL.Query()["command"]; ok { 594 wc := newWebsocketContext(conn) 595 ovl.AddWebsocketContext(wc) 596 agent.Command <- SpawnShellCmd{wc.Sid, command[0]} 597 if res := <-agent.Response; res != "" { 598 WebSocketSendError(conn, res) 599 } 600 } else { 601 WebSocketSendError(conn, "No command specified for shell request "+mid) 602 } 603 } else { 604 ovl.agentsMu.Unlock() 605 WebSocketSendError(conn, "No client with mid "+mid) 606 } 607 } 608 609 // Get agent properties as JSON. 610 AgentPropertiesHandler := func(w http.ResponseWriter, r *http.Request) { 611 w.Header().Set("Content-Type", "application/json") 612 613 vars := mux.Vars(r) 614 mid := vars["mid"] 615 ovl.agentsMu.Lock() 616 if agent, ok := ovl.agents[mid]; ok { 617 ovl.agentsMu.Unlock() 618 jsonResult, err := json.Marshal(agent.Properties) 619 if err != nil { 620 w.Write([]byte(fmt.Sprintf(`{"error": "%s"}`, err))) 621 return 622 } 623 w.Write(jsonResult) 624 } else { 625 ovl.agentsMu.Unlock() 626 w.Write([]byte(fmt.Sprintf(`{"error": "No client with mid %s"}`, mid))) 627 } 628 } 629 630 // Helper function for serving file and write it into response body. 631 serveFileHTTP := func(w http.ResponseWriter, c *ConnServer) { 632 defer func() { 633 if c != nil { 634 c.StopListen() 635 } 636 }() 637 c.SendClearToDownload() 638 639 dispose := fmt.Sprintf("attachment; filename=\"%s\"", c.Download.Name) 640 w.Header().Set("Content-Disposition", dispose) 641 w.Header().Set("Content-Length", strconv.FormatInt(c.Download.Size, 10)) 642 643 for { 644 data := <-c.Download.Data 645 if data == nil { 646 return 647 } 648 if _, err := w.Write(data); err != nil { 649 break 650 } 651 } 652 } 653 654 // File download request handler. 655 // Handler for file download request, the filename target machine is 656 // specified in the request URL. 657 AgentDownloadHandler := func(w http.ResponseWriter, r *http.Request) { 658 vars := mux.Vars(r) 659 mid := vars["mid"] 660 661 var agent *ConnServer 662 var ok bool 663 664 ovl.agentsMu.Lock() 665 if agent, ok = ovl.agents[mid]; !ok { 666 ovl.agentsMu.Unlock() 667 http.NotFound(w, r) 668 return 669 } 670 ovl.agentsMu.Unlock() 671 672 var filename []string 673 if filename, ok = r.URL.Query()["filename"]; !ok { 674 http.NotFound(w, r) 675 return 676 } 677 678 sid := uuid.NewV4().String() 679 agent.Command <- SpawnFileCmd{ 680 Sid: sid, Action: "download", Filename: filename[0]} 681 682 res := <-agent.Response 683 if res != "" { 684 http.Error(w, fmt.Sprintf(`{"error": "%s"}`, res), 685 http.StatusBadRequest) 686 return 687 } 688 689 var c *ConnServer 690 const maxTries = 100 // 20 seconds 691 count := 0 692 693 // Wait until download client connects 694 for { 695 if count++; count == maxTries { 696 http.NotFound(w, r) 697 return 698 } 699 ovl.downloadsMu.Lock() 700 if c, ok = ovl.downloads[sid]; ok { 701 ovl.downloadsMu.Unlock() 702 break 703 } 704 ovl.downloadsMu.Unlock() 705 time.Sleep(200 * time.Millisecond) 706 } 707 serveFileHTTP(w, c) 708 } 709 710 // Passive file download request handler. 711 // This handler deal with requests that are initiated by the client. We 712 // simply check if the session id exists in the download client list, than 713 // start to download the file if it does. 714 FileDownloadHandler := func(w http.ResponseWriter, r *http.Request) { 715 vars := mux.Vars(r) 716 sid := vars["sid"] 717 718 var c *ConnServer 719 var ok bool 720 721 ovl.downloadsMu.Lock() 722 if c, ok = ovl.downloads[sid]; !ok { 723 ovl.downloadsMu.Unlock() 724 http.NotFound(w, r) 725 return 726 } 727 ovl.downloadsMu.Unlock() 728 serveFileHTTP(w, c) 729 } 730 731 // File upload request handler. 732 AgentUploadHandler := func(w http.ResponseWriter, r *http.Request) { 733 var ok bool 734 var err error 735 var agent *ConnServer 736 var errMsg string 737 738 defer func() { 739 if errMsg != "" { 740 http.Error(w, fmt.Sprintf(`{"error": "%s"}`, errMsg), 741 http.StatusBadRequest) 742 } 743 }() 744 745 vars := mux.Vars(r) 746 mid := vars["mid"] 747 ovl.agentsMu.Lock() 748 if agent, ok = ovl.agents[mid]; !ok { 749 ovl.agentsMu.Unlock() 750 errMsg = fmt.Sprintf("No client with mid %s", mid) 751 return 752 } 753 ovl.agentsMu.Unlock() 754 755 // Target terminal session ID 756 var terminalSids []string 757 if terminalSids, ok = r.URL.Query()["terminal_sid"]; !ok { 758 terminalSids = []string{""} 759 } 760 sid := uuid.NewV4().String() 761 762 // Upload destination 763 var dsts []string 764 if dsts, ok = r.URL.Query()["dest"]; !ok { 765 dsts = []string{""} 766 } 767 768 // Upload destination 769 var perm int64 770 if perms, ok := r.URL.Query()["perm"]; ok { 771 if perm, err = strconv.ParseInt(perms[0], 8, 32); err != nil { 772 errMsg = err.Error() 773 return 774 } 775 } 776 777 // Check only 778 if r.Method == "GET" { 779 // If we are checking only, we need a extra filename parameters since 780 // we don't have a form to supply the filename. 781 var filenames []string 782 if filenames, ok = r.URL.Query()["filename"]; !ok { 783 filenames = []string{""} 784 } 785 786 agent.Command <- SpawnFileCmd{sid, terminalSids[0], "upload", 787 filenames[0], dsts[0], int(perm), true} 788 789 errMsg = <-agent.Response 790 return 791 } 792 793 mr, err := r.MultipartReader() 794 if err != nil { 795 errMsg = err.Error() 796 return 797 } 798 799 p, err := mr.NextPart() 800 if err != nil { 801 errMsg = err.Error() 802 return 803 } 804 805 agent.Command <- SpawnFileCmd{sid, terminalSids[0], "upload", 806 p.FileName(), dsts[0], int(perm), false} 807 808 res := <-agent.Response 809 if res != "" { 810 http.NotFound(w, r) 811 return 812 } 813 814 const maxTries = 100 // 20 seconds 815 count := 0 816 817 // Wait until upload client connects 818 var c *ConnServer 819 for { 820 if count++; count == maxTries { 821 http.Error(w, "no response from client", http.StatusInternalServerError) 822 return 823 } 824 ovl.uploadsMu.Lock() 825 if c, ok = ovl.uploads[sid]; ok { 826 ovl.uploadsMu.Unlock() 827 break 828 } 829 ovl.uploadsMu.Unlock() 830 time.Sleep(200 * time.Millisecond) 831 } 832 833 _, err = io.Copy(c.Conn, p) 834 c.StopListen() 835 836 if err != nil { 837 errMsg = err.Error() 838 return 839 } 840 w.Write([]byte(`{"status": "success"}`)) 841 return 842 } 843 844 // Port forwarding request handler 845 AgentModeForwardHandler := func(w http.ResponseWriter, r *http.Request) { 846 log.Printf("ModeForward request from %s\n", r.RemoteAddr) 847 conn, err := upgrader.Upgrade(w, r, nil) 848 if err != nil { 849 log.Println(err) 850 return 851 } 852 853 var port int 854 855 vars := mux.Vars(r) 856 mid := vars["mid"] 857 if _port, ok := r.URL.Query()["port"]; ok { 858 if port, err = strconv.Atoi(_port[0]); err != nil { 859 WebSocketSendError(conn, "invalid port") 860 return 861 } 862 } else { 863 WebSocketSendError(conn, "no port specified") 864 return 865 } 866 867 ovl.agentsMu.Lock() 868 if agent, ok := ovl.agents[mid]; ok { 869 ovl.agentsMu.Unlock() 870 wc := newWebsocketContext(conn) 871 ovl.AddWebsocketContext(wc) 872 agent.Command <- SpawnModeForwarderCmd{wc.Sid, port} 873 if res := <-agent.Response; res != "" { 874 WebSocketSendError(conn, res) 875 } 876 } else { 877 ovl.agentsMu.Unlock() 878 WebSocketSendError(conn, "No client with mid "+mid) 879 } 880 } 881 882 // Initialize socket IO server 883 ovl.InitSocketIOServer() 884 885 appDir := ovl.GetAppDir() 886 887 // HTTP basic auth 888 auth := NewBasicAuth("Overlord", ovl.htpasswdPath, !ovl.auth) 889 890 http.HandleFunc("/connect", GhostConnectHandler) 891 892 // Register the request handlers. 893 r := mux.NewRouter() 894 895 r.HandleFunc("/api/apps/list", AppsListHandler) 896 r.HandleFunc("/api/agents/list", AgentsListHandler) 897 r.HandleFunc("/api/agents/upgrade", AgentsUpgradeHandler) 898 r.HandleFunc("/api/logcats/list", LogcatsListHandler) 899 900 // Logcat methods 901 r.HandleFunc("/api/log/{mid}/{sid}", LogcatHandler) 902 903 // Agent methods 904 r.HandleFunc("/api/agent/tty/{mid}", AgentTtyHandler) 905 r.HandleFunc("/api/agent/shell/{mid}", ModeShellHandler) 906 r.HandleFunc("/api/agent/properties/{mid}", AgentPropertiesHandler) 907 r.HandleFunc("/api/agent/download/{mid}", AgentDownloadHandler) 908 r.HandleFunc("/api/agent/upload/{mid}", AgentUploadHandler) 909 r.HandleFunc("/api/agent/forward/{mid}", AgentModeForwardHandler) 910 911 // File methods 912 r.HandleFunc("/api/file/download/{sid}", FileDownloadHandler) 913 914 http.Handle("/api/", auth.WrapHandler(r)) 915 http.Handle("/api/socket.io/", auth.WrapHandler(ovl.ioserver)) 916 917 // /upgrade/ does not need authenticiation 918 http.Handle("/upgrade/", http.StripPrefix("/upgrade/", 919 http.FileServer(http.Dir(filepath.Join(appDir, "upgrade"))))) 920 http.Handle("/vendor/", auth.WrapHandler(http.FileServer( 921 http.Dir(filepath.Join(appDir, "common"))))) 922 http.Handle("/", auth.WrapHandler(http.FileServer( 923 http.Dir(filepath.Join(appDir, "dashboard"))))) 924 925 // Serve all apps 926 appNames, err := ovl.GetAppNames(false) 927 if err != nil { 928 log.Fatalln(err) 929 } 930 931 for _, app := range appNames { 932 if app == "upgrade" { 933 continue 934 } 935 if app != "common" && app != "third_party" { 936 log.Printf("App `%s' registered\n", app) 937 } 938 prefix := fmt.Sprintf("/%s/", app) 939 http.Handle(prefix, http.StripPrefix(prefix, 940 auth.WrapHandler(http.FileServer(http.Dir(filepath.Join(appDir, app)))))) 941 } 942 } 943 944 // ServHTTP is the Web server main routine. 945 func (ovl *Overlord) ServHTTP() { 946 var err error 947 948 tlsStatus := "disabled" 949 if ovl.certs != nil { 950 tlsStatus = "enabled" 951 } 952 if ovl.port == 0 { 953 if ovl.certs != nil { 954 ovl.port = DefaultHTTPSPort 955 } else { 956 ovl.port = DefaultHTTPPort 957 } 958 } 959 960 addr := fmt.Sprintf("%s:%d", ovl.bindAddr, ovl.port) 961 log.Printf("HTTP server started, listening at %s, TLS: %s", 962 addr, tlsStatus) 963 964 if ovl.certs != nil { 965 err = http.ListenAndServeTLS(addr, ovl.certs.Cert, ovl.certs.Key, nil) 966 } else { 967 err = http.ListenAndServe(addr, nil) 968 } 969 if err != nil { 970 log.Fatalf("net.http could not listen on address '%s': %s\n", 971 addr, err) 972 } 973 } 974 975 // StartUDPBroadcast is the main routine for broadcasting LAN discovery message. 976 func (ovl *Overlord) StartUDPBroadcast(port int) { 977 ifaceIP := "" 978 bcastIP := net.IPv4bcast.String() 979 980 if ovl.lanDiscInterface != "" { 981 interfaces, err := net.Interfaces() 982 if err != nil { 983 panic(err) 984 } 985 986 outter: 987 for _, iface := range interfaces { 988 if iface.Name == ovl.lanDiscInterface { 989 addrs, err := iface.Addrs() 990 if err != nil { 991 panic(err) 992 } 993 for _, addr := range addrs { 994 ip, ipnet, err := net.ParseCIDR(addr.String()) 995 if err != nil { 996 continue 997 } 998 // Calculate broadcast IP 999 ip4 := ip.To4() 1000 1001 // We only care about IPv4 address 1002 if ip4 == nil { 1003 continue 1004 } 1005 bcastIPraw := make(net.IP, 4) 1006 for i := 0; i < 4; i++ { 1007 bcastIPraw[i] = ip4[i] | ^ipnet.Mask[i] 1008 } 1009 ifaceIP = ip.String() 1010 bcastIP = bcastIPraw.String() 1011 break outter 1012 } 1013 } 1014 } 1015 1016 if ifaceIP == "" { 1017 log.Fatalf("can not found any interface with name %s\n", 1018 ovl.lanDiscInterface) 1019 } 1020 } 1021 1022 addr := fmt.Sprintf("%s:%d", bcastIP, port) 1023 conn, err := net.Dial("udp", addr) 1024 if err != nil { 1025 log.Fatalln("Unable to start UDP broadcast:", err) 1026 } 1027 1028 log.Printf("UDP Broadcasting started, broadcasting at %s", addr) 1029 1030 ticker := time.NewTicker(time.Duration(ldInterval * time.Second)) 1031 1032 for { 1033 select { 1034 case <-ticker.C: 1035 conn.Write([]byte(fmt.Sprintf("OVERLORD %s:%d", ifaceIP, ovl.port))) 1036 } 1037 } 1038 } 1039 1040 // Serv is the main routine for starting all the overlord sub-server. 1041 func (ovl *Overlord) Serv() { 1042 ovl.RegisterHTTPHandlers() 1043 go ovl.ServHTTP() 1044 if ovl.lanDisc { 1045 go ovl.StartUDPBroadcast(OverlordLDPort) 1046 } 1047 1048 ticker := time.NewTicker(time.Duration(60 * time.Second)) 1049 1050 for { 1051 select { 1052 case <-ticker.C: 1053 log.Printf("#Goroutines, #Ghostclient: %d, %d\n", 1054 runtime.NumGoroutine(), len(ovl.agents)) 1055 } 1056 } 1057 } 1058 1059 // StartOverlord starts the overlord server. 1060 func StartOverlord(bindAddr string, port int, lanDiscInterface string, lanDisc bool, auth bool, 1061 certsString string, linkTLS bool, htpasswdPath string) { 1062 ovl := NewOverlord(bindAddr, port, lanDiscInterface, lanDisc, auth, 1063 certsString, linkTLS, htpasswdPath) 1064 ovl.Serv() 1065 }