github.com/google/fleetspeak@v0.1.15-0.20240426164851-4f31f62c1aea/fleetspeak/src/server/https/https.go (about) 1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package https implements an https-based server Communicator. It is the 16 // primary way for clients to communicate with the FS server. 17 package https 18 19 import ( 20 "crypto/tls" 21 "net" 22 "net/http" 23 "sync" 24 "time" 25 26 log "github.com/golang/glog" 27 28 "github.com/google/fleetspeak/fleetspeak/src/server/authorizer" 29 "github.com/google/fleetspeak/fleetspeak/src/server/comms" 30 31 cpb "github.com/google/fleetspeak/fleetspeak/src/server/components/proto/fleetspeak_components" 32 ) 33 34 const ( 35 // MaxContactSize is the largest contact (in bytes) that we will accept. 36 MaxContactSize = 20 * 1024 * 1024 37 ) 38 39 // Communicator implements server.Communicator, and accepts client connections 40 // over HTTPS. 41 type Communicator struct { 42 p Params 43 hs http.Server 44 l net.Listener 45 fs comms.Context 46 stopping chan struct{} 47 running bool 48 runningLock sync.RWMutex 49 pending sync.WaitGroup 50 } 51 52 type guardedListener struct { 53 net.Listener 54 auth authorizer.Authorizer 55 } 56 57 func (l guardedListener) Accept() (net.Conn, error) { 58 for { 59 c, err := l.Listener.Accept() 60 if err != nil { 61 return nil, err 62 } 63 if l.auth.Allow1(c.RemoteAddr()) { 64 return c, err 65 } 66 c.Close() 67 } 68 } 69 70 type listener struct { 71 *net.TCPListener 72 } 73 74 func (l listener) Accept() (net.Conn, error) { 75 tc, err := l.AcceptTCP() 76 if err != nil { 77 return nil, err 78 } 79 tc.SetKeepAlive(true) 80 tc.SetKeepAlivePeriod(1 * time.Minute) 81 tc.SetNoDelay(false) 82 return tc, nil 83 } 84 85 // Params wraps the parameters required to create an https communicator. 86 type Params struct { 87 Listener net.Listener // Where to listen for connections, required. 88 Cert, Key []byte // x509 encoded certificate and matching private key, required. 89 Streaming bool // Whether to enable streaming communications. 90 FrontendConfig *cpb.FrontendConfig // Configure how the frontend identifies and communicates with clients 91 StreamingLifespan time.Duration // Maximum time to keep a streaming connection open, defaults to 10 min. 92 StreamingCloseTime time.Duration // How much of StreamingLifespan to allocate to an orderly stream close, defaults to 30 sec. 93 StreamingJitter time.Duration // Maximum amount of jitter to add to StreamingLifespan. 94 MaxPerClientBatchProcessors uint32 // Maximum number of concurrent processors for messages coming from a single client. 95 } 96 97 // NewCommunicator creates a Communicator, which listens through l and identifies 98 // itself using certFile and keyFile. 99 func NewCommunicator(p Params) (*Communicator, error) { 100 if p.StreamingLifespan == 0 { 101 p.StreamingLifespan = 10 * time.Minute 102 } 103 if p.StreamingCloseTime == 0 { 104 p.StreamingCloseTime = 30 * time.Second 105 } 106 if p.MaxPerClientBatchProcessors == 0 { 107 p.MaxPerClientBatchProcessors = 10 108 } 109 110 mux := http.NewServeMux() 111 h := Communicator{ 112 p: p, 113 hs: http.Server{ 114 Handler: mux, 115 ReadTimeout: 20 * time.Minute, 116 ReadHeaderTimeout: 10 * time.Second, 117 WriteTimeout: 20 * time.Minute, 118 IdleTimeout: 30 * time.Second, 119 }, 120 stopping: make(chan struct{}), 121 } 122 123 if p.FrontendConfig.GetCleartextHeaderConfig() == nil && 124 p.FrontendConfig.GetCleartextHeaderChecksumConfig() == nil && 125 p.FrontendConfig.GetCleartextXfccConfig() == nil { 126 c, err := tls.X509KeyPair(p.Cert, p.Key) 127 if err != nil { 128 return nil, err 129 } 130 h.hs.TLSConfig = &tls.Config{ 131 ClientAuth: tls.RequestClientCert, 132 Certificates: []tls.Certificate{c}, 133 CipherSuites: []uint16{ 134 // We may as well allow only the strongest (as far as we can guess) 135 // ciphers. Note that TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 is 136 // required by the https library. 137 tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 138 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 139 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 140 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 141 // Correctly implementing session tickets means sharing and rotating a 142 // secret key between servers, with implications if it leaks. Simply 143 // disable for the moment. 144 SessionTicketsDisabled: true, 145 MinVersion: tls.VersionTLS12, 146 NextProtos: []string{"h2"}, 147 } 148 } 149 mux.Handle("/message", messageServer{&h}) 150 if p.Streaming { 151 mux.Handle("/streaming-message", newStreamingMessageServer(&h, p.MaxPerClientBatchProcessors)) 152 } 153 mux.Handle("/files/", fileServer{&h}) 154 155 switch l := h.p.Listener.(type) { 156 case *net.TCPListener: 157 h.p.Listener = listener{l} 158 default: 159 } 160 161 return &h, nil 162 } 163 164 func (c *Communicator) serve(l net.Listener) { 165 err := c.hs.Serve(l) 166 log.Errorf("Serving finished with error: %v", err) 167 } 168 169 func (c *Communicator) Setup(fs comms.Context) error { 170 c.fs = fs 171 c.p.Listener = guardedListener{ 172 Listener: c.p.Listener, 173 auth: fs.Authorizer(), 174 } 175 return nil 176 } 177 178 func (c *Communicator) Start() error { 179 switch { 180 case c.p.FrontendConfig.GetCleartextHeaderConfig() != nil, 181 c.p.FrontendConfig.GetCleartextHeaderChecksumConfig() != nil, 182 c.p.FrontendConfig.GetCleartextXfccConfig() != nil: 183 go c.serve(c.p.Listener) 184 default: 185 go c.serve(tls.NewListener(c.p.Listener, c.hs.TLSConfig)) 186 } 187 c.runningLock.Lock() 188 defer c.runningLock.Unlock() 189 c.running = true 190 return nil 191 } 192 193 func (c *Communicator) Stop() { 194 // The most graceful way to shut down an http.Server is to close the associated listener. 195 c.p.Listener.Close() 196 c.runningLock.Lock() 197 c.running = false 198 c.runningLock.Unlock() 199 close(c.stopping) 200 c.pending.Wait() 201 } 202 203 // startProcessing returns if we are up and running. If we are up and running, 204 // it updates the pending operation count to support orderly shutdown. 205 func (c *Communicator) startProcessing() bool { 206 c.runningLock.RLock() 207 defer c.runningLock.RUnlock() 208 if c.running { 209 c.pending.Add(1) 210 } 211 return c.running 212 } 213 214 func (c *Communicator) stopProcessing() { 215 c.pending.Done() 216 }