mirror of
https://github.com/r-smith/deceptifeed.git
synced 2025-10-23 00:12:22 +00:00
Compare commits
9 Commits
90fbc24479
...
dc06d64b5b
Author | SHA1 | Date | |
---|---|---|---|
|
dc06d64b5b | ||
|
41345f04bd | ||
|
c0e6010143 | ||
|
2736c20158 | ||
|
8ebec3a8c4 | ||
|
650489bd5c | ||
|
da42f21f75 | ||
|
0a4d4536ba | ||
|
148d99876f |
@@ -2,6 +2,7 @@
|
||||
FROM golang:latest AS build-stage
|
||||
WORKDIR /build
|
||||
COPY . .
|
||||
RUN git update-index -q --refresh
|
||||
RUN make
|
||||
|
||||
FROM alpine:latest
|
||||
|
33
Makefile
33
Makefile
@@ -2,10 +2,7 @@
|
||||
|
||||
SOURCE := ./cmd/deceptifeed/
|
||||
BIN_DIRECTORY := ./bin/
|
||||
BIN_DEFAULT := deceptifeed
|
||||
BIN_LINUX := $(BIN_DEFAULT)_linux_amd64
|
||||
BIN_FREEBSD := $(BIN_DEFAULT)_freebsd_amd64
|
||||
BIN_WINDOWS := $(BIN_DEFAULT)_windows_amd64.exe
|
||||
BIN_DEFAULT := $(BIN_DIRECTORY)deceptifeed
|
||||
INSTALL_SCRIPT := ./scripts/install.sh
|
||||
UNINSTALL_SCRIPT := ./scripts/install.sh --uninstall
|
||||
VERSION := $(shell git describe --tags --dirty --broken)
|
||||
@@ -17,39 +14,47 @@ CGO_ENABLED := 0
|
||||
build:
|
||||
@echo "Building for current operating system..."
|
||||
@mkdir -p $(BIN_DIRECTORY)
|
||||
CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DIRECTORY)$(BIN_DEFAULT) $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DIRECTORY)$(BIN_DEFAULT)"
|
||||
CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DEFAULT) $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DEFAULT)"
|
||||
@echo
|
||||
|
||||
.PHONY: all
|
||||
all: build build-linux build-freebsd build-windows
|
||||
all: build build-linux build-linux-arm build-freebsd build-windows
|
||||
|
||||
.PHONY: build-linux
|
||||
build-linux:
|
||||
@echo "Building for Linux..."
|
||||
@mkdir -p $(BIN_DIRECTORY)
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DIRECTORY)$(BIN_LINUX) $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DIRECTORY)$(BIN_LINUX)"
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DEFAULT)_linux_x64 $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DEFAULT)_linux_x64"
|
||||
@echo
|
||||
|
||||
.PHONY: build-linux-arm
|
||||
build-linux-arm:
|
||||
@echo "Building for Linux (ARM)..."
|
||||
@mkdir -p $(BIN_DIRECTORY)
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DEFAULT)_linux_ARM64 $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DEFAULT)_linux_ARM64"
|
||||
@echo
|
||||
|
||||
.PHONY: build-freebsd
|
||||
build-freebsd:
|
||||
@echo "Building for FreeBSD..."
|
||||
@mkdir -p $(BIN_DIRECTORY)
|
||||
GOOS=freebsd GOARCH=amd64 CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DIRECTORY)$(BIN_FREEBSD) $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DIRECTORY)$(BIN_FREEBSD)"
|
||||
GOOS=freebsd GOARCH=amd64 CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DEFAULT)_freebsd_x64 $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DEFAULT)_freebsd_x64"
|
||||
@echo
|
||||
|
||||
.PHONY: build-windows
|
||||
build-windows:
|
||||
@echo "Building for Windows..."
|
||||
@mkdir -p $(BIN_DIRECTORY)
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DIRECTORY)$(BIN_WINDOWS) $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DIRECTORY)$(BIN_WINDOWS)"
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(BUILD_OPTIONS) -o $(BIN_DEFAULT)_windows_x64.exe $(SOURCE)
|
||||
@echo "Build complete: $(BIN_DEFAULT)_windows_x64.exe"
|
||||
@echo
|
||||
|
||||
.PHONY: install
|
||||
install: $(BIN_DIRECTORY)$(BIN_DEFAULT)
|
||||
install: $(BIN_DEFAULT)
|
||||
@bash $(INSTALL_SCRIPT)
|
||||
|
||||
.PHONY: uninstall
|
||||
|
@@ -14,6 +14,9 @@
|
||||
<threatExpiryHours>336</threatExpiryHours>
|
||||
<includePrivateIPs>false</includePrivateIPs>
|
||||
<excludeListPath></excludeListPath>
|
||||
<enableTLS>false</enableTLS>
|
||||
<certPath>/opt/deceptifeed/certs/threatfeed-cert.pem</certPath>
|
||||
<keyPath>/opt/deceptifeed/certs/threatfeed-key.pem</keyPath>
|
||||
</threatFeed>
|
||||
|
||||
<!-- Honeypot Server Configuration -->
|
||||
|
@@ -14,6 +14,9 @@
|
||||
<threatExpiryHours>336</threatExpiryHours>
|
||||
<includePrivateIPs>false</includePrivateIPs>
|
||||
<excludeListPath></excludeListPath>
|
||||
<enableTLS>false</enableTLS>
|
||||
<certPath>key-threatfeed-public.pem</certPath>
|
||||
<keyPath>key-threatfeed-private.pem</keyPath>
|
||||
</threatFeed>
|
||||
|
||||
<!-- Honeypot Server Configuration -->
|
||||
|
6
go.mod
6
go.mod
@@ -3,8 +3,8 @@ module github.com/r-smith/deceptifeed
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/net v0.38.0
|
||||
golang.org/x/crypto v0.37.0
|
||||
golang.org/x/net v0.39.0
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.31.0 // indirect
|
||||
require golang.org/x/sys v0.32.0 // indirect
|
||||
|
16
go.sum
16
go.sum
@@ -1,8 +1,8 @@
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
|
95
internal/certutil/certutil.go
Normal file
95
internal/certutil/certutil.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package certutil
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GenerateSelfSigned creates a self-signed certificate and returns it as a
|
||||
// tls.Certificate. If certPath and keyPath are provided, the generated
|
||||
// certificate and private key are saved to disk.
|
||||
func GenerateSelfSigned(certPath string, keyPath string) (tls.Certificate, error) {
|
||||
// Generate 2048-bit RSA private key.
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("failed to generate private key: %w", err)
|
||||
}
|
||||
|
||||
// Set the certificate validity period to 10 years.
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.AddDate(10, 0, 0)
|
||||
|
||||
// Generate a random certificate serial number.
|
||||
serialNumber := make([]byte, 16)
|
||||
_, err = rand.Read(serialNumber)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("failed to generate certificate serial number: %w", err)
|
||||
}
|
||||
|
||||
// Configure the certificate template.
|
||||
template := x509.Certificate{
|
||||
SerialNumber: new(big.Int).SetBytes(serialNumber),
|
||||
Subject: pkix.Name{CommonName: "localhost"},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
// Create the certificate.
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("failed to create certificate: %w", err)
|
||||
}
|
||||
|
||||
certPEM := &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}
|
||||
keyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
|
||||
|
||||
// Save the certificate and key to disk.
|
||||
if len(certPath) > 0 && len(keyPath) > 0 {
|
||||
// Silently ignore any potential errors and continue.
|
||||
_ = writeCertAndKey(certPEM, keyPEM, certPath, keyPath)
|
||||
}
|
||||
|
||||
return tls.X509KeyPair(pem.EncodeToMemory(certPEM), pem.EncodeToMemory(keyPEM))
|
||||
}
|
||||
|
||||
// writeCertAndKey saves the public certificate and private key in PEM format
|
||||
// to the specified paths.
|
||||
func writeCertAndKey(cert *pem.Block, key *pem.Block, certPath string, keyPath string) error {
|
||||
// Save the certificate file to disk.
|
||||
certFile, err := os.Create(certPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer certFile.Close()
|
||||
|
||||
if err := pem.Encode(certFile, cert); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the private key file to disk.
|
||||
keyFile, err := os.Create(keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer keyFile.Close()
|
||||
|
||||
// Limit key access to the owner only.
|
||||
_ = keyFile.Chmod(0600)
|
||||
|
||||
if err := pem.Encode(keyFile, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -145,6 +145,9 @@ type ThreatFeed struct {
|
||||
ExpiryHours int `xml:"threatExpiryHours"`
|
||||
IsPrivateIncluded bool `xml:"includePrivateIPs"`
|
||||
ExcludeListPath string `xml:"excludeListPath"`
|
||||
EnableTLS bool `xml:"enableTLS"`
|
||||
CertPath string `xml:"certPath"`
|
||||
KeyPath string `xml:"keyPath"`
|
||||
}
|
||||
|
||||
// Load reads an optional XML configuration file and unmarshals its contents
|
||||
|
@@ -2,17 +2,13 @@ package httpserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"log/slog"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -20,6 +16,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/r-smith/deceptifeed/internal/certutil"
|
||||
"github.com/r-smith/deceptifeed/internal/config"
|
||||
"github.com/r-smith/deceptifeed/internal/threatfeed"
|
||||
)
|
||||
@@ -112,7 +109,7 @@ func listenHTTP(cfg *config.Server, response *responseConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// listenHTTP initializes and starts an HTTPS (encrypted) honeypot server.
|
||||
// listenHTTPS initializes and starts an HTTPS (encrypted) honeypot server.
|
||||
func listenHTTPS(cfg *config.Server, response *responseConfig) {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", handleConnection(cfg, parseCustomHeaders(cfg.Headers), response))
|
||||
@@ -126,10 +123,9 @@ func listenHTTPS(cfg *config.Server, response *responseConfig) {
|
||||
}
|
||||
|
||||
// If the cert and key aren't found, generate a self-signed certificate.
|
||||
if _, err := os.Stat(cfg.CertPath); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(cfg.KeyPath); os.IsNotExist(err) {
|
||||
// Generate a self-signed certificate.
|
||||
cert, err := generateSelfSignedCert(cfg.CertPath, cfg.KeyPath)
|
||||
if _, err := os.Stat(cfg.CertPath); errors.Is(err, fs.ErrNotExist) {
|
||||
if _, err := os.Stat(cfg.KeyPath); errors.Is(err, fs.ErrNotExist) {
|
||||
cert, err := certutil.GenerateSelfSigned(cfg.CertPath, cfg.KeyPath)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to generate HTTPS certificate:", err)
|
||||
return
|
||||
@@ -223,6 +219,9 @@ func handleConnection(cfg *config.Server, customHeaders map[string]string, respo
|
||||
case modeDefault:
|
||||
// Built-in default response.
|
||||
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
|
||||
if _, _, ok := r.BasicAuth(); ok {
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
w.Header()["WWW-Authenticate"] = []string{"Basic"}
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
} else {
|
||||
@@ -357,91 +356,3 @@ func getLocalAddr(r *http.Request) (ip string, port string) {
|
||||
}
|
||||
return ip, port
|
||||
}
|
||||
|
||||
// generateSelfSignedCert creates a self-signed TLS certificate and private key
|
||||
// and returns the resulting tls.Certificate. If file paths are provided, the
|
||||
// certificate and key are also saved to disk.
|
||||
func generateSelfSignedCert(certPath string, keyPath string) (tls.Certificate, error) {
|
||||
// Generate 2048-bit RSA private key.
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("failed to generate private key: %w", err)
|
||||
}
|
||||
|
||||
// Set the certificate validity period to 10 years.
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.AddDate(10, 0, 0)
|
||||
|
||||
// Generate a random serial number for the certificate.
|
||||
serialNumber := make([]byte, 16)
|
||||
_, err = rand.Read(serialNumber)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("failed to generate certificate serial number: %w", err)
|
||||
}
|
||||
|
||||
// Set up the template for creating the certificate.
|
||||
template := x509.Certificate{
|
||||
SerialNumber: new(big.Int).SetBytes(serialNumber),
|
||||
Subject: pkix.Name{CommonName: "localhost"},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
// Use the template to create a self-signed X.509 certificate.
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("failed to create certificate: %w", err)
|
||||
}
|
||||
|
||||
certPEM := &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}
|
||||
keyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
|
||||
|
||||
// Save the certificate and key to disk.
|
||||
if len(certPath) > 0 && len(keyPath) > 0 {
|
||||
_ = writeCertAndKey(certPEM, keyPEM, certPath, keyPath)
|
||||
// If saving fails, ignore the errors and use the in-memory
|
||||
// certificate.
|
||||
}
|
||||
|
||||
// Parse the public certificate and private key bytes into a tls.Certificate.
|
||||
cert, err := tls.X509KeyPair(pem.EncodeToMemory(certPEM), pem.EncodeToMemory(keyPEM))
|
||||
if err != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("failed to load certificate and private key: %w", err)
|
||||
}
|
||||
|
||||
// Return the tls.Certificate.
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// writeCertAndKey saves the public certificate and private key in PEM format
|
||||
// to the specified file paths.
|
||||
func writeCertAndKey(cert *pem.Block, key *pem.Block, certPath string, keyPath string) error {
|
||||
// Save the certificate file to disk.
|
||||
certFile, err := os.Create(certPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer certFile.Close()
|
||||
|
||||
if err := pem.Encode(certFile, cert); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the private key file to disk.
|
||||
keyFile, err := os.Create(keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer keyFile.Close()
|
||||
|
||||
// Limit key access to the owner only.
|
||||
_ = keyFile.Chmod(0600)
|
||||
|
||||
if err := pem.Encode(keyFile, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -139,7 +139,7 @@ func loadOrGeneratePrivateKey(path string) (ssh.Signer, error) {
|
||||
// Load the specified file and return the parsed private key.
|
||||
privateKey, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read private key from '%s': %w", path, err)
|
||||
return nil, fmt.Errorf("failed to read private key '%s': %w", path, err)
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(privateKey)
|
||||
if err != nil {
|
||||
@@ -150,20 +150,19 @@ func loadOrGeneratePrivateKey(path string) (ssh.Signer, error) {
|
||||
// Generate and return a new private key.
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate RSA private key: %w", err)
|
||||
return nil, fmt.Errorf("failed to generate private key: %w", err)
|
||||
}
|
||||
|
||||
// Save the private key to disk.
|
||||
if len(path) > 0 {
|
||||
// Silently ignore any potential errors and continue.
|
||||
_ = writePrivateKey(path, privateKey)
|
||||
// If saving fails, ignore the errors and use the in-memory private
|
||||
// key.
|
||||
}
|
||||
|
||||
// Convert the key to ssh.Signer.
|
||||
signer, err := ssh.NewSignerFromKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert RSA key to SSH signer: %w", err)
|
||||
return nil, fmt.Errorf("failed to convert key to SSH signer: %w", err)
|
||||
}
|
||||
return signer, nil
|
||||
} else {
|
||||
@@ -171,8 +170,7 @@ func loadOrGeneratePrivateKey(path string) (ssh.Signer, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// writePrivateKey saves a private key in PEM format to the specified file
|
||||
// path.
|
||||
// writePrivateKey saves a private key in PEM format to the specified path.
|
||||
func writePrivateKey(path string, privateKey *rsa.PrivateKey) error {
|
||||
privBytes := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||
privPem := &pem.Block{
|
||||
|
@@ -1,11 +1,15 @@
|
||||
package threatfeed
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/r-smith/deceptifeed/internal/certutil"
|
||||
"github.com/r-smith/deceptifeed/internal/config"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
@@ -91,9 +95,32 @@ func Start(c *config.Config) {
|
||||
IdleTimeout: 0,
|
||||
}
|
||||
|
||||
// Start the threat feed HTTP server.
|
||||
fmt.Printf("Starting Threat Feed server on port: %s\n", c.ThreatFeed.Port)
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "The Threat Feed server has stopped:", err)
|
||||
// Start the threat feed (HTTP) server if TLS is not enabled.
|
||||
if !c.ThreatFeed.EnableTLS {
|
||||
fmt.Printf("Starting threat feed (HTTP) on port: %s\n", c.ThreatFeed.Port)
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "The threat feed server has stopped:", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a self-signed cert if the provided key and cert aren't found.
|
||||
if _, err := os.Stat(c.ThreatFeed.CertPath); errors.Is(err, fs.ErrNotExist) {
|
||||
if _, err := os.Stat(c.ThreatFeed.KeyPath); errors.Is(err, fs.ErrNotExist) {
|
||||
cert, err := certutil.GenerateSelfSigned(c.ThreatFeed.CertPath, c.ThreatFeed.KeyPath)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to generate threat feed TLS certificate:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Add cert to server config.
|
||||
srv.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
|
||||
}
|
||||
}
|
||||
|
||||
// Start the threat feed (HTTPS) server.
|
||||
fmt.Printf("Starting threat feed (HTTPS) on port: %s\n", c.ThreatFeed.Port)
|
||||
if err := srv.ListenAndServeTLS(c.ThreatFeed.CertPath, c.ThreatFeed.KeyPath); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "The threat feed server has stopped:", err)
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,10 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><th>State</th><td>{{if .C.ThreatFeed.Enabled}}<span class="green">Enabled{{else}}<span class="red">Disabled{{end}}</span></td></tr>
|
||||
<tr><th>Database</th><td class="blue">{{if .C.ThreatFeed.DatabasePath}}{{.C.ThreatFeed.DatabasePath}}{{else}}<span class="gray">(not set)</span>{{end}}</td></tr>
|
||||
<tr><th>TLS</th><td>{{if .C.ThreatFeed.EnableTLS}}<span class="green">Enabled{{else}}<span class="red">Disabled{{end}}</span></td></tr>
|
||||
{{if .C.ThreatFeed.EnableTLS}}<tr><th>Certificate</th><td class="blue">{{if .C.ThreatFeed.CertPath}}{{.C.ThreatFeed.CertPath}}{{else}}<span class="gray">(not set){{end}}</span></td></tr>{{end}}
|
||||
{{if .C.ThreatFeed.EnableTLS}}<tr><th>Private Key</th><td class="blue">{{if .C.ThreatFeed.KeyPath}}{{.C.ThreatFeed.KeyPath}}{{else}}<span class="gray">(not set){{end}}</span></td></tr>{{end}}
|
||||
<tr><th>Threat Database</th><td class="blue">{{if .C.ThreatFeed.DatabasePath}}{{.C.ThreatFeed.DatabasePath}}{{else}}<span class="gray">(not set)</span>{{end}}</td></tr>
|
||||
<tr><th>Include Private IPs</th><td>{{if .C.ThreatFeed.IsPrivateIncluded}}<span class="red">Yes{{else}}<span class="green">No{{end}}</span></td></tr>
|
||||
<tr><th>Expiry Hours</th><td class="orange">{{if eq .C.ThreatFeed.ExpiryHours 0}}<span class="gray">(never expire)</span>{{else}}{{.C.ThreatFeed.ExpiryHours}}{{end}}</td></tr>
|
||||
<tr><th>Exclude List</th><td class="blue">{{if .C.ThreatFeed.ExcludeListPath}}{{.C.ThreatFeed.ExcludeListPath}}{{else}}<span class="gray">(not set)</span>{{end}}</td></tr>
|
||||
|
Reference in New Issue
Block a user