func versionCheck(s *State, ctl *ui.Controller) { check := func() { resp, err := http.Get(versionEndpoint) if err != nil { log.Warn("Failed to get version info %s: %v", versionEndpoint, err) return } defer resp.Body.Close() var payload struct { Client struct { Version string } } err = json.NewDecoder(resp.Body).Decode(&payload) if err != nil { log.Warn("Failed to read version info: %v", err) return } if payload.Client.Version != version.MajorMinor() { s.newVersion = payload.Client.Version ctl.Update(s) } } // check immediately and then at a set interval check() for _ = range time.Tick(versionCheckInterval) { check() } }
func NewWebView(ctl *ui.Controller, state ui.State, port int) *WebView { v := &WebView{ wsMessages: util.NewBroadcast(), } switch p := state.GetProtocol().(type) { case *proto.Http: NewWebHttpView(v, ctl, p) } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/http/in", 302) }) http.HandleFunc("/_ws", func(w http.ResponseWriter, r *http.Request) { conn, err := websocket.Upgrade(w, r.Header, nil, 1024, 1024) if err != nil { http.Error(w, "Failed websocket upgrade", 400) log.Warn("Failed websocket upgrade: %v", err) return } msgs := v.wsMessages.Reg() defer v.wsMessages.UnReg(msgs) for m := range msgs { err := conn.WriteMessage(websocket.OpText, m.([]byte)) if err != nil { // connection is closed break } } }) http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) { buf, err := assets.ReadAsset(path.Join("assets", "client", r.URL.Path[1:])) if err != nil { log.Warn("Error serving static file: %s", err.Error()) http.NotFound(w, r) return } w.Write(buf) }) log.Info("Serving web interface on localhost:%d", port) go http.ListenAndServe(fmt.Sprintf(":%d", port), nil) return v }
/** * Listens for new public tcp connections from the internet. */ func (t *Tunnel) listenTcp(listener *net.TCPListener) { for { defer func() { if r := recover(); r != nil { log.Warn("listenTcp failed with error %v", r) } }() // accept public connections tcpConn, err := listener.AcceptTCP() if err != nil { // not an error, we're shutting down this tunnel if atomic.LoadInt32(&t.closing) == 1 { return } t.Error("Failed to accept new TCP connection: %v", err) continue } conn := conn.Wrap(tcpConn, "pub") conn.AddLogPrefix(t.Id()) conn.Info("New connection from %v", conn.RemoteAddr()) go t.HandlePublicConnection(conn) } }
func SaveAuthToken(token string) { if token == "" || token == LoadAuthToken() || authTokenFile == "" { return } perms := os.FileMode(0644) err := ioutil.WriteFile(authTokenFile, []byte(token), perms) if err != nil { log.Warn("Failed to write auth token to file %s: %v", authTokenFile, err.Error()) } }
func defaultPath() string { user, err := user.Current() // user.Current() does not work on linux when cross compilling because // it requires CGO; use os.Getenv("HOME") hack until we compile natively homeDir := os.Getenv("HOME") if err != nil { log.Warn("Failed to get user's home directory: %s. Using $HOME: %s", err.Error(), homeDir) } else { homeDir = user.HomeDir } return path.Join(homeDir, ".ngrok") }
func Init() { user, err := user.Current() // os.Getenv("HOME") hack is here to support osx -> linux cross-compilation // because user.Current() only cross compiles correctly from osx -> windows homeDir := os.Getenv("HOME") if err != nil { log.Warn("Failed to get user's home directory: %s", err.Error()) } else { homeDir = user.HomeDir } authTokenFile = path.Join(homeDir, ".ngrok") log.Debug("Reading auth token from file %s", authTokenFile) tokenBytes, err := ioutil.ReadFile(authTokenFile) if err == nil { currentAuthToken = string(tokenBytes) } else { log.Warn("Failed to read ~/.ngrok for auth token: %s", err.Error()) } }
func init() { user, err := user.Current() if err != nil { log.Warn("Failed to get user's home directory: %s", err.Error()) return } authTokenFile = path.Join(user.HomeDir, ".ngrok") tokenBytes, err := ioutil.ReadFile(authTokenFile) if err == nil { currentAuthToken = string(tokenBytes) } }
func initAuth() { user, err := user.Current() // user.Current() does not work on linux when cross compilling because // it requires CGO; use os.Getenv("HOME") hack until we compile natively homeDir := os.Getenv("HOME") if err != nil { log.Warn("Failed to get user's home directory: %s", err.Error()) } else { homeDir = user.HomeDir } authTokenFile = path.Join(homeDir, ".ngrok") log.Debug("Reading auth token from file %s", authTokenFile) tokenBytes, err := ioutil.ReadFile(authTokenFile) if err == nil { currentAuthToken = string(tokenBytes) } else { log.Warn("Failed to read ~/.ngrok for auth token: %s", err.Error()) } }
/** * Listens for new public tcp connections from the internet. */ func (t *Tunnel) listenTcp(listener *net.TCPListener) { for { defer func() { if r := recover(); r != nil { log.Warn("listenTcp failed with error %v", r) } }() // accept public connections tcpConn, err := listener.AcceptTCP() if err != nil { panic(err) } conn := conn.Wrap(tcpConn, "pub") conn.AddLogPrefix(t.Id()) conn.Info("New connection from %v", conn.RemoteAddr()) go t.HandlePublicConnection(conn) } }
func Main() { // parse options opts := parseArgs() // set up logging log.LogTo(opts.logto) // set up auth token if opts.authtoken == "" { opts.authtoken = LoadAuthToken() } // init client state s := &State{ status: "connecting", // unique client id id: util.RandIdOrPanic(8), // command-line options opts: opts, // metrics metrics: NewClientMetrics(), } switch opts.protocol { case "http": s.protocol = proto.NewHttp() case "tcp": s.protocol = proto.NewTcp() } // init ui ctl := ui.NewController() if opts.webport != -1 { web.NewWebView(ctl, s, opts.webport) } if opts.logto != "stdout" { term.New(ctl, s) } go reconnectingControl(s, ctl) go autoUpdate(s, ctl, opts.authtoken) quitMessage := "" ctl.Wait.Add(1) go func() { defer ctl.Wait.Done() for { select { case obj := <-ctl.Cmds: switch cmd := obj.(type) { case ui.CmdQuit: quitMessage = cmd.Message ctl.DoShutdown() return case ui.CmdRequest: go func() { var localConn conn.Conn localConn, err := conn.Dial(s.opts.localaddr, "prv", nil) if err != nil { log.Warn("Failed to open private leg %s: %v", s.opts.localaddr, err) return } //defer localConn.Close() localConn = s.protocol.WrapConn(localConn) localConn.Write(cmd.Payload) ioutil.ReadAll(localConn) }() } } } }() ctl.Wait.Wait() fmt.Println(quitMessage) }