diff --git a/Taskfile.yaml b/Taskfile.yaml new file mode 100644 index 0000000..a53b617 --- /dev/null +++ b/Taskfile.yaml @@ -0,0 +1,36 @@ +version: '3' + +tasks: + certs_windows: + cmds: + - mkdir -p "./cmd/proxy/.cert" + - openssl ecparam -out ./cmd/proxy/.cert/ca.key -name prime256v1 -genkey + - openssl req -new -sha256 -key ./cmd/proxy/.cert/ca.key -out ./cmd/proxy/.cert/ca.csr + - openssl x509 -req -sha256 -days 3650 -in ./cmd/proxy/.cert/ca.csr -signkey ./cmd/proxy/.cert/ca.key -out ./cmd/proxy/.cert/ca.crt + - openssl ecparam -out ./cmd/proxy/.cert/server.key -name prime256v1 -genkey + - openssl req -new -sha256 -key ./cmd/proxy/.cert/server.key -out ./cmd/proxy/.cert/server.csr + - openssl x509 -req -in ./cmd/proxy/.cert/server.csr -CA ./cmd/proxy/.cert/ca.crt -CAkey ./cmd/proxy/.cert/ca.key -CAcreateserial -out ./cmd/proxy/.cert/server.crt -days 3650 -sha256 + - openssl x509 -in ./cmd/proxy/.cert/server.crt -text -noout + + certs: + cmds: + - mkdir -p "./cmd/proxy/.cert" + - openssl ecparam -out ./cmd/proxy/.cert/ca.key -name prime256v1 -genkey + - openssl req -new -sha256 -key ./cmd/proxy/.cert/ca.key -out ./cmd/proxy/.cert/ca.csr + - openssl x509 -req -sha256 -days 3650 -in ./cmd/proxy/.cert/ca.csr -signkey ./cmd/proxy/.cert/ca.key -out ./cmd/proxy/.cert/ca.crt + - openssl ecparam -out ./cmd/proxy/.cert/server.key -name prime256v1 -genkey + - openssl req -new -sha256 -key ./cmd/proxy/.cert/server.key -out ./cmd/proxy/.cert/server.csr + - openssl x509 -req -in ./cmd/proxy/.cert/server.csr -CA ./cmd/proxy/.cert/ca.crt -CAkey ./cmd/proxy/.cert/ca.key -CAcreateserial -out ./cmd/proxy/.cert/server.crt -days 3650 -sha256 + - openssl x509 -in ./cmd/proxy/.cert/server.crt -text -noout + + mocks: + cmds: + - mockery + + docker-build: + cmds: + - docker build -t ${IMAGE_NAME} -f .\build\Dockerfile . + + docker-push: + cmds: + - docker push ${IMAGE_NAME} diff --git a/build/Dockerfile b/build/Dockerfile index 7d855c8..c52c30e 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,15 +1,16 @@ FROM golang:1.22-alpine as builder -ARG CGO_ENABLED=0 WORKDIR /app COPY go.mod go.sum ./ RUN go mod download + COPY . . -RUN go build cmd/proxy -o /out/app +RUN go build -o /out/app ./cmd/proxy -# multi stage build, to reduce size of the image FROM alpine:latest + COPY --from=builder /out/app /app + ENTRYPOINT ["/app"] \ No newline at end of file diff --git a/cmd/collector/main.go b/cmd/collector/main.go index 7876c05..79026bf 100644 --- a/cmd/collector/main.go +++ b/cmd/collector/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "flag" "log" "time" "waffle/internal/packet" @@ -9,14 +10,25 @@ import ( "waffle/internal/worker" ) -const networkInterfaceDescription = "Intel(R) I211 Gigabit Network Connection" +const ( + defaultNetworkInterfaceDescription = "Intel(R) I211 Gigabit Network Connection" +) func main() { + var ( + networkInterface string + ) + flag.StringVar(&networkInterface, "i", defaultNetworkInterfaceDescription, "Identification of the interface") + + // question: Why do we need context here? It is not used in collector.Run, except of ctx.Done, but since it is not + // context.WithTimeout (as example) it can not be closed in any way. + // Same in c.serializer.SerializePackets(ctx, packetsChan), it can not be closed there as well. + // Why not just to remove it? ctx := context.Background() log.Println("starting collector") - inMemoryPacketSerializer := packet.NewMemoryPacketSerializer(time.Minute * 5) + packetSerializer := packet.NewMemoryPacketSerializer(time.Minute * 5) // NEXT TODO: add BPF filter builder // https://www.ibm.com/docs/en/qsip/7.4?topic=queries-berkeley-packet-filters @@ -26,10 +38,10 @@ func main() { collector := worker.NewCollector( cfg, - packet.NewWindowsNetworkInterfaceProvider(networkInterfaceDescription), - inMemoryPacketSerializer) + packet.NewWindowsNetworkInterfaceProvider(networkInterface), + packetSerializer) if err := collector.Run(ctx); err != nil { - panic(err.Error()) + log.Fatalln("Error during running collector: ", err.Error()) } } diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go index a5c125e..481463a 100644 --- a/cmd/proxy/main.go +++ b/cmd/proxy/main.go @@ -4,9 +4,8 @@ import ( "context" "embed" _ "embed" - "fmt" - "os" - + "flag" + "log" "waffle/cmd/proxy/server" ) @@ -17,9 +16,15 @@ var yamlConfigBytes []byte var certificates embed.FS func main() { + var ( + visualizeServerPort string + proxyServerPort string + ) + flag.StringVar(&visualizeServerPort, "p", "8081", "Port for server to listen on") + flag.StringVar(&proxyServerPort, "p", "8081", "Port for server to listen on") + ctx := context.Background() - if err := server.Run(ctx, yamlConfigBytes, certificates); err != nil { - _, _ = fmt.Fprintf(os.Stderr, "%s\n", err) - os.Exit(1) + if err := server.Run(ctx, proxyServerPort, visualizeServerPort, yamlConfigBytes, certificates); err != nil { + log.Fatalln(err) } } diff --git a/cmd/proxy/server/server.go b/cmd/proxy/server/server.go index 81e023f..c56101e 100644 --- a/cmd/proxy/server/server.go +++ b/cmd/proxy/server/server.go @@ -3,6 +3,7 @@ package server import ( "context" "embed" + "fmt" "log" "os" "os/signal" @@ -19,7 +20,29 @@ import ( "waffle/internal/waf/guard" ) -func Run(ctx context.Context, yamlConfigBytes []byte, certificates embed.FS) error { +// Run initializes and starts the Waffle Proxy server with the provided context, configuration, and embedded certificates. +// +// It first sets up signal handling to allow graceful shutdown on receiving an interrupt signal. +// +// The function loads environment-specific configurations, then parses the provided YAML configuration +// to initialize a DNS provider for managing domain names. +// +// Next, it sets up the certificate provider using locally embedded certificates, +// loading custom CA certificates, certificate PEM blocks, and key PEM blocks. +// +// A defense coordinator is initialized to handle security measures like XSS protection, +// along with an in-memory rate limiter to control the number of requests allowed per a given time window (5 minutes). +// +// Additionally, a server for visualizing traffic is set up on port :8081. +// +// The WAF (Web Application Firewall) handler is constructed using a redirect handler, the defender (for security), +// the rate limiter, and a visualizer from the visualization server. +// +// Finally, the main proxy server is started on port :8080, with the guard handler and certificate provider. +// If the proxy server fails to start, the function logs a fatal error. +// +// The function returns nil upon normal completion. +func Run(ctx context.Context, proxyServerPort, visualizeServerPort string, yamlConfigBytes []byte, certificates embed.FS) error { _, cancel := signal.NotifyContext(ctx, os.Interrupt) defer cancel() @@ -35,28 +58,47 @@ func Run(ctx context.Context, yamlConfigBytes []byte, certificates embed.FS) err yamlDnsProvider := domain.NewYamlNameSystemProvider(yamlCfg) + caCerts, err := loadLocalCustomCACerts(certificates) + if err != nil { + return err + } + + certPemBlock, err := loadLocalCertPEMBlock(certificates) + if err != nil { + return err + } + + keyPemBlock, err := loadLocalKeyPEMBlock(certificates) + if err != nil { + return err + } + certificateProvider := certificate.NewLocalCertificatesProvider( - loadLocalCustomCACerts(certificates), - loadLocalCertPEMBlock(certificates), - loadLocalKeyPEMBlock(certificates), + caCerts, + certPemBlock, + keyPemBlock, ) defender := guard.NewDefenseCoordinator([]guard.Defender{&guard.XSS{}}) limiter := ratelimit.NewInMemoryLimiter(time.Minute * 5) - visualizeServer := visualize.NewServer(":8081") + visualizeServerPort = fmt.Sprintf(":%s", visualizeServerPort) + + s := visualize.NewServer(visualizeServerPort) guardHandler := waf.NewHandler( redirect.NewHandler(yamlDnsProvider), defender, limiter, - visualizeServer.GetVisualizer(), + s.GetVisualizer(), ) - proxyServer := proxy.NewServer(":8080", certificateProvider, guardHandler) + proxyServerPort = fmt.Sprintf(":%s", proxyServerPort) - log.Println("Starting Waffle Proxy on port :8080 🚀") + proxyServer := proxy.NewServer(proxyServerPort, certificateProvider, guardHandler) + + log.Printf("Starting Waffle Proxy on port %s 🚀\n", proxyServerPort) if err := proxyServer.Start(); err != nil { log.Fatal(err.Error()) @@ -65,20 +107,33 @@ func Run(ctx context.Context, yamlConfigBytes []byte, certificates embed.FS) err return nil } -func loadLocalCustomCACerts(certificates embed.FS) [][]byte { - certBytes, _ := certificates.ReadFile(".cert/ca.crt") - - return [][]byte{certBytes} +// loadLocalCustomCACerts reads the local custom CA certificates from the embedded file system. +// It reads the CA certificate file (ca.crt) located in the ".cert" directory and returns it as a slice of byte slices. +// This CA certificate is used for establishing trust during TLS/SSL handshakes. +func loadLocalCustomCACerts(certificates embed.FS) ([][]byte, error) { + certBytes, err := certificates.ReadFile(".cert/ca.crt") + if err != nil { + return nil, err + } + return [][]byte{certBytes}, nil } -func loadLocalCertPEMBlock(certificates embed.FS) []byte { - certBytes, _ := certificates.ReadFile(".cert/server.crt") - - return certBytes +// loadLocalCertPEMBlock reads the local server certificate (server.crt) from the embedded file system. +// It returns the certificate as a byte slice, which is later used to serve the server's public certificate in TLS/SSL connections. +func loadLocalCertPEMBlock(certificates embed.FS) ([]byte, error) { + certBytes, err := certificates.ReadFile(".cert/server.crt") + if err != nil { + return nil, err + } + return certBytes, nil } -func loadLocalKeyPEMBlock(certificates embed.FS) []byte { - certBytes, _ := certificates.ReadFile(".cert/server.key") - - return certBytes +// loadLocalKeyPEMBlock reads the private key (server.key) from the embedded file system. +// It returns the private key as a byte slice, which is paired with the server certificate during TLS/SSL handshakes. +func loadLocalKeyPEMBlock(certificates embed.FS) ([]byte, error) { + certBytes, err := certificates.ReadFile(".cert/server.key") + if err != nil { + return nil, err + } + return certBytes, nil } diff --git a/cmd/tcpproxy/main.go b/cmd/tcpproxy/main.go index 31e6095..4807f1e 100644 --- a/cmd/tcpproxy/main.go +++ b/cmd/tcpproxy/main.go @@ -48,7 +48,7 @@ func tcpDummy() error { for { conn, err := listener.Accept() if err != nil { - return fmt.Errorf("liistener accept: %w", err) + return fmt.Errorf("listener accept: %w", err) } log.Println(conn) diff --git a/internal/certificate/provider.go b/internal/certificate/provider.go index eacd53d..c0eaefc 100644 --- a/internal/certificate/provider.go +++ b/internal/certificate/provider.go @@ -13,12 +13,18 @@ type Provider interface { GetCACertificatesPool() (*x509.CertPool, error) } +// LocalCertificatesProvider is a structure that holds custom CA certificates, +// the server certificate PEM block, and the private key PEM block. +// It provides methods for retrieving TLS certificates and a CA certificate pool for establishing secure connections. type LocalCertificatesProvider struct { customCaCerts [][]byte certPEMBlock []byte keyPEMBlock []byte } +// NewLocalCertificatesProvider initializes a new instance of LocalCertificatesProvider. +// It takes custom CA certificates, a certificate PEM block, and a key PEM block as input, +// and returns a LocalCertificatesProvider that can provide certificates for secure connections. func NewLocalCertificatesProvider(caCerts [][]byte, certPEMBlock, keyPEMBlock []byte) *LocalCertificatesProvider { return &LocalCertificatesProvider{ customCaCerts: caCerts, @@ -27,6 +33,9 @@ func NewLocalCertificatesProvider(caCerts [][]byte, certPEMBlock, keyPEMBlock [] } } +// GetTLSCertificate returns a TLS certificate created from the certificate PEM block and key PEM block. +// This is used to provide the server's certificate for TLS/SSL handshakes. +// If an error occurs while loading the key pair, it returns an error. func (l *LocalCertificatesProvider) GetTLSCertificate() (*tls.Certificate, error) { cert, err := tls.X509KeyPair(l.certPEMBlock, l.keyPEMBlock) if err != nil { @@ -36,6 +45,10 @@ func (l *LocalCertificatesProvider) GetTLSCertificate() (*tls.Certificate, error return &cert, nil } +// GetCACertificatesPool returns a pool of CA certificates, including both system CA certificates and +// any custom CA certificates provided to the LocalCertificatesProvider. +// If the system CA certificate pool cannot be loaded, it returns an error. +// Custom CA certificates are appended to the pool to support specific trusted CAs. func (l *LocalCertificatesProvider) GetCACertificatesPool() (*x509.CertPool, error) { caCertPool, err := x509.SystemCertPool() if err != nil { diff --git a/internal/clock/time.go b/internal/clock/time.go deleted file mode 100644 index bd0d9ec..0000000 --- a/internal/clock/time.go +++ /dev/null @@ -1,9 +0,0 @@ -package clock - -import "time" - -var Now = nowFunc - -func nowFunc() time.Time { - return time.Now() -} diff --git a/internal/packet/find.go b/internal/packet/find.go index bb86df8..129b7bd 100644 --- a/internal/packet/find.go +++ b/internal/packet/find.go @@ -11,6 +11,7 @@ import ( ) var ( + // ErrNetworkInterfaceNotFound is an error which indicates that network interface was not found ErrNetworkInterfaceNotFound = errors.New("network interface not found") ) @@ -28,6 +29,9 @@ func NewWindowsNetworkInterfaceProvider(interfaceDescription string) *WindowsNet return &WindowsNetworkInterfaceProvider{interfaceDescription: interfaceDescription} } +// GetNetworkInterface retrieves all available interfaces, verifies if interface's description matches description +// in interfaceDescription field of WindowsNetworkInterfaceProvider struct, and returns an interfaces which +// suits that condition. func (w *WindowsNetworkInterfaceProvider) GetNetworkInterface() (*pcap.Interface, error) { interfaces, err := pcap.FindAllDevs() if err != nil { diff --git a/internal/packet/memserializer.go b/internal/packet/mem_serializer.go similarity index 100% rename from internal/packet/memserializer.go rename to internal/packet/mem_serializer.go diff --git a/internal/proxy/server.go b/internal/proxy/server.go index 80af86a..b77f290 100644 --- a/internal/proxy/server.go +++ b/internal/proxy/server.go @@ -61,12 +61,18 @@ var ( alpnProto = "acme-tls/1" ) +// Server represents an HTTP server that listens on a specific address. +// It uses a certificate provider to manage TLS certificates and an HTTP handler to process incoming requests. type Server struct { addr string certificateProvider certificate.Provider handler http.Handler } +// NewServer initializes a new Server instance with the given address, certificate provider, and HTTP handler. +// The address defines where the server will listen for incoming connections. +// The certificateProvider is used to manage the TLS certificates for secure connections. +// The handler (usually a redirect handler) will process HTTP requests that are received by the server. func NewServer( addr string, certificateProvider certificate.Provider, @@ -79,6 +85,22 @@ func NewServer( } } +// Start initializes and starts the server with TLS configuration using the provided certificate provider. +// It first retrieves the CA certificates pool and server TLS certificate from the certificate provider. +// Then, it configures the server to use TLS 1.3, sets the allowed cipher suites, and prepares the server for +// mutual TLS authentication (client certificates are verified if provided). +// +// A TCP listener is created to listen for incoming TLS connections on the specified address. +// +// The HTTP server is configured with various timeouts (read, write, idle), a maximum header size, and a custom error logger. +// The server handles incoming requests using the provided handler. +// +// A graceful shutdown mechanism is implemented: when an interrupt signal is received (e.g., Ctrl+C), +// the server begins shutting down by closing the active listener and processing any outstanding requests. +// +// The function waits for all idle connections to be closed before returning. +// +// If there is any error while starting or serving the server, the error is returned. func (s *Server) Start() error { caCertPool, err := s.certificateProvider.GetCACertificatesPool() if err != nil { diff --git a/internal/ratelimit/limiter.go b/internal/ratelimit/limiter.go index 13e7330..97c3efc 100644 --- a/internal/ratelimit/limiter.go +++ b/internal/ratelimit/limiter.go @@ -14,15 +14,22 @@ var ( defaultPurgeDuration = time.Minute * 5 ) +// Limiter is an interface that defines rate-limiting functionality for network addresses. +// It includes methods to retrieve the current rate for an IP address and to set a rate limit for an IP address until a specific time. type Limiter interface { GetRate(ctx context.Context, address net.IP) *Rate SetRate(ctx context.Context, address net.IP, limitedUntil time.Time) string } +// InMemoryLimiter is a concrete implementation of the Limiter interface. +// It stores rate limit data in memory using a cache, with each IP address associated with its corresponding rate information. type InMemoryLimiter struct { cache *cache.Cache[stringIpAddress, Rate] } +// NewInMemoryLimiter creates and returns a new instance of InMemoryLimiter. +// It accepts an expirationTime, which defines how long rate limit data will be cached. +// The cache will automatically purge expired data at twice the expiration time or at a default purge duration, whichever is greater. func NewInMemoryLimiter(expirationTime time.Duration) *InMemoryLimiter { purgeDuration := expirationTime * 2 if purgeDuration < defaultPurgeDuration { @@ -36,14 +43,19 @@ func NewInMemoryLimiter(expirationTime time.Duration) *InMemoryLimiter { } } +// Ensures that InMemoryLimiter implements the Limiter interface. var _ Limiter = (*InMemoryLimiter)(nil) +// GetRate retrieves the rate limit information for the given IP address from the in-memory cache. +// If no rate limit is found for the IP address, it returns nil. func (i *InMemoryLimiter) GetRate(_ context.Context, address net.IP) *Rate { rate, _ := i.cache.Get(stringIpAddress(address.String())) - return rate } +// SetRate sets the rate limit for the given IP address until the specified limitedUntil time. +// If a rate limit already exists for the IP address but the existing limit expires later than the provided time, +// the limit is not updated. The method returns a UUID associated with the new rate limit if it is set, or an empty string otherwise. func (i *InMemoryLimiter) SetRate(_ context.Context, address net.IP, limitedUntil time.Time) string { addrString := address.String() @@ -63,4 +75,5 @@ func (i *InMemoryLimiter) SetRate(_ context.Context, address net.IP, limitedUnti return id } +// stringIpAddress is a type alias for string, used to represent IP addresses in the cache. type stringIpAddress string diff --git a/internal/ratelimit/rate.go b/internal/ratelimit/rate.go index a1dedc3..d3ad749 100644 --- a/internal/ratelimit/rate.go +++ b/internal/ratelimit/rate.go @@ -3,8 +3,6 @@ package ratelimit import ( "net" "time" - - "waffle/internal/clock" ) type Rate struct { @@ -14,5 +12,5 @@ type Rate struct { } func (r *Rate) IsLimited() bool { - return clock.Now().Before(r.LimitedUntil) + return time.Now().Before(r.LimitedUntil) } diff --git a/internal/ratelimit/rate_test.go b/internal/ratelimit/rate_test.go index 427218c..41a056e 100644 --- a/internal/ratelimit/rate_test.go +++ b/internal/ratelimit/rate_test.go @@ -4,13 +4,11 @@ import ( "net" "testing" "time" - - "waffle/internal/clock" ) func TestRate_IsLimited(t *testing.T) { - limitedUntilBefore := clock.Now().Add(time.Duration(-1) * time.Hour) - limitedUntilAfter := clock.Now().Add(time.Hour) + limitedUntilBefore := time.Now().Add(time.Duration(-1) * time.Hour) + limitedUntilAfter := time.Now().Add(time.Hour) type fields struct { UUID string diff --git a/internal/redirect/handler.go b/internal/redirect/handler.go index 75857b2..30aabea 100644 --- a/internal/redirect/handler.go +++ b/internal/redirect/handler.go @@ -6,22 +6,33 @@ import ( "net/http/httputil" "strings" "time" - + "waffle/internal/domain" ) +// Handler is a struct that implements the http.Handler interface. +// It is responsible for processing incoming HTTP requests and forwarding them to the appropriate backend server +// based on the DNS resolution provided by the NameSystemProvider. type Handler struct { dns domain.NameSystemProvider } +// NewHandler creates and returns a new instance of Handler. +// It takes a NameSystemProvider as a parameter, which is used to resolve hostnames to addresses. func NewHandler(dns domain.NameSystemProvider) *Handler { return &Handler{ dns: dns, } } +// Ensures that Handler implements the http.Handler interface. var _ http.Handler = (*Handler)(nil) +// ServeHTTP processes an incoming HTTP request. +// It resolves the target address using the DNS provider based on the request's host. +// If an error occurs during resolution, it responds with a 502 Bad Gateway status. +// Otherwise, it sets up a reverse proxy to the resolved address and forwards the request, +// adjusting the request URL and headers as needed to maintain the correct context for the proxying. func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { addr, err := h.dns.GetAddress(r.Host) if err != nil { @@ -35,7 +46,6 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.URL.Scheme = addr.Scheme r.Header.Set("X-Forwarded-Host", r.Header.Get("Host")) r.Host = addr.Host - //trim reverseProxyRoutePrefix path := r.URL.Path r.URL.Path = strings.TrimLeft(path, addr.Path) fmt.Printf("[ TinyRP ] Redirecting request to %s at %s\n", r.URL, time.Now().UTC()) diff --git a/internal/request/wrapper.go b/internal/request/wrapper.go index f52c536..468a880 100644 --- a/internal/request/wrapper.go +++ b/internal/request/wrapper.go @@ -4,8 +4,6 @@ import ( "net" "net/http" "time" - - "waffle/internal/clock" ) // Wrapper is used to wrap request, in order to not pass it every time. @@ -21,6 +19,6 @@ func NewRequestWrapper(r *http.Request, ipAddress *net.IP) *Wrapper { return &Wrapper{ Request: r, IPAddress: ipAddress, - IssuedAt: clock.Now(), + IssuedAt: time.Now(), } } diff --git a/internal/visualize/server.go b/internal/visualize/server.go index e937a7f..389a233 100644 --- a/internal/visualize/server.go +++ b/internal/visualize/server.go @@ -2,16 +2,22 @@ package visualize import ( "context" + "log" "net/http" "nhooyr.io/websocket" ) +// Server represents a web server that listens on a specific port and includes a visualizer component. +// The visualizer is used to analyze or display certain data related to the server's functionality. type Server struct { port string visualizer *Visualizer } +// NewServer initializes and returns a new instance of the Server struct. +// It takes a port as input to define where the server will listen for incoming connections. +// A new Visualizer is also created and attached to the server during initialization. func NewServer(port string) *Server { return &Server{ port: port, @@ -19,19 +25,26 @@ func NewServer(port string) *Server { } } +// GetVisualizer returns the Visualizer instance associated with the server. +// This allows other components to access and use the visualizer for data visualization. func (s *Server) GetVisualizer() *Visualizer { return s.visualizer } +// Start begins the server's operation, listening on the specified port. +// It defines an HTTP handler that attempts to upgrade incoming HTTP connections to WebSocket connections. +// If a connection upgrade fails, the error is silently handled. +// The server listens for incoming requests and serves them using the handler. +// If the server fails to start, an error is returned and handled. func (s *Server) Start(ctx context.Context) { handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := websocket.Accept(w, r, nil) if err != nil { - + log.Fatalln("Accept error:", err) } }) if err := http.ListenAndServe(s.port, handlerFunc); err != nil { - + log.Fatalln("Error while listening and serving visualizer:", err) } } diff --git a/internal/worker/collector.go b/internal/worker/collector.go index 2c3b749..d796a44 100644 --- a/internal/worker/collector.go +++ b/internal/worker/collector.go @@ -47,6 +47,23 @@ func NewCollector( } } +// Run starts the packet capturing process for the Collector. +// It retrieves the network interface using the netInterfaceProvider. +// Then, it opens a live packet capture session on the interface using pcap, with a +// specified snapshot length of 1600 bytes, setting the device to promiscuous mode +// and waiting indefinitely for packets to arrive. +// +// If a BPF is provided in the configuration (c.cfg.BPF), +// it applies the filter to capture only relevant packets. +// +// The packets are read using a gopacket PacketSource and passed through a channel +// to be serialized by the Serializer in a separate goroutine. +// +// The function listens for packets in an infinite loop, and if the context is canceled +// (signaling termination), it gracefully exits. +// +// Deferred actions ensure that the packet channel is closed and a log message is generated +// when the collector is closed. func (c *Collector) Run(ctx context.Context) error { netInterface, err := c.netInterfaceProvider.GetNetworkInterface() if err != nil { @@ -74,7 +91,7 @@ func (c *Collector) Run(ctx context.Context) error { go func() { if err := c.serializer.SerializePackets(ctx, packetsChan); err != nil { - log.Println("error in serialize packets") + log.Printf("Error in serialize packets: %v\n", err) } }() @@ -82,7 +99,7 @@ func (c *Collector) Run(ctx context.Context) error { select { case packet, ok := <-packetSource.Packets(): if !ok { - log.Println("error reading packet") + log.Printf("Error while reading packet: %v\n", err) } packetsChan <- packet diff --git a/makefile b/makefile index bb14ce7..4f97745 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,8 @@ +IMAGE_NAME =? /: + certs_windows: mkdir -p "./cmd/proxy/.cert" + # Create CA (certificate authority) openssl ecparam -out ./cmd/proxy/.cert/ca.key -name prime256v1 -genkey openssl req -new -sha256 -key ./cmd/proxy/.cert/ca.key -out ./cmd/proxy/.cert/ca.csr @@ -13,6 +16,7 @@ certs_windows: certs: mkdir -p "./cmd/proxy/.cert" + # Create CA (certificate authority) openssl ecparam -out ./cmd/proxy/.cert/ca.key -name prime256v1 -genkey openssl req -new -sha256 -key ./cmd/proxy/.cert/ca.key -out ./cmd/proxy/.cert/ca.csr @@ -25,4 +29,10 @@ certs: openssl x509 -in ./cmd/proxy/.cert/server.crt -text -noout mocks: - mockery \ No newline at end of file + mockery + +docker-build: + docker build -t ${IMAGE_NAME} -f .\build\Dockerfile . + +docker-push: + docker push -t ${IMAGE_NAME} -f .\build\Dockerfile .