Skip to content

Commit

Permalink
Merge pull request #123 from croessner/features
Browse files Browse the repository at this point in the history
Features
  • Loading branch information
croessner authored Sep 30, 2024
2 parents 51eebeb + c50d18b commit fa181f3
Show file tree
Hide file tree
Showing 49 changed files with 10,029 additions and 9 deletions.
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ require (
github.com/simia-tech/crypt v0.5.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
github.com/tengattack/gluacrypto v0.0.0-20240324200146-54b58c95c255
github.com/vadv/gopher-lua-libs v0.5.0
github.com/yuin/gopher-lua v1.1.1
Expand All @@ -62,6 +63,7 @@ require (
github.com/cheggaaa/pb/v3 v3.1.5 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emersion/go-message v0.18.0 // indirect
Expand Down Expand Up @@ -91,6 +93,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/magiconair/properties v1.8.7 // indirect
Expand All @@ -104,6 +107,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/common v0.59.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
Expand Down
11 changes: 10 additions & 1 deletion server/core/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import (
"crypto/subtle"
"crypto/tls"
stderrors "errors"
"fmt"
"io"
"net"
"net/http"
"os"
"strings"
"sync/atomic"
"time"

Expand Down Expand Up @@ -115,6 +117,8 @@ func (lc *LimitCounter) Middleware() gin.HandlerFunc {

atomic.AddInt32(&lc.CurrentConnections, 1)

stats.CurrentRequests.Set(float64(atomic.LoadInt32(&lc.CurrentConnections)))

defer atomic.AddInt32(&lc.CurrentConnections, -1)

ctx.Next()
Expand Down Expand Up @@ -591,7 +595,12 @@ func prometheusMiddleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
var timer *prometheus.Timer

stopTimer := stats.PrometheusTimer(global.PromRequest, "request_total")
mode := ctx.Query("mode")
if mode == "" {
mode = "auth"
}

stopTimer := stats.PrometheusTimer(global.PromRequest, fmt.Sprintf("request_%s_total", strings.ReplaceAll(mode, "-", "_")))
path := ctx.FullPath()

if config.LoadableConfig.Server.PrometheusTimer.Enabled {
Expand Down
18 changes: 18 additions & 0 deletions server/global/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,9 @@ const (
// LuaModHTTPRequest is a constant representing the value "nauthilus_http_request".
LuaModHTTPRequest = "nauthilus_http_request"

// LuaModPrometheus is a constant that identifies the Prometheus module for monitoring and metrics collection.
LuaModPrometheus = "nauthilus_prometheus"

// LuaModGLuaCrypto is a constant that represents the name of the GLuaCrypto module in Lua.
LuaModGLuaCrypto = "nauthilus_gluacrypto"

Expand Down Expand Up @@ -1220,6 +1223,21 @@ const (

// LuaFnWaitRandom represents the constant value for the Lua function name "wait_random".
LuaFnWaitRandom = "wait_random"

// LuaFnCreateSummaryVec represents the identifier for creating a Prometheus SummaryVec.
LuaFnCreateSummaryVec = "create_summary_vec"

// LuaFnCreateCounterVec represents the identifier for creating a Prometheus CounterVec.
LuaFnCreateCounterVec = "create_counter_vec"

// LuaFnStartTimer specifies the identifier for starting a Prometheus timer.
LuaFnStartTimer = "start_timer"

// LuaFnStopTimer defines the identifier for stopping a Prometheus timer.
LuaFnStopTimer = "stop_timer"

// LuaFnIncrementCounter represents the identifier for incrementing a Prometheus counter.
LuaFnIncrementCounter = "increment_counter"
)

const (
Expand Down
8 changes: 8 additions & 0 deletions server/lua-plugins.d/actions/haveibeenpwnd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ function nauthilus_call_action(request)
dynamic_loader("nauthilus_context")
local nauthilus_context = require("nauthilus_context")

dynamic_loader("nauthilus_prometheus")
local nauthilus_prometheus = require("nauthilus_prometheus")

dynamic_loader("nauthilus_gluacrypto")
local crypto = require('crypto')

Expand Down Expand Up @@ -82,13 +85,18 @@ function nauthilus_call_action(request)
end
end


nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the haveibeenpwnd network", {"http"})

local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {http="get"})
local result, err = http.get("https://api.pwnedpasswords.com/range/" .. hash:sub(1, 5), {
timeout = "10s",
headers = {
Accept = "*/*",
["User-Agent"] = "Nauthilus",
},
})
nauthilus_prometheus.stop_timer(timer)
nauthilus_util.if_error_raise(err)

if result.status_code ~= 200 then
Expand Down
7 changes: 7 additions & 0 deletions server/lua-plugins.d/actions/telegram.lua
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ function nauthilus_call_action(request)
end

if send_message then
dynamic_loader("nauthilus_prometheus")
local nauthilus_prometheus = require("nauthilus_prometheus")

dynamic_loader("nauthilus_gll_http")
local http = require("http")

Expand Down Expand Up @@ -153,10 +156,14 @@ function nauthilus_call_action(request)
values.username = username
values.pwnd_info = pwnd_info

nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the telegram network", {"bot"})

local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {bot="send"})
local _, err_bat = bot:sendMessage({
chat_id = tonumber(os.getenv("TELEGRAM_CHAT_ID")),
text = headline .. mustache:render(":\n\nSESSION {{session}}\nTS {{ts}}\nIP {{client_ip}}\nHOSTNAME {{hostname}}\nPROTOCOL {{proto}}\nDISPLAY_NAME {{display_name}}\nACCOUNT {{account}}\nUNIQUE ID {{unique_user_id}}\nUSERNAME {{username}}\nPWND INFO {{pwnd_info}}", values)
})
nauthilus_prometheus.stop_timer(timer)
nauthilus_util.if_error_raise(err_bat)

result.caller = N .. ".lua"
Expand Down
9 changes: 8 additions & 1 deletion server/lua-plugins.d/features/blocklist.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <https://www.gnu.org/licenses/>.

local N = "feature_blocklist"
local N = "blocklist"

function nauthilus_call_feature(request)
if request.no_auth then
Expand All @@ -25,6 +25,9 @@ function nauthilus_call_feature(request)
dynamic_loader("nauthilus_context")
local nauthilus_context = require("nauthilus_context")

dynamic_loader("nauthilus_prometheus")
local nauthilus_prometheus = require("nauthilus_prometheus")

dynamic_loader("nauthilus_gluahttp")
local http = require("glua_http")

Expand All @@ -44,6 +47,9 @@ function nauthilus_call_feature(request)
local payload, json_encode_err = json.encode(t)
nauthilus_util.if_error_raise(json_encode_err)

nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the blocklist service", {"http"})

local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {http="post"})
local result, request_err = http.post(os.getenv("BLOCKLIST_URL"), {
timeout = "10s",
headers = {
Expand All @@ -53,6 +59,7 @@ function nauthilus_call_feature(request)
},
body = payload,
})
nauthilus_prometheus.stop_timer(timer)
nauthilus_util.if_error_raise(request_err)

if result.status_code ~= 200 then
Expand Down
7 changes: 7 additions & 0 deletions server/lua-plugins.d/filters/geoip.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ function nauthilus_call_filter(request)
dynamic_loader("nauthilus_context")
local nauthilus_context = require("nauthilus_context")

dynamic_loader("nauthilus_prometheus")
local nauthilus_prometheus = require("nauthilus_prometheus")

dynamic_loader("nauthilus_gluahttp")
local http = require("glua_http")

Expand All @@ -75,6 +78,9 @@ function nauthilus_call_filter(request)
local payload, json_encode_err = json.encode(t)
nauthilus_util.if_error_raise(json_encode_err)

nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the geoip-policyd service", {"http"})

local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {http="post"})
local result, request_err = http.post(os.getenv("GEOIP_POLICY_URL"), {
timeout = "10s",
headers = {
Expand All @@ -84,6 +90,7 @@ function nauthilus_call_filter(request)
},
body = payload,
})
nauthilus_prometheus.stop_timer(timer)
nauthilus_util.if_error_raise(request_err)

if result.status_code ~= 202 then
Expand Down
3 changes: 3 additions & 0 deletions server/lualib/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/cjoudrey/gluahttp"
"github.com/croessner/nauthilus/server/global"
"github.com/croessner/nauthilus/server/lualib/metrics"
"github.com/croessner/nauthilus/server/lualib/redislib"
"github.com/croessner/nauthilus/server/lualib/smtp"
"github.com/tengattack/gluacrypto"
Expand Down Expand Up @@ -158,6 +159,8 @@ func RegisterCommonLuaLibraries(L *lua.LState, modName string, registry map[stri
L.PreloadModule(modName, mailModule.Loader)
case global.LuaModMisc:
L.PreloadModule(modName, LoaderModMisc)
case global.LuaModPrometheus:
L.PreloadModule(modName, metrics.LoaderModPrometheus)
default:
return
}
Expand Down
148 changes: 148 additions & 0 deletions server/lualib/metrics/statistics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package metrics

import (
"github.com/croessner/nauthilus/server/global"
"github.com/prometheus/client_golang/prometheus"
"github.com/yuin/gopher-lua"
)

var (
summaries = make(map[string]*prometheus.SummaryVec)
counters = make(map[string]*prometheus.CounterVec)
)

// createSummaryVec registers a new Prometheus SummaryVec metric with the provided name, help description, and label names.
func createSummaryVec(L *lua.LState) int {
name := L.CheckString(1)
help := L.CheckString(2)

labelNames := make([]string, 0)

if L.GetTop() > 2 {
labelTable := L.CheckTable(3)
labelTable.ForEach(func(_ lua.LValue, value lua.LValue) {
labelNames = append(labelNames, value.String())
})
}

// Check if the summary already exists
if _, exists := summaries[name]; exists {
return 0
}

summary := prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: name,
Help: help,
}, labelNames)

prometheus.MustRegister(summary)

summaries[name] = summary

return 0
}

// createCounterVec registers a new Prometheus CounterVec metric with the provided name, help description, and label names.
func createCounterVec(L *lua.LState) int {
name := L.CheckString(1)
help := L.CheckString(2)

labelNames := make([]string, 0)

if L.GetTop() > 2 {
labelTable := L.CheckTable(3)
labelTable.ForEach(func(_ lua.LValue, value lua.LValue) {
labelNames = append(labelNames, value.String())
})
}

// Check if the counter already exists
if _, exists := counters[name]; exists {
return 0
}

counter := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: name,
Help: help,
}, labelNames)

prometheus.MustRegister(counter)

counters[name] = counter

return 0
}

// startTimer starts a Prometheus timer for a specified SummaryVec metric with the provided label values.
func startTimer(L *lua.LState) int {
name := L.CheckString(1)
labels := L.CheckTable(2)

summary, exists := summaries[name]
if !exists {
L.ArgError(1, "SummaryVec not found")

return 0
}

labelValues := make(map[string]string)
labels.ForEach(func(key, value lua.LValue) {
labelValues[key.String()] = value.String()
})

timer := prometheus.NewTimer(summary.With(labelValues))
ud := L.NewUserData()
ud.Value = timer

L.Push(ud)

return 1
}

// stopTimer stops a running Prometheus timer, recording its duration in the underlying metric.
func stopTimer(L *lua.LState) int {
ud := L.CheckUserData(1)

if timer, ok := ud.Value.(*prometheus.Timer); ok {
timer.ObserveDuration()
}

return 0
}

// incrementCounter increments a Prometheus counter based on the name and label values provided in the Lua state.
func incrementCounter(L *lua.LState) int {
name := L.CheckString(1)
labels := L.CheckTable(2)

counter, exists := counters[name]
if !exists {
L.ArgError(1, "CounterVec not found")
return 0
}

labelValues := make(map[string]string)
labels.ForEach(func(key, value lua.LValue) {
labelValues[key.String()] = value.String()
})

counter.With(labelValues).Inc()

return 0
}

var exportsModPrometheus = map[string]lua.LGFunction{
global.LuaFnCreateSummaryVec: createSummaryVec,
global.LuaFnCreateCounterVec: createCounterVec,
global.LuaFnStartTimer: startTimer,
global.LuaFnStopTimer: stopTimer,
global.LuaFnIncrementCounter: incrementCounter,
}

func LoaderModPrometheus(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), exportsModPrometheus)

L.Push(mod)

return 1
}
Loading

0 comments on commit fa181f3

Please sign in to comment.