func main() { fixListenPid() listeners, _ := activation.Listeners(false) if len(listeners) == 0 { panic("No listeners") } if os.Getenv("LISTEN_PID") == "" || os.Getenv("LISTEN_FDS") == "" { panic("Should not unset envs") } listeners, err := activation.Listeners(true) if err != nil { panic(err) } if os.Getenv("LISTEN_PID") != "" || os.Getenv("LISTEN_FDS") != "" { panic("Can not unset envs") } c0, _ := listeners[0].Accept() c1, _ := listeners[1].Accept() // Write out the expected strings to the two pipes c0.Write([]byte("Hello world")) c1.Write([]byte("Goodbye world")) return }
// Init sets up the Daemon's internal workings. // Don't call more than once. func (d *Daemon) Init() error { t0 := time.Now() listeners, err := activation.Listeners(false) if err != nil { return err } listenerMap := make(map[string]net.Listener) for _, listener := range listeners { listenerMap[listener.Addr().String()] = listener } // The SnapdSocket is required-- without it, die. if listener, ok := listenerMap[dirs.SnapdSocket]; ok { d.snapdListener = &ucrednetListener{listener} } else { return fmt.Errorf("daemon is missing the listener for %s", dirs.SnapdSocket) } // Note that the SnapSocket listener does not use ucrednet. We use the lack // of remote information as an indication that the request originated with // this socket. This listener may also be nil if that socket wasn't among // the listeners, so check it before using it. d.snapListener = listenerMap[dirs.SnapSocket] d.addRoutes() logger.Debugf("init done in %s", time.Now().Sub(t0)) return nil }
func fdListener(addr string) (net.Listener, error) { fdOffset := 0 if addr != "" { fd, err := strconv.Atoi(addr) if err != nil { return nil, fmt.Errorf("fd index is not a number") } fdOffset = fd - 3 } listeners, err := activation.Listeners(false) if err != nil { return nil, err } if fdOffset >= len(listeners) { return nil, fmt.Errorf("fd %v is out of range (%v)", addr, len(listeners)+3) } if listeners[fdOffset] == nil { return nil, fmt.Errorf("fd %v was not socket activated", addr) } return listeners[fdOffset], nil }
// ListenFD returns the specified socket activated files as a slice of // net.Listeners or all of the activated files if "*" is given. func ListenFD(addr string) ([]net.Listener, error) { // socket activation listeners, err := activation.Listeners(false) if err != nil { return nil, err } if listeners == nil || len(listeners) == 0 { return nil, errors.New("No sockets found") } // default to all fds just like unix:// and tcp:// if addr == "" { addr = "*" } fdNum, _ := strconv.Atoi(addr) fdOffset := fdNum - 3 if (addr != "*") && (len(listeners) < int(fdOffset)+1) { return nil, errors.New("Too few socket activated files passed in") } if addr == "*" { return listeners, nil } return []net.Listener{listeners[fdOffset]}, nil }
func main() { log.SetFlags(0) flag.Parse() os.Setenv("DISCOVERY_URL", url) if os.Getenv("DISCOVERY_ADDR") != "" { http.ListenAndServe(os.Getenv("DISCOVERY_ADDR"), nil) } else { if *addr != "" { http.ListenAndServe(*addr, nil) } } listeners, err := activation.Listeners(true) if err != nil { panic(err) } if len(listeners) != 1 { log.Print(len(listeners)) panic("Unexpected number of socket activation fds:") } http.Serve(listeners[0], nil) }
func socketActivationListener() net.Listener { listeners, err := activation.Listeners(true) if err != nil { panic(err) } if len(listeners) != 1 { panic(fmt.Sprintf("Unexpected number of socket activation fds, got: %d listeners, expected 1!", len(listeners))) } return listeners[0] }
func main() { listeners, err := activation.Listeners(true) if err != nil { panic(err) } if len(listeners) != 1 { panic("Unexpected number of socket activation fds") } http.HandleFunc("/", HelloServer) http.Serve(listeners[0], nil) }
func (s *Server) systemdServe() { // We will usually have at least one TCP socket and one UDP socket. // PacketConns are UDP sockets, Listeners are TCP sockets. // To make things more annoying, both can (and usually will) have nil // entries for the file descriptors that don't match. pconns, err := activation.PacketConns(false) if err != nil { glog.Fatalf("Error getting systemd packet conns: %v", err) } listeners, err := activation.Listeners(false) if err != nil { glog.Fatalf("Error getting systemd listeners: %v", err) } var wg sync.WaitGroup for _, pconn := range pconns { if pconn == nil { continue } wg.Add(1) go func(c net.PacketConn) { defer wg.Done() glog.Infof("Activate on packet connection (UDP)") err := dns.ActivateAndServe(nil, c, dns.HandlerFunc(s.Handler)) glog.Fatalf("Exiting UDP listener: %v", err) }(pconn) } for _, lis := range listeners { if lis == nil { continue } wg.Add(1) go func(l net.Listener) { defer wg.Done() glog.Infof("Activate on listening socket (TCP)") err := dns.ActivateAndServe(l, nil, dns.HandlerFunc(s.Handler)) glog.Fatalf("Exiting TCP listener: %v", err) }(lis) } wg.Wait() // We should only get here if there were no useful sockets. glog.Fatalf("No systemd sockets, did you forget the .socket?") }
// Serve either serves on the previously opened sockets if started with systemd-compatible protocol, or: // - opens sockets and starts /proc/self/exe in a subprocess with systemd-compatible protocol // - gracefully terminates subprocess on SIGTERM // - gracefully restarts subprocess on SIGUSR2 func Serve(servers ...*http.Server) error { // Simplify LISTEN_PID protocol because it is harder to set PID between // fork and exec in Golang. pid := os.Getenv(listenPID) initActivated := len(pid) != 0 && pid != "0" if pid == "0" { if err := os.Setenv(listenPID, strconv.Itoa(os.Getpid())); err != nil { return err } } listeners, _ := activation.Listeners(true) // ignore error: always nil didInherit := len(listeners) != 0 if *verbose { if didInherit { if initActivated { log.Printf("Listening on init activated %s", pprintAddr(servers)) } else { const msg = "Graceful handoff of %s with new pid %d" log.Printf(msg, pprintAddr(servers), os.Getpid()) } } else { const msg = "Serving %s with pid %d" log.Printf(msg, pprintAddr(servers), os.Getpid()) } } if didInherit { // Serve. return serve(listeners, servers) } // Listen and fork&exec to serve. fds := make([]*os.File, len(servers)) for i, srv := range servers { l, err := net.Listen("tcp", srv.Addr) if err != nil { return err } fds[i], err = l.(*net.TCPListener).File() if err != nil { return err } defer fds[i].Close() // ignore error } return runServer(fds) }
func cmdRunSa(c *cli.Context) error { s, err := openAndCheck(c) if err != nil { return cli.NewExitError(err.Error(), 3) } listeners, err := activation.Listeners(true) if err != nil { return cli.NewExitError(fmt.Sprintf("fetching socket listeners from systemd failed: %s", err), 2) } fmt.Printf("got %d sockets from systemd\n", len(listeners)) if len(listeners) == 0 { return cli.NewExitError("shutting down since there are no sockets to lissten on.", 2) } var wg sync.WaitGroup for idx, listener := range listeners { switch listener.(type) { case *net.UnixListener: fmt.Printf("listener[%d]: is a UNIX socket (-> saslauthd)\n", idx) wg.Add(1) ln := listener.(*net.UnixListener) go func() { defer wg.Done() if err := runSaslAuthSocketListener(ln, s.GetInterface()); err != nil { fmt.Printf("warning running auth agent failed: %s\n", err) } }() case *net.TCPListener: fmt.Printf("listener[%d]: is a TCP socket (-> HTTP)\n", idx) wg.Add(1) ln := listener.(*net.TCPListener) go func() { defer wg.Done() if err := runWebListener(ln, s.GetInterface(), c.GlobalString("web-static-dir")); err != nil { fmt.Printf("error running web-api: %s", err) } }() default: fmt.Printf("listener[%d]: has type %T (ingnoring)\n", idx, listener) } } wg.Wait() return cli.NewExitError(fmt.Sprintf("shutting down since all auth sockets have closed."), 0) }
// listenFD returns the specified socket activated files as a slice of // net.Listeners or all of the activated files if "*" is given. func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) { var ( err error listeners []net.Listener ) // socket activation if tlsConfig != nil { listeners, err = activation.TLSListeners(false, tlsConfig) } else { listeners, err = activation.Listeners(false) } if err != nil { return nil, err } if len(listeners) == 0 { return nil, fmt.Errorf("no sockets found via socket activation: make sure the service was started by systemd") } // default to all fds just like unix:// and tcp:// if addr == "" || addr == "*" { return listeners, nil } fdNum, err := strconv.Atoi(addr) if err != nil { return nil, fmt.Errorf("failed to parse systemd fd address: should be a number: %v", addr) } fdOffset := fdNum - 3 if len(listeners) < int(fdOffset)+1 { return nil, fmt.Errorf("too few socket activated files passed in by systemd") } if listeners[fdOffset] == nil { return nil, fmt.Errorf("failed to listen on systemd activated file: fd %d", fdOffset+3) } for i, ls := range listeners { if i == fdOffset || ls == nil { continue } if err := ls.Close(); err != nil { // TODO: We shouldn't log inside a library. Remove this or error out. logrus.Errorf("failed to close systemd activated file: fd %d: %v", fdOffset+3, err) } } return []net.Listener{listeners[fdOffset]}, nil }
// listenFD returns the specified socket activated files as a slice of // net.Listeners or all of the activated files if "*" is given. func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) { var ( err error listeners []net.Listener ) // socket activation if tlsConfig != nil { listeners, err = systemdActivation.TLSListeners(false, tlsConfig) } else { listeners, err = systemdActivation.Listeners(false) } if err != nil { return nil, err } if len(listeners) == 0 { return nil, fmt.Errorf("No sockets found") } // default to all fds just like unix:// and tcp:// if addr == "" || addr == "*" { return listeners, nil } fdNum, err := strconv.Atoi(addr) if err != nil { return nil, fmt.Errorf("failed to parse systemd address, should be number: %v", err) } fdOffset := fdNum - 3 if len(listeners) < int(fdOffset)+1 { return nil, fmt.Errorf("Too few socket activated files passed in") } if listeners[fdOffset] == nil { return nil, fmt.Errorf("failed to listen on systemd activated file at fd %d", fdOffset+3) } for i, ls := range listeners { if i == fdOffset || ls == nil { continue } if err := ls.Close(); err != nil { logrus.Errorf("Failed to close systemd activated file at fd %d: %v", fdOffset+3, err) } } return []net.Listener{listeners[fdOffset]}, nil }
func main() { log.SetFlags(0) flag.Parse() if *addr != "" { http.ListenAndServe(*addr, nil) } listeners, err := activation.Listeners(true) if err != nil { panic(err) } if len(listeners) != 1 { panic("Unexpected number of socket activation fds") } http.Serve(listeners[0], nil) }
// Init sets up the Daemon's internal workings. // Don't call more than once. func (d *Daemon) Init() error { t0 := time.Now() listeners, err := activation.Listeners(false) if err != nil { return err } if len(listeners) != 1 { return fmt.Errorf("daemon does not handle %d listeners right now, just one", len(listeners)) } d.listener = listeners[0] d.addRoutes() logger.Debugf("init done in %s", time.Now().Sub(t0)) return nil }
func getListener() (net.Listener, error) { l, err := activation.Listeners(true) if err != nil { return nil, err } switch { case len(l) == 0: if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil { return nil, err } return net.Listen("unix", socketPath) case len(l) == 1: if l[0] == nil { return nil, fmt.Errorf("LISTEN_FDS=1 but no FD found") } return l[0], nil default: return nil, fmt.Errorf("Too many (%v) FDs passed through socket activation", len(l)) } }
// Run is a blocking operation that starts the server listening on the DNS ports. func (s *server) Run() error { mux := dns.NewServeMux() mux.Handle(".", s) dnsReadyMsg := func(addr, net string) { if s.config.DNSSEC == "" { log.Printf("skydns: ready for queries on %s for %s://%s [rcache %d]", s.config.Domain, net, addr, s.config.RCache) } else { log.Printf("skydns: ready for queries on %s for %s://%s [rcache %d], signing with %s [scache %d]", s.config.Domain, net, addr, s.config.RCache, s.config.DNSSEC, s.config.SCache) } } if s.config.Systemd { packetConns, err := activation.PacketConns(false) if err != nil { return err } listeners, err := activation.Listeners(true) if err != nil { return err } if len(packetConns) == 0 && len(listeners) == 0 { return fmt.Errorf("no UDP or TCP sockets supplied by systemd") } for _, p := range packetConns { if u, ok := p.(*net.UDPConn); ok { s.group.Add(1) go func() { defer s.group.Done() if err := dns.ActivateAndServe(nil, u, mux); err != nil { log.Fatalf("skydns: %s", err) } }() dnsReadyMsg(u.LocalAddr().String(), "udp") } } for _, l := range listeners { if t, ok := l.(*net.TCPListener); ok { s.group.Add(1) go func() { defer s.group.Done() if err := dns.ActivateAndServe(t, nil, mux); err != nil { log.Fatalf("skydns: %s", err) } }() dnsReadyMsg(t.Addr().String(), "tcp") } } } else { s.group.Add(1) go func() { defer s.group.Done() if err := dns.ListenAndServe(s.config.DnsAddr, "tcp", mux); err != nil { log.Fatalf("skydns: %s", err) } }() dnsReadyMsg(s.config.DnsAddr, "tcp") s.group.Add(1) go func() { defer s.group.Done() if err := dns.ListenAndServe(s.config.DnsAddr, "udp", mux); err != nil { log.Fatalf("skydns: %s", err) } }() dnsReadyMsg(s.config.DnsAddr, "udp") } s.group.Wait() return nil }
// Run is a blocking operation that starts the server listening on the DNS ports. func (s *server) Run() error { mux := dns.NewServeMux() mux.Handle(".", s) dnsReadyMsg := func(addr, net string) { rCacheState := "disabled" if s.config.RCache > 0 { rCacheState = fmt.Sprintf("capacity: %d", s.config.RCache) } log.Infof("Ready for queries on %s://%s [cache: %s]", net, addr, rCacheState) } if s.config.Systemd { packetConns, err := activation.PacketConns(false) if err != nil { return err } listeners, err := activation.Listeners(true) if err != nil { return err } if len(packetConns) == 0 && len(listeners) == 0 { return fmt.Errorf("No UDP or TCP sockets supplied by systemd") } for _, p := range packetConns { if u, ok := p.(*net.UDPConn); ok { s.group.Add(1) go func() { defer s.group.Done() if err := dns.ActivateAndServe(nil, u, mux); err != nil { log.Fatalf("%s", err) } }() dnsReadyMsg(u.LocalAddr().String(), "udp") } } for _, l := range listeners { if t, ok := l.(*net.TCPListener); ok { s.group.Add(1) go func() { defer s.group.Done() if err := dns.ActivateAndServe(t, nil, mux); err != nil { log.Fatalf("%s", err) } }() dnsReadyMsg(t.Addr().String(), "tcp") } } } else { s.group.Add(1) go func() { defer s.group.Done() if err := dns.ListenAndServe(s.config.DnsAddr, "tcp", mux); err != nil { log.Fatalf("%s", err) } }() dnsReadyMsg(s.config.DnsAddr, "tcp") s.group.Add(1) go func() { defer s.group.Done() if err := dns.ListenAndServe(s.config.DnsAddr, "udp", mux); err != nil { log.Fatalf("%s", err) } }() dnsReadyMsg(s.config.DnsAddr, "udp") } s.group.Wait() return nil }
func (d *Daemon) Init() error { /* Initialize some variables */ d.imagesDownloading = map[string]chan bool{} d.readyChan = make(chan bool) d.shutdownChan = make(chan bool) /* Set the executable path */ absPath, err := os.Readlink("/proc/self/exe") if err != nil { return err } d.execPath = absPath /* Set the LVM environment */ err = os.Setenv("LVM_SUPPRESS_FD_WARNINGS", "1") if err != nil { return err } /* Setup logging if that wasn't done before */ if shared.Log == nil { shared.Log, err = logging.GetLogger("", "", true, true, nil) if err != nil { return err } } /* Print welcome message */ if d.MockMode { shared.Log.Info("LXD is starting in mock mode", log.Ctx{"path": shared.VarPath("")}) } else if d.SetupMode { shared.Log.Info("LXD is starting in setup mode", log.Ctx{"path": shared.VarPath("")}) } else { shared.Log.Info("LXD is starting in normal mode", log.Ctx{"path": shared.VarPath("")}) } /* Detect user namespaces */ runningInUserns = shared.RunningInUserNS() /* Detect AppArmor support */ if aaAvailable && os.Getenv("LXD_SECURITY_APPARMOR") == "false" { aaAvailable = false aaAdmin = false shared.Log.Warn("AppArmor support has been manually disabled") } if aaAvailable && !shared.IsDir("/sys/kernel/security/apparmor") { aaAvailable = false aaAdmin = false shared.Log.Warn("AppArmor support has been disabled because of lack of kernel support") } _, err = exec.LookPath("apparmor_parser") if aaAvailable && err != nil { aaAvailable = false aaAdmin = false shared.Log.Warn("AppArmor support has been disabled because 'apparmor_parser' couldn't be found") } /* Detect AppArmor admin support */ if aaAdmin && !haveMacAdmin() { aaAdmin = false shared.Log.Warn("Per-container AppArmor profiles are disabled because the mac_admin capability is missing.") } if aaAdmin && runningInUserns { aaAdmin = false shared.Log.Warn("Per-container AppArmor profiles are disabled because LXD is running in an unprivileged container.") } /* Detect AppArmor confinment */ if !aaConfined { profile := aaProfile() if profile != "unconfined" && profile != "" { aaConfined = true shared.Log.Warn("Per-container AppArmor profiles are disabled because LXD is already protected by AppArmor.") } } /* Detect CGroup support */ cgBlkioController = shared.PathExists("/sys/fs/cgroup/blkio/") if !cgBlkioController { shared.Log.Warn("Couldn't find the CGroup blkio controller, I/O limits will be ignored.") } cgCpuController = shared.PathExists("/sys/fs/cgroup/cpu/") if !cgCpuController { shared.Log.Warn("Couldn't find the CGroup CPU controller, CPU time limits will be ignored.") } cgCpusetController = shared.PathExists("/sys/fs/cgroup/cpuset/") if !cgCpusetController { shared.Log.Warn("Couldn't find the CGroup CPUset controller, CPU pinning will be ignored.") } cgDevicesController = shared.PathExists("/sys/fs/cgroup/devices/") if !cgDevicesController { shared.Log.Warn("Couldn't find the CGroup devices controller, device access control won't work.") } cgMemoryController = shared.PathExists("/sys/fs/cgroup/memory/") if !cgMemoryController { shared.Log.Warn("Couldn't find the CGroup memory controller, memory limits will be ignored.") } cgNetPrioController = shared.PathExists("/sys/fs/cgroup/net_prio/") if !cgNetPrioController { shared.Log.Warn("Couldn't find the CGroup network class controller, network limits will be ignored.") } cgPidsController = shared.PathExists("/sys/fs/cgroup/pids/") if !cgPidsController { shared.Log.Warn("Couldn't find the CGroup pids controller, process limits will be ignored.") } cgSwapAccounting = shared.PathExists("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes") if !cgSwapAccounting { shared.Log.Warn("CGroup memory swap accounting is disabled, swap limits will be ignored.") } /* Get the list of supported architectures */ var architectures = []int{} architectureName, err := shared.ArchitectureGetLocal() if err != nil { return err } architecture, err := shared.ArchitectureId(architectureName) if err != nil { return err } architectures = append(architectures, architecture) personalities, err := shared.ArchitecturePersonalities(architecture) if err != nil { return err } for _, personality := range personalities { architectures = append(architectures, personality) } d.architectures = architectures /* Set container path */ d.lxcpath = shared.VarPath("containers") /* Make sure all our directories are available */ if err := os.MkdirAll(shared.VarPath("containers"), 0711); err != nil { return err } if err := os.MkdirAll(shared.VarPath("devices"), 0711); err != nil { return err } if err := os.MkdirAll(shared.VarPath("devlxd"), 0755); err != nil { return err } if err := os.MkdirAll(shared.VarPath("images"), 0700); err != nil { return err } if err := os.MkdirAll(shared.LogPath(), 0700); err != nil { return err } if err := os.MkdirAll(shared.VarPath("security"), 0700); err != nil { return err } if err := os.MkdirAll(shared.VarPath("shmounts"), 0711); err != nil { return err } if err := os.MkdirAll(shared.VarPath("snapshots"), 0700); err != nil { return err } /* Detect the filesystem */ d.BackingFs, err = filesystemDetect(d.lxcpath) if err != nil { shared.Log.Error("Error detecting backing fs", log.Ctx{"err": err}) } /* Read the uid/gid allocation */ d.IdmapSet, err = shared.DefaultIdmapSet() if err != nil { shared.Log.Warn("Error reading idmap", log.Ctx{"err": err.Error()}) shared.Log.Warn("Only privileged containers will be able to run") } else { shared.Log.Info("Default uid/gid map:") for _, lxcmap := range d.IdmapSet.ToLxcString() { shared.Log.Info(strings.TrimRight(" - "+lxcmap, "\n")) } } /* Initialize the database */ err = initializeDbObject(d, shared.VarPath("lxd.db")) if err != nil { return err } /* Setup the storage driver */ if !d.MockMode { err = d.SetupStorageDriver() if err != nil { return fmt.Errorf("Failed to setup storage: %s", err) } } /* Load all config values from the database */ _, err = d.ConfigValuesGet() if err != nil { return err } /* set the initial proxy function based on config values in the DB */ d.updateProxy() /* Setup /dev/lxd */ d.devlxd, err = createAndBindDevLxd() if err != nil { return err } if err := setupSharedMounts(); err != nil { return err } if !d.MockMode { /* Start the scheduler */ go deviceEventListener(d) /* Setup the TLS authentication */ certf, keyf, err := readMyCert() if err != nil { return err } cert, err := tls.LoadX509KeyPair(certf, keyf) if err != nil { return err } tlsConfig := &tls.Config{ InsecureSkipVerify: true, ClientAuth: tls.RequestClientCert, Certificates: []tls.Certificate{cert}, MinVersion: tls.VersionTLS12, MaxVersion: tls.VersionTLS12, CipherSuites: []uint16{ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, PreferServerCipherSuites: true, } tlsConfig.BuildNameToCertificate() d.tlsConfig = tlsConfig readSavedClientCAList(d) } /* Setup the web server */ d.mux = mux.NewRouter() d.mux.StrictSlash(false) d.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") SyncResponse(true, []string{"/1.0"}).Render(w) }) for _, c := range api10 { d.createCmd("1.0", c) } for _, c := range apiInternal { d.createCmd("internal", c) } d.mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { shared.Log.Debug("Sending top level 404", log.Ctx{"url": r.URL}) w.Header().Set("Content-Type", "application/json") NotFound.Render(w) }) listeners, err := activation.Listeners(false) if err != nil { return err } if len(listeners) > 0 { shared.Log.Info("LXD is socket activated") for _, listener := range listeners { if shared.PathExists(listener.Addr().String()) { d.UnixSocket = &Socket{Socket: listener, CloseOnExit: false} } else { tlsListener := tls.NewListener(listener, d.tlsConfig) d.TCPSocket = &Socket{Socket: tlsListener, CloseOnExit: false} } } } else { shared.Log.Info("LXD isn't socket activated") localSocketPath := shared.VarPath("unix.socket") // If the socket exists, let's try to connect to it and see if there's // a lxd running. if shared.PathExists(localSocketPath) { _, err := lxd.NewClient(&lxd.DefaultConfig, "local") if err != nil { shared.Log.Debug("Detected stale unix socket, deleting") // Connecting failed, so let's delete the socket and // listen on it ourselves. err = os.Remove(localSocketPath) if err != nil { return err } } else { return fmt.Errorf("LXD is already running.") } } unixAddr, err := net.ResolveUnixAddr("unix", localSocketPath) if err != nil { return fmt.Errorf("cannot resolve unix socket address: %v", err) } unixl, err := net.ListenUnix("unix", unixAddr) if err != nil { return fmt.Errorf("cannot listen on unix socket: %v", err) } if err := os.Chmod(localSocketPath, 0660); err != nil { return err } var gid int if d.group != "" { gid, err = shared.GroupId(d.group) if err != nil { return err } } else { gid = os.Getgid() } if err := os.Chown(localSocketPath, os.Getuid(), gid); err != nil { return err } d.UnixSocket = &Socket{Socket: unixl, CloseOnExit: true} } listenAddr, err := d.ConfigValueGet("core.https_address") if err != nil { return err } if listenAddr != "" { _, _, err := net.SplitHostPort(listenAddr) if err != nil { listenAddr = fmt.Sprintf("%s:%s", listenAddr, shared.DefaultPort) } tcpl, err := tls.Listen("tcp", listenAddr, d.tlsConfig) if err != nil { shared.Log.Error("cannot listen on https socket, skipping...", log.Ctx{"err": err}) } else { if d.TCPSocket != nil { shared.Log.Info("Replacing systemd TCP socket by configure one") d.TCPSocket.Socket.Close() } d.TCPSocket = &Socket{Socket: tcpl, CloseOnExit: true} } } d.tomb.Go(func() error { shared.Log.Info("REST API daemon:") if d.UnixSocket != nil { shared.Log.Info(" - binding Unix socket", log.Ctx{"socket": d.UnixSocket.Socket.Addr()}) d.tomb.Go(func() error { return http.Serve(d.UnixSocket.Socket, &lxdHttpServer{d.mux, d}) }) } if d.TCPSocket != nil { shared.Log.Info(" - binding TCP socket", log.Ctx{"socket": d.TCPSocket.Socket.Addr()}) d.tomb.Go(func() error { return http.Serve(d.TCPSocket.Socket, &lxdHttpServer{d.mux, d}) }) } d.tomb.Go(func() error { server := devLxdServer(d) return server.Serve(d.devlxd) }) return nil }) if !d.MockMode && !d.SetupMode { err := d.Ready() if err != nil { return err } } return nil }
func main() { var patterns []matcher var n int if len(os.Args) < 2 { usage() } for n = 1; ; n += 1 { if bytes.Equal([]byte(os.Args[n])[:2], []byte("--")) { break } if n == len(os.Args)-1 { usage() } } firstFilterArg := n for ; n < len(os.Args)-1; n += 2 { if bytes.Equal([]byte(os.Args[n]), []byte("--regex")) { if len(os.Args) < n+2 { fmt.Println("Not enough arguments to --regex") os.Exit(1) } host, port, err := parseHostPort(os.Args[n+2]) if err != nil { fmt.Println("Bad host:port specification:", os.Args[n+2], host, port, err) os.Exit(1) } r, err := regexp.Compile(os.Args[n+1]) if err != nil { fmt.Println("Failed to compile regular expression:", os.Args[n+1], err) os.Exit(1) } patterns = append(patterns, (func(packet []byte, length int) (h string, p int) { h = host if r.Match(packet) { p = port } return })) n += 1 continue } host, port, err := parseHostPort(os.Args[n+1]) if err != nil { fmt.Println("Bad host:port specification:", os.Args[n+1], host, port, err) os.Exit(1) } if bytes.Equal([]byte(os.Args[n]), []byte("--ssh")) { patterns = append(patterns, (func(packet []byte, length int) (h string, p int) { h = host if bytes.Equal(packet[:4], []byte("SSH-")) { p = port } return })) } else if bytes.Equal([]byte(os.Args[n]), []byte("--ssl")) { patterns = append(patterns, (func(pack []byte, length int) (h string, p int) { h = host if bytes.Equal(pack[:2], []byte{0x16, 0x03}) && pack[3] >= 0x00 && pack[3] <= 0x03 { p = port } return })) } else if bytes.Equal([]byte(os.Args[n]), []byte("--openvpn")) { patterns = append(patterns, (func(pack []byte, length int) (h string, p int) { var l uint16 h = host binary.Read(bytes.NewReader(pack), binary.BigEndian, &l) if l == uint16(length-2) { p = port } return })) } } listeners, err := activation.Listeners(true) if err != nil { panic(err) } // If we recieved any sockets from systemd do not open our own listeners if len(listeners) > 0 { for _, ln := range listeners { go handleListener(ln, patterns) } } else { if firstFilterArg == 1 { fmt.Println("No listen port(s) specified and did not recieve and not being systemd socket activated") os.Exit(1) } for n = 1; n < firstFilterArg; n += 1 { host, port, err := parseHostPort(os.Args[n]) if err != nil { fmt.Println("Bad Listen host:port:", os.Args[n]) break } if bytes.Compare([]byte(host), []byte("localhost")) == 0 { host = "0.0.0.0" } ln, err := net.Listen("tcp", fmt.Sprint(host, ":", port)) if err != nil { fmt.Println("Listen failed:", err) break } go handleListener(ln, patterns) } } }
func New(cfg config.Config, listeners []net.Listener) (*Server, error) { agentTTL, err := time.ParseDuration(cfg.AgentTTL) if err != nil { return nil, err } mgr, err := systemd.NewSystemdUnitManager(systemd.DefaultUnitsDirectory) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } eCfg := etcd.Config{ Transport: &http.Transport{TLSClientConfig: tlsConfig}, Endpoints: cfg.EtcdServers, HeaderTimeoutPerRequest: (time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond), } eClient, err := etcd.New(eCfg) if err != nil { return nil, err } kAPI := etcd.NewKeysAPI(eClient) reg := registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix) pub := agent.NewUnitStatePublisher(reg, mach, agentTTL) gen := unit.NewUnitStateGenerator(mgr) a := agent.New(mgr, gen, reg, mach, agentTTL) var rStream pkg.EventStream if !cfg.DisableWatches { rStream = registry.NewEtcdEventStream(kAPI, cfg.EtcdKeyPrefix) } lManager := lease.NewEtcdLeaseManager(kAPI, cfg.EtcdKeyPrefix) ar := agent.NewReconciler(reg, rStream) e := engine.New(reg, lManager, rStream, mach) if len(listeners) == 0 { listeners, err = activation.Listeners(false) if err != nil { return nil, err } } hrt := heart.New(reg, mach) mon := NewMonitor(agentTTL) apiServer := api.NewServer(listeners, api.NewServeMux(reg, cfg.TokenLimit)) apiServer.Serve() eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, mach: mach, hrt: hrt, mon: mon, api: apiServer, killc: make(chan struct{}), stopc: nil, engineReconcileInterval: eIval, disableEngine: cfg.DisableEngine, reconfigServer: false, restartServer: false, } return &srv, nil }
// NewServer starts an HTTPS server the handles the redoctober JSON // API. Each of the URIs in the functions map above is setup with a // separate HandleFunc. Each HandleFunc is an instance of queueRequest // above. // // Returns a valid http.Server handling redoctober JSON requests (and // its associated listener) or an error func NewServer(process chan<- userRequest, staticPath, addr, caPath string, certPaths, keyPaths []string, useSystemdSocket bool) (*http.Server, *net.Listener, error) { config := &tls.Config{ PreferServerCipherSuites: true, SessionTicketsDisabled: true, } for i, certPath := range certPaths { cert, err := tls.LoadX509KeyPair(certPath, keyPaths[i]) if err != nil { return nil, nil, fmt.Errorf("Error loading certificate (%s, %s): %s", certPath, keyPaths[i], err) } config.Certificates = append(config.Certificates, cert) } config.BuildNameToCertificate() // If a caPath has been specified then a local CA is being used // and not the system configuration. if caPath != "" { pemCert, err := ioutil.ReadFile(caPath) if err != nil { return nil, nil, fmt.Errorf("Error reading %s: %s\n", caPath, err) } derCert, _ := pem.Decode(pemCert) if derCert == nil { return nil, nil, fmt.Errorf("No PEM data was found in the CA certificate file\n") } cert, err := x509.ParseCertificate(derCert.Bytes) if err != nil { return nil, nil, fmt.Errorf("Error parsing CA certificate: %s\n", err) } rootPool := x509.NewCertPool() rootPool.AddCert(cert) config.ClientAuth = tls.RequireAndVerifyClientCert config.ClientCAs = rootPool } var lstnr net.Listener if useSystemdSocket { listenFDs, err := activation.Listeners(true) if err != nil { log.Fatal(err) } if len(listenFDs) != 1 { log.Fatalf("Unexpected number of socket activation FDs! (%d)", len(listenFDs)) } lstnr = tls.NewListener(listenFDs[0], config) } else { conn, err := net.Listen("tcp", addr) if err != nil { return nil, nil, fmt.Errorf("Error starting TCP listener on %s: %s\n", addr, err) } lstnr = tls.NewListener(conn, config) } mux := http.NewServeMux() // queue up post URIs for current := range functions { // copy this so reference does not get overwritten requestType := current mux.HandleFunc(requestType, func(w http.ResponseWriter, r *http.Request) { log.Printf("http.server: endpoint=%s remote=%s", requestType, r.RemoteAddr) queueRequest(process, requestType, w, r) }) } // queue up web frontend idxHandler := &indexHandler{staticPath} mux.HandleFunc("/index", idxHandler.handle) mux.HandleFunc("/", idxHandler.handle) srv := http.Server{ Addr: addr, Handler: mux, } return &srv, &lstnr, nil }
func New(cfg config.Config, listeners []net.Listener) (*Server, error) { agentTTL, err := time.ParseDuration(cfg.AgentTTL) if err != nil { return nil, err } mgr, err := systemd.NewSystemdUnitManager(cfg.UnitsDirectory, cfg.SystemdUser) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } eCfg := etcd.Config{ Transport: &http.Transport{TLSClientConfig: tlsConfig}, Endpoints: cfg.EtcdServers, HeaderTimeoutPerRequest: (time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond), Username: cfg.EtcdUsername, Password: cfg.EtcdPassword, } eClient, err := etcd.New(eCfg) if err != nil { return nil, err } kAPI := etcd.NewKeysAPI(eClient) var ( reg engine.CompleteRegistry genericReg interface{} ) lManager := lease.NewEtcdLeaseManager(kAPI, cfg.EtcdKeyPrefix) if !cfg.EnableGRPC { genericReg = registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix) if obj, ok := genericReg.(engine.CompleteRegistry); ok { reg = obj } } else { etcdReg := registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix) genericReg = rpc.NewRegistryMux(etcdReg, mach, lManager) if obj, ok := genericReg.(engine.CompleteRegistry); ok { reg = obj } } pub := agent.NewUnitStatePublisher(reg, mach, agentTTL) gen := unit.NewUnitStateGenerator(mgr) a := agent.New(mgr, gen, reg, mach, agentTTL) var rStream pkg.EventStream if !cfg.DisableWatches { rStream = registry.NewEtcdEventStream(kAPI, cfg.EtcdKeyPrefix) } ar := agent.NewReconciler(reg, rStream) var e *engine.Engine if !cfg.EnableGRPC { e = engine.New(reg, lManager, rStream, mach, nil) } else { regMux := genericReg.(*rpc.RegistryMux) e = engine.New(reg, lManager, rStream, mach, regMux.EngineChanged) if cfg.DisableEngine { go regMux.ConnectToRegistry(e) } } if len(listeners) == 0 { listeners, err = activation.Listeners(false) if err != nil { return nil, err } } hrt := heart.New(reg, mach) mon := NewMonitor(agentTTL) apiServer := api.NewServer(listeners, api.NewServeMux(reg, cfg.TokenLimit)) apiServer.Serve() eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, mach: mach, hrt: hrt, mon: mon, api: apiServer, killc: make(chan struct{}), stopc: nil, engineReconcileInterval: eIval, disableEngine: cfg.DisableEngine, reconfigServer: false, restartServer: false, } return &srv, nil }