Example #1
0
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()
	}
}
Example #2
0
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
}
Example #3
0
/**
 * 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)
	}
}
Example #4
0
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())
	}
}
Example #5
0
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")
}
Example #6
0
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())
	}
}
Example #7
0
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)
	}
}
Example #8
0
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())
	}
}
Example #9
0
/**
 * 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)
	}
}
Example #10
0
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)
}