package daemon import ( "context" "fmt" "isle/bootstrap" "isle/yamlutil" "net" "path/filepath" "code.betamike.com/micropelago/pmux/pmuxlib" "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, hostBootstrap bootstrap.Bootstrap, ) error { ip := hostBootstrap.ThisHost().IP() lUdpAddr := &net.UDPAddr{IP: ip, Port: 0} rUdpAddr := &net.UDPAddr{IP: ip, Port: 45535} return until(ctx, func(context.Context) error { conn, err := net.DialUDP("udp", lUdpAddr, rUdpAddr) if err != nil { return err } conn.Close() return nil }) } func nebulaPmuxProcConfig( runtimeDirPath, binDirPath string, hostBootstrap bootstrap.Bootstrap, daemonConfig Config, ) ( 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, 0440); err != nil { return pmuxlib.ProcessConfig{}, fmt.Errorf("writing nebula.yml to %q: %w", nebulaYmlPath, err) } return pmuxlib.ProcessConfig{ Name: "nebula", Cmd: filepath.Join(binDirPath, "nebula"), Args: []string{"-config", nebulaYmlPath}, }, nil }