package daemon import ( "context" "fmt" "isle/bootstrap" "isle/yamlutil" "net" "path/filepath" "code.betamike.com/micropelago/pmux/pmuxlib" "dev.mediocregopher.com/mediocre-go-lib.git/mctx" "dev.mediocregopher.com/mediocre-go-lib.git/mlog" "github.com/slackhq/nebula/cert" ) // waitForNebula waits for the nebula interface to have been started up. It does // this by attempting to create a UDP connection which has the nebula IP set as // its source. If this succeeds we can assume that at the very least the nebula // interface has been initialized. func waitForNebula( ctx context.Context, logger *mlog.Logger, hostBootstrap bootstrap.Bootstrap, ) error { var ( ip = net.IP(hostBootstrap.ThisHost().IP().AsSlice()) lUDPAddr = &net.UDPAddr{IP: ip, Port: 0} rUDPAddr = &net.UDPAddr{IP: ip, Port: 45535} ) ctx = mctx.Annotate(ctx, "lUDPAddr", lUDPAddr, "rUDPAddr", rUDPAddr) until( ctx, logger, "Creating UDP socket from nebula addr", func(context.Context) error { conn, err := net.DialUDP("udp", lUDPAddr, rUDPAddr) if err != nil { return err } conn.Close() return nil }, ) return ctx.Err() } func nebulaPmuxProcConfig( runtimeDirPath, binDirPath string, daemonConfig Config, hostBootstrap bootstrap.Bootstrap, ) ( pmuxlib.ProcessConfig, error, ) { var ( lighthouseHostIPs []string staticHostMap = map[string][]string{} ) for _, host := range hostBootstrap.Hosts { if host.Nebula.PublicAddr == "" { continue } ip := host.IP().String() lighthouseHostIPs = append(lighthouseHostIPs, ip) staticHostMap[ip] = []string{host.Nebula.PublicAddr} } caCertPEM, err := hostBootstrap.CAPublicCredentials.Cert.Unwrap().MarshalToPEM() if err != nil { return pmuxlib.ProcessConfig{}, fmt.Errorf( "marshaling CA cert to PEM: :%w", err, ) } hostCertPEM, err := hostBootstrap.PublicCredentials.Cert.Unwrap().MarshalToPEM() if err != nil { return pmuxlib.ProcessConfig{}, fmt.Errorf( "marshaling host cert to PEM: :%w", err, ) } hostKeyPEM := cert.MarshalX25519PrivateKey( hostBootstrap.PrivateCredentials.EncryptingPrivateKey.Bytes(), ) config := map[string]interface{}{ "pki": map[string]string{ "ca": string(caCertPEM), "cert": string(hostCertPEM), "key": string(hostKeyPEM), }, "static_host_map": staticHostMap, "punchy": map[string]bool{ "punch": true, "respond": true, }, "tun": map[string]interface{}{ "dev": daemonConfig.VPN.Tun.Device, }, "firewall": daemonConfig.VPN.Firewall, } if publicAddr := daemonConfig.VPN.PublicAddr; publicAddr == "" { config["listen"] = map[string]string{ "host": "0.0.0.0", "port": "0", } config["lighthouse"] = map[string]interface{}{ "hosts": lighthouseHostIPs, } } else { _, port, err := net.SplitHostPort(publicAddr) if err != nil { return pmuxlib.ProcessConfig{}, fmt.Errorf("parsing public address %q: %w", publicAddr, err) } config["listen"] = map[string]string{ "host": "0.0.0.0", "port": port, } config["lighthouse"] = map[string]interface{}{ "hosts": []string{}, "am_lighthouse": true, } } nebulaYmlPath := filepath.Join(runtimeDirPath, "nebula.yml") if err := yamlutil.WriteYamlFile(config, nebulaYmlPath, 0600); err != nil { return pmuxlib.ProcessConfig{}, fmt.Errorf("writing nebula.yml to %q: %w", nebulaYmlPath, err) } return pmuxlib.ProcessConfig{ Cmd: filepath.Join(binDirPath, "nebula"), Args: []string{"-config", nebulaYmlPath}, Group: -1, // Make sure nebula is shut down last. }, nil }