Example #1
0
// ServeConn serves a single connection, driving the handshake process
// and delegating to the appropriate connection type.
func (s *Server) ServeConn(conn net.Conn) error {
	var draining bool
	{
		s.mu.Lock()
		draining = s.mu.draining
		s.mu.Unlock()
	}

	// If the Server is draining, we will use the connection only to send an
	// error, so we don't count it in the stats. This makes sense since
	// DrainClient() waits for that number to drop to zero,
	// so we don't want it to oscillate unnecessarily.
	if !draining {
		s.metrics.Conns.Inc(1)
		defer s.metrics.Conns.Dec(1)
	}

	var buf readBuffer
	n, err := buf.readUntypedMsg(conn)
	if err != nil {
		return err
	}
	s.metrics.BytesInCount.Inc(int64(n))
	version, err := buf.getUint32()
	if err != nil {
		return err
	}
	errSSLRequired := false
	if version == versionSSL {
		if len(buf.msg) > 0 {
			return errors.Errorf("unexpected data after SSLRequest: %q", buf.msg)
		}

		if s.context.Insecure {
			if _, err := conn.Write(sslUnsupported); err != nil {
				return err
			}
		} else {
			if _, err := conn.Write(sslSupported); err != nil {
				return err
			}
			tlsConfig, err := s.context.GetServerTLSConfig()
			if err != nil {
				return err
			}
			conn = tls.Server(conn, tlsConfig)
		}

		n, err := buf.readUntypedMsg(conn)
		if err != nil {
			return err
		}
		s.metrics.BytesInCount.Inc(int64(n))
		version, err = buf.getUint32()
		if err != nil {
			return err
		}
	} else if !s.context.Insecure {
		errSSLRequired = true
	}

	if version == version30 {
		sessionArgs, argsErr := parseOptions(buf.msg)
		// We make a connection regardless of argsErr. If there was an error parsing
		// the args, the connection will only be used to send a report of that
		// error.
		v3conn := makeV3Conn(conn, s.executor, s.metrics, sessionArgs)
		defer v3conn.finish()
		if argsErr != nil {
			return v3conn.sendInternalError(argsErr.Error())
		}
		if errSSLRequired {
			return v3conn.sendInternalError(ErrSSLRequired)
		}
		if draining {
			// TODO(tschottdorf): Likely not handled gracefully by clients.
			// See #6295.
			return v3conn.sendInternalError(ErrDraining)
		}

		if tlsConn, ok := conn.(*tls.Conn); ok {
			tlsState := tlsConn.ConnectionState()
			authenticationHook, err := security.UserAuthHook(s.context.Insecure, &tlsState)
			if err != nil {
				return v3conn.sendInternalError(err.Error())
			}
			return v3conn.serve(authenticationHook)
		}
		return v3conn.serve(nil)
	}

	return errors.Errorf("unknown protocol version %d", version)
}
Example #2
0
// serveConn serves a single connection, driving the handshake process
// and delegating to the appropriate connection type.
func (s *Server) serveConn(conn net.Conn) error {
	var buf readBuffer
	n, err := buf.readUntypedMsg(conn)
	if err != nil {
		return err
	}
	s.metrics.bytesInCount.Inc(int64(n))
	version, err := buf.getInt32()
	if err != nil {
		return err
	}
	errSSLRequired := false
	if version == versionSSL {
		if len(buf.msg) > 0 {
			return util.Errorf("unexpected data after SSLRequest: %q", buf.msg)
		}

		if s.context.Insecure {
			if _, err := conn.Write(sslUnsupported); err != nil {
				return err
			}
		} else {
			if _, err := conn.Write(sslSupported); err != nil {
				return err
			}
			tlsConfig, err := s.context.GetServerTLSConfig()
			if err != nil {
				return err
			}
			conn = tls.Server(conn, tlsConfig)
		}

		n, err := buf.readUntypedMsg(conn)
		if err != nil {
			return err
		}
		s.metrics.bytesInCount.Inc(int64(n))
		version, err = buf.getInt32()
		if err != nil {
			return err
		}
	} else if !s.context.Insecure {
		errSSLRequired = true
	}

	if version == version30 {
		v3conn := makeV3Conn(conn, s.context.Executor, s.metrics)
		// This is better than always flushing on error.
		defer func() {
			if err := v3conn.wr.Flush(); err != nil {
				log.Error(err)
			}
		}()
		if errSSLRequired {
			return v3conn.sendError(ErrSSLRequired)
		}
		if err := v3conn.parseOptions(buf.msg); err != nil {
			return v3conn.sendError(err.Error())
		}
		if tlsConn, ok := conn.(*tls.Conn); ok {
			tlsState := tlsConn.ConnectionState()
			authenticationHook, err := security.UserAuthHook(s.context.Insecure, &tlsState)
			if err != nil {
				return v3conn.sendError(err.Error())
			}
			return v3conn.serve(authenticationHook)
		}
		return v3conn.serve(nil)
	}

	return util.Errorf("unknown protocol version %d", version)
}
Example #3
0
// ServeConn serves a single connection, driving the handshake process
// and delegating to the appropriate connection type.
func (s *Server) ServeConn(conn net.Conn) error {
	s.metrics.conns.Inc(1)
	defer s.metrics.conns.Dec(1)

	var buf readBuffer
	n, err := buf.readUntypedMsg(conn)
	if err != nil {
		return err
	}
	s.metrics.bytesInCount.Inc(int64(n))
	version, err := buf.getInt32()
	if err != nil {
		return err
	}
	errSSLRequired := false
	if version == versionSSL {
		if len(buf.msg) > 0 {
			return util.Errorf("unexpected data after SSLRequest: %q", buf.msg)
		}

		if s.context.Insecure {
			if _, err := conn.Write(sslUnsupported); err != nil {
				return err
			}
		} else {
			if _, err := conn.Write(sslSupported); err != nil {
				return err
			}
			tlsConfig, err := s.context.GetServerTLSConfig()
			if err != nil {
				return err
			}
			conn = tls.Server(conn, tlsConfig)
		}

		n, err := buf.readUntypedMsg(conn)
		if err != nil {
			return err
		}
		s.metrics.bytesInCount.Inc(int64(n))
		version, err = buf.getInt32()
		if err != nil {
			return err
		}
	} else if !s.context.Insecure {
		errSSLRequired = true
	}

	if version == version30 {
		sessionArgs, argsErr := parseOptions(buf.msg)
		// We make a connection regardless of argsErr. If there was an error parsing
		// the args, the connection will only be used to send a report of that
		// error.
		v3conn := makeV3Conn(conn, s.executor, s.metrics, sessionArgs)
		defer v3conn.finish()
		if argsErr != nil {
			return v3conn.sendInternalError(err.Error())
		}
		if errSSLRequired {
			return v3conn.sendInternalError(ErrSSLRequired)
		}
		if tlsConn, ok := conn.(*tls.Conn); ok {
			tlsState := tlsConn.ConnectionState()
			authenticationHook, err := security.UserAuthHook(s.context.Insecure, &tlsState)
			if err != nil {
				return v3conn.sendInternalError(err.Error())
			}
			return v3conn.serve(authenticationHook)
		}
		return v3conn.serve(nil)
	}

	return util.Errorf("unknown protocol version %d", version)
}