about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Taskfile.yml5
-rw-r--r--bridge/main.go110
3 files changed, 115 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index d163863..542a269 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-build/
\ No newline at end of file
+build/
+test.socket
\ No newline at end of file
diff --git a/Taskfile.yml b/Taskfile.yml
index adda6eb..ec302d9 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -18,3 +18,8 @@ tasks:
     deps: [build]
     cmds:
       - build/bridge
+
+  open-test-socket:
+    desc: "Opens and listens to `./test.socket`."
+    cmds:
+      - ncat -Ulk ./test.socket
diff --git a/bridge/main.go b/bridge/main.go
index 8a55772..1c70fdc 100644
--- a/bridge/main.go
+++ b/bridge/main.go
@@ -1,5 +1,111 @@
 package main
 
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"log/slog"
+	"net"
+	"os"
+	"strconv"
+)
+
 func main() {
-	println("hello!!!! this is the container bridge")
-}
\ No newline at end of file
+	slog.Info("starting container bridge...")
+
+	info := getInfo()
+	slog.Info("got configuration from environment variables.", slog.Any("info", info))
+
+	source, err := net.Listen("tcp", fmt.Sprintf(":%d", info.Port))
+	dieIfErr(err, "failed to listen on port.")
+
+	slog.Info("listening...", slog.Uint64("port", uint64(info.Port)))
+	for {
+		conn, err := source.Accept()
+		if err != nil {
+			slog.Error("could not accept conenction.", slog.Any("error", err))
+			continue
+		}
+		slog.Info("accepted connection.", slog.String("remoteAddr", conn.RemoteAddr().String()))
+
+		go bridge(conn, info.SocketPath)
+	}
+}
+
+func bridge(source net.Conn, socketPath string) {
+	data := bytes.NewBuffer([]byte{})
+	for {
+		buffer := make([]byte, 1024)
+		n, err := source.Read(buffer)
+		if err != nil {
+			if err == io.EOF {
+				slog.Info("got EOF...", slog.String("remoteAddr", source.RemoteAddr().String()))
+				break
+			}
+			slog.Error("could not read from connection.", slog.Any("error", err))
+			break
+		}
+
+		n, err = data.Write(buffer[:n])
+		if err != nil {
+			slog.Error("could not write to buffer.", slog.Any("error", err))
+			break
+		}
+	}
+	source.Close()
+	slog.Info("connection completed. attempting write...", slog.String("remoteAddr", source.RemoteAddr().String()))
+
+	destination, err := net.Dial("unix", socketPath)
+	if err != nil {
+		slog.Error("could not connect to destination socket.", slog.Any("error", err))
+		return
+	}
+	defer destination.Close()
+
+	_, err = destination.Write(data.Bytes())
+	if err != nil {
+		slog.Error("could not write to destination socket.", slog.Any("error", err))
+		return
+	}
+	
+	slog.Info("write to destination socket successful.", slog.String("remoteAddr", source.RemoteAddr().String()))
+}
+
+type Info struct {
+	Port       uint64
+	SocketPath string
+}
+
+func getInfo() Info {
+	portStr := os.Getenv("PORT")
+	if portStr == "" {
+		die("`PORT` environment variable must be set.")
+	}
+
+	port, err := strconv.ParseUint(portStr, 10, 32)
+	dieIfErr(err, "could not parse `PORT` environment variable.")
+
+	path := os.Getenv("SOCKET_PATH")
+	if path == "" {
+		defaultPath := fmt.Sprintf("/run/cthcous/%d.socket", port)
+		slog.Warn("`SOCKET_PATH` environment variable not set.", "default", string(defaultPath))
+	}
+
+	if _, err := os.Stat(path); os.IsNotExist(err) {
+		die(fmt.Sprintf("socket path `%s` does not exist.", path))
+	}
+
+	return Info{Port: port, SocketPath: path}
+}
+
+func die(msg string) {
+	slog.Error(msg)
+	os.Exit(1)
+}
+
+func dieIfErr(err error, msg string) {
+	if err != nil {
+		slog.Error(msg, slog.Any("error", err))
+		os.Exit(1)
+	}
+}