Skip to content

Commit

Permalink
Feat: Refactor backend server handling, unify connection methods
Browse files Browse the repository at this point in the history
Unified backend server handling by replacing separate IP and port with a single server struct across multiple modules. This refactor simplifies connection methods by integrating detailed server configurations, enabling improved handling of different protocols and connections, including enhanced TLS support and HAProxy v2 configurations.

Signed-off-by: Christian Roessner <[email protected]>
  • Loading branch information
Christian Roessner committed Dec 5, 2024
1 parent 2ad52d8 commit 463c00e
Show file tree
Hide file tree
Showing 11 changed files with 399 additions and 276 deletions.
17 changes: 11 additions & 6 deletions server/config/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,24 @@ func (r *RelayDomainsSection) String() string {
}

type BackendServer struct {
Protocol string `mapstructure:"protocol"`
IP string `mapstructure:"ip"`
Port int `mapstructure:"port"`
TLS bool `mapstructure:"tls"`
HAProxyV2 bool `mapstructure:"haproxy_v2"`
Protocol string `mapstructure:"protocol"`
Host string `mapstructure:"host"`
RequestURI string `mapstructure:"request_uri"`
TestUsername string `mapstructure:"test_username"`
TestPassword string `mapstructure:"test_password"`
Port int `mapstructure:"port"`
TLS bool `mapstructure:"tls"`
TLSSkipVerify bool `mapstructure:"tls_skip_verify"`
HAProxyV2 bool `mapstructure:"haproxy_v2"`
}

func (n *BackendServer) String() string {
if n == nil {
return "BackendServer: <nil>"
}

return fmt.Sprintf("BackendServers: {Protocol: %s, IP: %s, Port: %d}", n.Protocol, n.IP, n.Port)
return fmt.Sprintf("BackendServer: {Protocol: %s, Host: %s, RequestURI: %s, TestUsername: %s, TestPassword: <hidden>, Port: %d, TLS: %t, TLSSkipVerify: %t, HAProxyV2: %t}",
n.Protocol, n.Host, n.RequestURI, n.TestUsername, n.Port, n.TLS, n.TLSSkipVerify, n.HAProxyV2)
}

type BackendServerMonitoring struct {
Expand Down
2 changes: 1 addition & 1 deletion server/config/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (f *File) GetBackendServerIP(protocol string) string {
}

if f.GetBackendServer(protocol) != nil {
return f.GetBackendServer(protocol).IP
return f.GetBackendServer(protocol).Host
}

return ""
Expand Down
7 changes: 2 additions & 5 deletions server/definitions/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,8 @@ const (
// LogKeyLuaScripttimeout represents timeout setting for lua scripts
LogKeyLuaScripttimeout = "lua_script_timeout"

// LogKeyBackendServerIP represents the IP address of the backend server.
LogKeyBackendServerIP = "backend_server_ip"

// LogKeyBackendServerPort represents the port of the backend server.
LogKeyBackendServerPort = "backend_server_port"
// LogKeyBackendServer represents the IP address of the backend server.
LogKeyBackendServer = "backend_server"

// NotAvailable is used when data for a particular field is not available.
NotAvailable = "N/A"
Expand Down
24 changes: 12 additions & 12 deletions server/lua-plugins.d/filters/monitoring.lua
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,14 @@ function nauthilus_call_filter(request)
if nauthilus_util.is_table(backend_servers) then
num_of_bs = nauthilus_util.table_length(backend_servers)

local server_ip = ""
local new_server_ip = ""
local server_host = ""
local new_server_host = ""

local session = get_dovecot_session()
if session then
local maybe_server = get_server_from_sessions(session)
if maybe_server then
server_ip = maybe_server
server_host = maybe_server
end
end

Expand All @@ -168,13 +168,13 @@ function nauthilus_call_filter(request)
local b = nauthilus_backend_result.new()

for _, server in ipairs(backend_servers) do
new_server_ip = server.ip
new_server_host = server.host

if server_ip == new_server_ip then
attributes["Proxy-Host"] = server_ip
if server_host == new_server_host then
attributes["Proxy-Host"] = server_host

add_session(session, server_ip)
nauthilus_builtin.custom_log_add(N .. "_backend_server_current", server_ip)
add_session(session, server_host)
nauthilus_builtin.custom_log_add(N .. "_backend_server_current", server_host)

b:attributes(attributes)
nauthilus_backend.apply_backend_result(b)
Expand All @@ -183,13 +183,13 @@ function nauthilus_call_filter(request)
end
end

if server_ip ~= new_server_ip then
if server_host ~= new_server_host then
-- Put your own logic here to select a proper server for the user. In this demo, the last server
-- available is always used.
attributes["Proxy-Host"] = new_server_ip
attributes["Proxy-Host"] = new_server_host

add_session(session, new_server_ip)
nauthilus_builtin.custom_log_add(N .. "_backend_server_new", new_server_ip)
add_session(session, new_server_host)
nauthilus_builtin.custom_log_add(N .. "_backend_server_new", new_server_host)

b:attributes(attributes)
nauthilus_backend.apply_backend_result(b)
Expand Down
3 changes: 2 additions & 1 deletion server/lualib/backendresult.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ func backendResultGetSetAttributes(L *lua.LState) int {
backendResult := checkBackendResult(L)

if L.GetTop() == 2 {
backendResult.Attributes = convert.LuaValueToGo(L.CheckTable(2)).(map[any]any)
attributes := convert.LuaValueToGo(L.CheckTable(2)).(map[any]any)
backendResult.Attributes = attributes

return 0
}
Expand Down
70 changes: 32 additions & 38 deletions server/lualib/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,50 @@
package lualib

import (
"github.com/croessner/nauthilus/server/config"
"github.com/croessner/nauthilus/server/monitoring"
lua "github.com/yuin/gopher-lua"
)

// CheckBackendConnection is a Lua function that checks the connection to a backend server.
// It receives the server IP address, port number, a boolean flag indicating whether the server runs with HAProxy V2 protocol,
// and a boolean flag indicating whether TLS should be used.
// The function calls the CheckBackendConnection method of the provided monitoring.Monitor instance
// and returns an error message if there is an error, or nil if the connection is successful.
// getNumberFromTable retrieves an integer value from a Lua table for the given key. If the key is missing or nil, returns 0.
//
// Params:
// - monitor monitoring.Monitor : The monitoring.Monitor instance used to check the backend connection.
// Parameters:
// - table: The Lua table to search in.
// - key: The key to look for in the table.
//
// Returns:
// - int : The number of return values pushed to the Lua stack, always 1.
//
// Lua stack requirements:
// - 4 arguments are expected in the following order:
// 1. string : The server IP address.
// 2. int : The server port number.
// 3. boolean : Whether the server runs with HAProxy V2 protocol.
// 4. boolean : Whether TLS should be used.
// - The arguments should be of the expected types; otherwise, an error will be raised.
// - The function expects to have 1 return value on the stack - nil if the connection is successful,
// or a string with an error message if there is an error.
//
// Example:
//
// connection_error = check_backend_connection("192.168.0.1", 8080, false, true)
// if connection_error ~= nil then
// log("Connection failed: " .. connection_error)
// else
// log("Connection successful")
// end
//
// Note: The above example is in Lua language and should be executed in a Lua environment.
// - The integer value associated with the key, or 0 if the key is not present or value is nil.
func getNumberFromTable(table *lua.LTable, key string) int {
value := table.RawGet(lua.LString(key))

if value == nil {
return 0
}

return int(value.(lua.LNumber))
}

// CheckBackendConnection attempts to verify the connection to a backend server using the provided monitor.
// It extracts necessary configuration details such as protocol, IP address, port, and credentials from the given Lua table.
// The function then calls the monitor's CheckBackendConnection method to perform the actual connectivity check.
// If the connection check encounters an error, this error is pushed onto the Lua stack.
// If the connection check is successful, a nil value is pushed onto the Lua stack.
// It returns an integer indicating the number of results pushed onto the Lua stack.
func CheckBackendConnection(monitor monitoring.Monitor) lua.LGFunction {
return func(L *lua.LState) int {
if L.GetTop() != 4 {
L.RaiseError("Invalid number of arguments. Expected 4, got %d", L.GetTop())
table := L.CheckTable(1)

return 0
}
server := &config.BackendServer{}

server := L.CheckString(1)
port := L.CheckInt(2)
haproxyV2 := L.CheckBool(3)
tls := L.CheckBool(4)
server.Protocol = getStringFromTable(table, "protocol")
server.Host = getStringFromTable(table, "ip_address")
server.Port = getNumberFromTable(table, "port")
server.HAProxyV2 = getBoolFromTable(table, "haproxy_v2")
server.TLS = getBoolFromTable(table, "tls")
server.TestUsername = getStringFromTable(table, "test_username")
server.TestPassword = getStringFromTable(table, "test_password")

if err := monitor.CheckBackendConnection(server, port, haproxyV2, tls); err != nil {
if err := monitor.CheckBackendConnection(server); err != nil {
L.Push(lua.LString(err.Error()))

return 1
Expand Down
120 changes: 0 additions & 120 deletions server/lualib/connection_test.go

This file was deleted.

Loading

0 comments on commit 463c00e

Please sign in to comment.