Example #1
0
func newTunnel(m *msg.RegMsg, ctl *Control) (t *Tunnel) {
	t = &Tunnel{
		regMsg:  m,
		start:   time.Now(),
		ctl:     ctl,
		proxies: make(chan conn.Conn),
		Logger:  log.NewPrefixLogger(),
	}

	switch t.regMsg.Protocol {
	case "tcp":
		var err error
		t.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: 0})

		if err != nil {
			t.ctl.conn.Error("Failed to create tunnel. Error binding TCP listener: %v", err)

			t.ctl.stop <- &msg.RegAckMsg{Error: "Internal server error"}
		}

		go t.listenTcp(t.listener)

	default:
	}

	if err := tunnels.Add(t); err != nil {
		t.ctl.stop <- &msg.RegAckMsg{Error: fmt.Sprint(err)}
		return
	}

	if m.Version != version.Proto {
		t.ctl.stop <- &msg.RegAckMsg{Error: fmt.Sprintf("Incompatible versions. Server %s, client %s. Download a new version at http://ngrok.com", version.MajorMinor(), m.Version)}
	}

	// pre-encode the http basic auth for fast comparisons later
	if m.HttpAuth != "" {
		m.HttpAuth = "Basic " + base64.StdEncoding.EncodeToString([]byte(m.HttpAuth))
	}

	t.ctl.conn.AddLogPrefix(t.Id())
	t.AddLogPrefix(t.Id())
	t.Info("Registered new tunnel")
	t.ctl.out <- &msg.RegAckMsg{
		Url:       t.url,
		ProxyAddr: fmt.Sprintf("%s", proxyAddr),
		Version:   version.Proto,
		MmVersion: version.MajorMinor(),
	}

	metrics.OpenTunnel(t)
	return
}
Example #2
0
File: tunnel.go Project: jzs/ngrok
func newTunnel(m *msg.RegMsg, ctl *Control) (t *Tunnel) {
	t = &Tunnel{
		regMsg:  m,
		start:   time.Now(),
		ctl:     ctl,
		proxies: make(chan conn.Conn),
		Logger:  log.NewPrefixLogger(),
	}

	failReg := func(err error) {
		t.ctl.stop <- &msg.RegAckMsg{Error: err.Error()}
	}

	var err error

	switch t.regMsg.Protocol {
	case "tcp":
		var port int = 0

		// try to return to you the same port you had before
		cachedUrl := tunnels.GetCachedRegistration(t)
		if cachedUrl != "" {
			parts := strings.Split(cachedUrl, ":")
			portPart := parts[len(parts)-1]
			port, err = strconv.Atoi(portPart)
			if err != nil {
				t.ctl.conn.Error("Failed to parse cached url port as integer: %s", portPart)
				// continue with zero
				port = 0
			}
		}

		// Bind for TCP connections
		t.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: port})

		// If we failed with a custom port, try with a random one
		if err != nil && port != 0 {
			t.ctl.conn.Warn("Failed to get custom port %d: %v, trying a random one", port, err)
			t.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: 0})
		}

		// we tried to bind with a random port and failed (no more ports available?)
		if err != nil {
			failReg(t.ctl.conn.Error("Error binding TCP listener: %v", err))
			return
		}

		// create the url
		addr := t.listener.Addr().(*net.TCPAddr)
		t.url = fmt.Sprintf("tcp://%s:%d", domain, addr.Port)

		// register it
		if err = tunnels.RegisterAndCache(t.url, t); err != nil {
			// This should never be possible because the OS will
			// only assign available ports to us.
			t.listener.Close()
			failReg(fmt.Errorf("TCP listener bound, but failed to register %s", t.url))
			return
		}

		go t.listenTcp(t.listener)

	case "http":
		if strings.TrimSpace(t.regMsg.Hostname) != "" {
			t.url = fmt.Sprintf("http://%s", t.regMsg.Hostname)
		} else if strings.TrimSpace(t.regMsg.Subdomain) != "" {
			t.url = fmt.Sprintf("http://%s.%s", t.regMsg.Subdomain, domain)
		}

		if t.url != "" {
			if err := tunnels.Register(t.url, t); err != nil {
				failReg(err)
				return
			}
		} else {
			t.url, err = tunnels.RegisterRepeat(func() string {
				return fmt.Sprintf("http://%x.%s", rand.Int31(), domain)
			}, t)

			if err != nil {
				failReg(err)
				return
			}
		}
	}

	if m.Version != version.Proto {
		failReg(fmt.Errorf("Incompatible versions. Server %s, client %s. Download a new version at http://ngrok.com", version.MajorMinor(), m.Version))
		return
	}

	// pre-encode the http basic auth for fast comparisons later
	if m.HttpAuth != "" {
		m.HttpAuth = "Basic " + base64.StdEncoding.EncodeToString([]byte(m.HttpAuth))
	}

	t.ctl.conn.AddLogPrefix(t.Id())
	t.AddLogPrefix(t.Id())
	t.Info("Registered new tunnel")
	t.ctl.out <- &msg.RegAckMsg{
		Url:       t.url,
		ProxyAddr: fmt.Sprintf("%s", proxyAddr),
		Version:   version.Proto,
		MmVersion: version.MajorMinor(),
	}

	metrics.OpenTunnel(t)
	return
}
Example #3
0
func newTunnel(m *msg.RegMsg, ctl *Control) (t *Tunnel) {
	t = &Tunnel{
		regMsg:  m,
		start:   time.Now(),
		ctl:     ctl,
		proxies: make(chan conn.Conn),
		Logger:  log.NewPrefixLogger(),
	}

	failReg := func(err error) {
		t.ctl.stop <- &msg.RegAckMsg{Error: err.Error()}
	}

	switch t.regMsg.Protocol {
	case "tcp":
		var err error
		t.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: 0})

		if err != nil {
			t.ctl.conn.Error("Failed to create tunnel. Error binding TCP listener: %v", err)

			t.ctl.stop <- &msg.RegAckMsg{Error: "Internal server error"}
		}

		addr := t.listener.Addr().(*net.TCPAddr)
		t.url = fmt.Sprintf("tcp://%s:%d", domain, addr.Port)

		if err = tunnels.Register(t.url, t); err != nil {
			// This should never be possible because the OS will only assign
			// available ports to us.
			t.Error("TCP listener bound, but failed to register: %s", err.Error())
			t.listener.Close()
			failReg(err)
			return
		}

		go t.listenTcp(t.listener)

	case "http":
		if strings.TrimSpace(t.regMsg.Hostname) != "" {
			t.url = fmt.Sprintf("http://%s", t.regMsg.Hostname)
		} else if strings.TrimSpace(t.regMsg.Subdomain) != "" {
			t.url = fmt.Sprintf("http://%s.%s", t.regMsg.Subdomain, domain)
		}

		if t.url != "" {
			if err := tunnels.Register(t.url, t); err != nil {
				failReg(err)
				return
			}
		} else {
			t.url = tunnels.RegisterRepeat(func() string {
				return fmt.Sprintf("http://%x.%s", rand.Int31(), domain)
			}, t)
		}
	}

	if m.Version != version.Proto {
		failReg(fmt.Errorf("Incompatible versions. Server %s, client %s. Download a new version at http://ngrok.com", version.MajorMinor(), m.Version))
		return
	}

	// pre-encode the http basic auth for fast comparisons later
	if m.HttpAuth != "" {
		m.HttpAuth = "Basic " + base64.StdEncoding.EncodeToString([]byte(m.HttpAuth))
	}

	t.ctl.conn.AddLogPrefix(t.Id())
	t.AddLogPrefix(t.Id())
	t.Info("Registered new tunnel")
	t.ctl.out <- &msg.RegAckMsg{
		Url:       t.url,
		ProxyAddr: fmt.Sprintf("%s", proxyAddr),
		Version:   version.Proto,
		MmVersion: version.MajorMinor(),
	}

	metrics.OpenTunnel(t)
	return
}