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 }
// 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 }