Example #1
0
func (cmd *recordsAdd) Valid() error {
	if cmd.record.Name == "" {
		return errors.New("empty value for -name flag")
	}
	if cmd.record.IP == "" {
		return errors.New("empty value for -value flag")
	}
	if cmd.record.Type == "" {
		cmd.record.Type = dnsclient.ParseRecord("", cmd.record.IP).Type
	}
	if cmd.record.TTL == 0 {
		cmd.record.TTL = 30
	}
	return nil
}
Example #2
0
// NewServer gives new tunneling server for the given options.
func NewServer(opts *ServerOptions) (*Server, error) {
	optsCopy := *opts

	if optsCopy.ServerAddr == "" {
		ip, err := publicIP()
		if err != nil {
			return nil, err
		}

		optsCopy.ServerAddr = ip
	}

	if optsCopy.Log == nil {
		optsCopy.Log = logging.NewCustom("tunnelserver", optsCopy.Debug)
	}

	optsCopy.Log.Debug("Initial server options: %# v", &optsCopy)

	if optsCopy.BaseVirtualHost == "" {
		optsCopy.BaseVirtualHost = optsCopy.HostedZone
	}

	if optsCopy.BaseVirtualHost == "" {
		return nil, errors.New("either BaseVirtualHost or HostedZone parameter is required to be non-empty")
	}

	optsCopy.BaseVirtualHost = customPort(optsCopy.BaseVirtualHost, opts.Port, 80, 443)
	optsCopy.ServerAddr = customPort(optsCopy.ServerAddr, opts.Port)

	if optsCopy.TCPRangeFrom == 0 {
		optsCopy.TCPRangeFrom = 20000
	}

	if optsCopy.TCPRangeTo == 0 {
		optsCopy.TCPRangeTo = 50000
	}

	tunnelCfg := &tunnel.ServerConfig{
		Debug: optsCopy.Debug,
		Log:   optsCopy.Log,
	}
	server, err := tunnel.NewServer(tunnelCfg)
	if err != nil {
		return nil, err
	}

	if optsCopy.NoCNAME && (optsCopy.AccessKey == "" || optsCopy.SecretKey == "") {
		return nil, errors.New("no valid Route53 configuration found")
	}

	var dns *dnsclient.Route53
	if optsCopy.AccessKey != "" && optsCopy.SecretKey != "" {
		dnsOpts := &dnsclient.Options{
			Creds:      credentials.NewStaticCredentials(optsCopy.AccessKey, optsCopy.SecretKey, ""),
			HostedZone: optsCopy.HostedZone,
			Log:        optsCopy.Log,
			Debug:      optsCopy.Debug,
		}
		dns, err = dnsclient.NewRoute53Client(dnsOpts)
		if err != nil {
			return nil, err
		}
	}

	// Inserts DNS records for the tunnelserver. Host-routing requires an A record pointing
	// to the tunnelserver and a wildcard CNAME record pointing to that A record.
	// In other words if tunnel.example.com resolves to the tunnelserver, then
	// *.tunnel.example.com must also resolve to the very same tunnelserver instance.
	//
	// If there are not route53 credentials passed, we assume the DNS records are
	// taken care externally.
	if !optsCopy.NoCNAME && dns != nil {
		id, err := instanceID()
		if err != nil {
			if optsCopy.Test {
				username := os.Getenv("USER")
				if u, err := user.Current(); err == nil {
					username = u.Username
				}

				id = "koding-" + username
			}
		}

		if id != "" {
			optsCopy.BaseVirtualHost = strings.TrimPrefix(id, "i-") + "." + optsCopy.BaseVirtualHost
		}

		ip := host(optsCopy.ServerAddr)
		base := host(optsCopy.BaseVirtualHost)

		tunnelRec := &dnsclient.Record{
			Name: base,
			IP:   ip,
			Type: "A",
			TTL:  300,
		}

		allRec := &dnsclient.Record{
			Name: "\\052." + base,
			IP:   base,
			Type: "CNAME",
			TTL:  300,
		}

		// TODO(rjeczalik): add retries to pkg/dnsclient (TMS-2052)
		for i := 0; i < 5; i++ {
			if err = dns.UpsertRecords(tunnelRec, allRec); err == nil {
				break
			}

			time.Sleep(time.Duration(i) * time.Second) // linear backoff, overall time: 30s
		}

		if err != nil {
			return nil, err
		}
	}

	optsCopy.Log.Debug("Server options: %# v", &optsCopy)

	s := &Server{
		Server:    server,
		DNS:       dns,
		opts:      &optsCopy,
		privateIP: "0.0.0.0",
		record:    dnsclient.ParseRecord("", optsCopy.ServerAddr),
		idents:    make(map[string]string),
		services:  make(map[int]net.Listener),
		tunnels:   newTunnels(),
	}

	// Do not bind to private address for testing.
	if !s.opts.Test {
		if ip, err := privateIP(); err == nil {
			s.privateIP = ip
		}
	}

	return s, nil
}