Add timeouts to http servers

This commit is contained in:
Ryan Smith
2024-11-01 10:31:30 -07:00
parent 855d913ade
commit 16971d7c0d
2 changed files with 46 additions and 28 deletions

View File

@@ -25,54 +25,65 @@ import (
// StartHTTP initializes and starts an HTTP honeypot server. This is a fully // StartHTTP initializes and starts an HTTP honeypot server. This is a fully
// functional HTTP server designed to log all incoming requests for analysis. // functional HTTP server designed to log all incoming requests for analysis.
func StartHTTP(srv *config.Server) { func StartHTTP(cfg *config.Server) {
// Get any custom headers, if provided. // Get any custom headers, if provided.
headers := parseCustomHeaders(srv.Banner) headers := parseCustomHeaders(cfg.Banner)
// Setup handler. // Setup handler and server config.
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("/", handleConnection(srv, headers)) mux.HandleFunc("/", handleConnection(cfg, headers))
srv := &http.Server{
Addr: ":" + cfg.Port,
Handler: mux,
ErrorLog: log.New(io.Discard, "", log.LstdFlags),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 0,
}
// Start the HTTP server. // Start the HTTP server.
fmt.Printf("Starting HTTP server on port: %s\n", srv.Port) fmt.Printf("Starting HTTP server on port: %s\n", cfg.Port)
if err := http.ListenAndServe(":"+srv.Port, mux); err != nil { if err := srv.ListenAndServe(); err != nil {
fmt.Fprintln(os.Stderr, "The HTTP server has terminated:", err) fmt.Fprintln(os.Stderr, "The HTTP server has terminated:", err)
} }
} }
// StartHTTPS initializes and starts an HTTPS honeypot server. This is a fully // StartHTTPS initializes and starts an HTTPS honeypot server. This is a fully
// functional HTTPS server designed to log all incoming requests for analysis. // functional HTTPS server designed to log all incoming requests for analysis.
func StartHTTPS(srv *config.Server) { func StartHTTPS(cfg *config.Server) {
// Get any custom headers, if provided. // Get any custom headers, if provided.
headers := parseCustomHeaders(srv.Banner) headers := parseCustomHeaders(cfg.Banner)
// Setup handler and initialize HTTPS config. // Setup handler and initialize HTTPS config.
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("/", handleConnection(srv, headers)) mux.HandleFunc("/", handleConnection(cfg, headers))
server := &http.Server{ srv := &http.Server{
Addr: ":" + srv.Port, Addr: ":" + cfg.Port,
Handler: mux, Handler: mux,
ErrorLog: log.New(io.Discard, "", log.LstdFlags), ErrorLog: log.New(io.Discard, "", log.LstdFlags),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 0,
} }
// If the cert and key aren't found, generate a self-signed certificate. // If the cert and key aren't found, generate a self-signed certificate.
if _, err := os.Stat(srv.CertPath); os.IsNotExist(err) { if _, err := os.Stat(cfg.CertPath); os.IsNotExist(err) {
if _, err := os.Stat(srv.KeyPath); os.IsNotExist(err) { if _, err := os.Stat(cfg.KeyPath); os.IsNotExist(err) {
// Generate a self-signed certificate. // Generate a self-signed certificate.
cert, err := generateSelfSignedCert(srv.CertPath, srv.KeyPath) cert, err := generateSelfSignedCert(cfg.CertPath, cfg.KeyPath)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "Failed to generate HTTPS certificate:", err) fmt.Fprintln(os.Stderr, "Failed to generate HTTPS certificate:", err)
return return
} }
// Add cert to server config. // Add cert to server config.
server.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}} srv.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
} }
} }
// Start the HTTPS server. // Start the HTTPS server.
fmt.Printf("Starting HTTPS server on port: %s\n", srv.Port) fmt.Printf("Starting HTTPS server on port: %s\n", cfg.Port)
if err := server.ListenAndServeTLS(srv.CertPath, srv.KeyPath); err != nil { if err := srv.ListenAndServeTLS(cfg.CertPath, cfg.KeyPath); err != nil {
fmt.Fprintln(os.Stderr, "The HTTPS server has terminated:", err) fmt.Fprintln(os.Stderr, "The HTTPS server has terminated:", err)
} }
} }
@@ -83,14 +94,14 @@ func StartHTTPS(srv *config.Server) {
// HTML file specified in the configuration or a default page prompting for // HTML file specified in the configuration or a default page prompting for
// basic HTTP authentication. Requests for any other URLs will return a 404 // basic HTTP authentication. Requests for any other URLs will return a 404
// error to the client. // error to the client.
func handleConnection(srv *config.Server, customHeaders map[string]string) http.HandlerFunc { func handleConnection(cfg *config.Server, customHeaders map[string]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// Log details of the incoming HTTP request. // Log details of the incoming HTTP request.
dst_ip, dst_port := getLocalAddr(r) dst_ip, dst_port := getLocalAddr(r)
src_ip, src_port, _ := net.SplitHostPort(r.RemoteAddr) src_ip, src_port, _ := net.SplitHostPort(r.RemoteAddr)
username, password, isAuth := r.BasicAuth() username, password, isAuth := r.BasicAuth()
if isAuth { if isAuth {
srv.Logger.LogAttrs(context.Background(), slog.LevelInfo, "", cfg.Logger.LogAttrs(context.Background(), slog.LevelInfo, "",
slog.String("event_type", "http"), slog.String("event_type", "http"),
slog.String("source_ip", src_ip), slog.String("source_ip", src_ip),
slog.String("source_port", src_port), slog.String("source_port", src_port),
@@ -112,7 +123,7 @@ func handleConnection(srv *config.Server, customHeaders map[string]string) http.
), ),
) )
} else { } else {
srv.Logger.LogAttrs(context.Background(), slog.LevelInfo, "", cfg.Logger.LogAttrs(context.Background(), slog.LevelInfo, "",
slog.String("event_type", "http"), slog.String("event_type", "http"),
slog.String("source_ip", src_ip), slog.String("source_ip", src_ip),
slog.String("source_port", src_port), slog.String("source_port", src_port),
@@ -135,8 +146,8 @@ func handleConnection(srv *config.Server, customHeaders map[string]string) http.
fmt.Printf("[HTTP] %s %s %s %s\n", src_ip, r.Method, r.URL.Path, r.URL.RawQuery) fmt.Printf("[HTTP] %s %s %s %s\n", src_ip, r.Method, r.URL.Path, r.URL.RawQuery)
// Update the threat feed with the source IP address from the request. // Update the threat feed with the source IP address from the request.
if srv.SendToThreatFeed { if cfg.SendToThreatFeed {
threatfeed.UpdateIoC(src_ip, srv.ThreatScore) threatfeed.UpdateIoC(src_ip, cfg.ThreatScore)
} }
// If custom headers are provided, add each header and its value to the // If custom headers are provided, add each header and its value to the
@@ -150,9 +161,9 @@ func handleConnection(srv *config.Server, customHeaders map[string]string) http.
// For any other requests, return a '404 Not Found' response. // For any other requests, return a '404 Not Found' response.
if r.URL.Path == "/" || r.URL.Path == "/index.html" { if r.URL.Path == "/" || r.URL.Path == "/index.html" {
// The request is for the root or /index.html. // The request is for the root or /index.html.
if len(srv.HtmlPath) > 0 { if len(cfg.HtmlPath) > 0 {
// Serve the custom HTML file specified in the configuration. // Serve the custom HTML file specified in the configuration.
http.ServeFile(w, r, srv.HtmlPath) http.ServeFile(w, r, cfg.HtmlPath)
} else { } else {
// Serve the default page that prompts the client for basic // Serve the default page that prompts the client for basic
// authentication. // authentication.

View File

@@ -68,14 +68,21 @@ func StartThreatFeed(cfg *config.ThreatFeed) {
} }
}() }()
// Setup handlers. // Setup handlers and server config.
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("/", enforcePrivateIP(handleConnection)) mux.HandleFunc("/", enforcePrivateIP(handleConnection))
mux.HandleFunc("/empty/", enforcePrivateIP(serveEmpty)) mux.HandleFunc("/empty/", enforcePrivateIP(serveEmpty))
srv := &http.Server{
Addr: ":" + cfg.Port,
Handler: mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 0,
}
// Start the threat feed HTTP server. // Start the threat feed HTTP server.
fmt.Printf("Starting Threat Feed server on port: %s\n", cfg.Port) fmt.Printf("Starting Threat Feed server on port: %s\n", cfg.Port)
if err := http.ListenAndServe(":"+cfg.Port, mux); err != nil { if err := srv.ListenAndServe(); err != nil {
fmt.Fprintln(os.Stderr, "The Threat Feed server has terminated:", err) fmt.Fprintln(os.Stderr, "The Threat Feed server has terminated:", err)
} }
} }