Toby Chui cd822ed904 Added dynamic capture example
- Added dynamic capture plugin example
- Added dynamic capture plugin doc
- Removed ztnc from plugin example
2025-05-30 21:21:08 +08:00

132 lines
4.0 KiB
Go

package main
import (
"fmt"
"net/http"
"sort"
"strconv"
"strings"
plugin "example.com/zoraxy/dynamic-capture-example/mod/zoraxy_plugin"
)
const (
PLUGIN_ID = "org.aroz.zoraxy.dynamic-capture-example"
UI_PATH = "/debug"
STATIC_CAPTURE_INGRESS = "/s_capture"
)
func main() {
// Serve the plugin intro spect
// This will print the plugin intro spect and exit if the -introspect flag is provided
runtimeCfg, err := plugin.ServeAndRecvSpec(&plugin.IntroSpect{
ID: "org.aroz.zoraxy.dynamic-capture-example",
Name: "Dynamic Capture Example",
Author: "aroz.org",
AuthorContact: "https://aroz.org",
Description: "This is an example plugin for Zoraxy that demonstrates how to use dynamic captures.",
URL: "https://zoraxy.aroz.org",
Type: plugin.PluginType_Router,
VersionMajor: 1,
VersionMinor: 0,
VersionPatch: 0,
DynamicCaptureSniff: "/d_sniff",
DynamicCaptureIngress: "/d_capture",
UIPath: UI_PATH,
/*
SubscriptionPath: "/subept",
SubscriptionsEvents: []plugin.SubscriptionEvent{
*/
})
if err != nil {
//Terminate or enter standalone mode here
panic(err)
}
// Setup the path router
pathRouter := plugin.NewPathRouter()
pathRouter.SetDebugPrintMode(true)
/*
Dynamic Captures
*/
pathRouter.RegisterDynamicSniffHandler("/d_sniff", http.DefaultServeMux, func(dsfr *plugin.DynamicSniffForwardRequest) plugin.SniffResult {
//In this example, we want to capture all URI
//that start with /foobar and forward it to the dynamic capture handler
if strings.HasPrefix(dsfr.RequestURI, "/foobar") {
reqUUID := dsfr.GetRequestUUID()
fmt.Println("Accepting request with UUID: " + reqUUID)
// Print all the values of the request
fmt.Println("Method:", dsfr.Method)
fmt.Println("Hostname:", dsfr.Hostname)
fmt.Println("URL:", dsfr.URL)
fmt.Println("Header:")
for key, values := range dsfr.Header {
for _, value := range values {
fmt.Printf(" %s: %s\n", key, value)
}
}
fmt.Println("RemoteAddr:", dsfr.RemoteAddr)
fmt.Println("Host:", dsfr.Host)
fmt.Println("RequestURI:", dsfr.RequestURI)
fmt.Println("Proto:", dsfr.Proto)
fmt.Println("ProtoMajor:", dsfr.ProtoMajor)
fmt.Println("ProtoMinor:", dsfr.ProtoMinor)
// We want to handle this request, reply with aSniffResultAccept
return plugin.SniffResultAccpet
}
// If the request URI does not match, we skip this request
fmt.Println("Skipping request with UUID: " + dsfr.GetRequestUUID())
return plugin.SniffResultSkip
})
pathRouter.RegisterDynamicCaptureHandle("/d_capture", http.DefaultServeMux, func(w http.ResponseWriter, r *http.Request) {
// This is the dynamic capture handler where it actually captures and handle the request
w.WriteHeader(http.StatusOK)
w.Write([]byte("Welcome to the dynamic capture handler!"))
// Print all the request info to the response writer
w.Write([]byte("\n\nRequest Info:\n"))
w.Write([]byte("Request URI: " + r.RequestURI + "\n"))
w.Write([]byte("Request Method: " + r.Method + "\n"))
w.Write([]byte("Request Headers:\n"))
headers := make([]string, 0, len(r.Header))
for key := range r.Header {
headers = append(headers, key)
}
sort.Strings(headers)
for _, key := range headers {
for _, value := range r.Header[key] {
w.Write([]byte(fmt.Sprintf("%s: %s\n", key, value)))
}
}
})
http.HandleFunc(UI_PATH+"/", RenderDebugUI)
fmt.Println("Dynamic capture example started at http://127.0.0.1:" + strconv.Itoa(runtimeCfg.Port))
http.ListenAndServe("127.0.0.1:"+strconv.Itoa(runtimeCfg.Port), nil)
}
// Render the debug UI
func RenderDebugUI(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "**Plugin UI Debug Interface**\n\n[Recv Headers] \n")
headerKeys := make([]string, 0, len(r.Header))
for name := range r.Header {
headerKeys = append(headerKeys, name)
}
sort.Strings(headerKeys)
for _, name := range headerKeys {
values := r.Header[name]
for _, value := range values {
fmt.Fprintf(w, "%s: %s\n", name, value)
}
}
w.Header().Set("Content-Type", "text/html")
}