mirror of
https://github.com/openappsec/attachment.git
synced 2025-06-28 16:41:03 +03:00
Update istio (#34)
* update istio * update istio * fixing istio * fix library name * fix library name * fix missing defenition of advanced-model * fix append * fix wrong name * fix pvc issue * fix config.go file * fix config.go file * fix config.go file * fix config.go file --------- Co-authored-by: Daniel Eisenberg <danielei@checkpoint.com>
This commit is contained in:
parent
83fccba6a5
commit
22852d8428
@ -1,3 +1,6 @@
|
|||||||
add_subdirectory(envoy)
|
|
||||||
add_subdirectory(nano_attachment)
|
add_subdirectory(nano_attachment)
|
||||||
add_subdirectory(nginx)
|
if ("${ATTACHMENT_TYPE}" STREQUAL "envoy")
|
||||||
|
add_subdirectory(envoy)
|
||||||
|
else()
|
||||||
|
add_subdirectory(nginx)
|
||||||
|
endif()
|
||||||
|
33
attachments/envoy/1.31/CMakeLists.txt
Executable file
33
attachments/envoy/1.31/CMakeLists.txt
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND ATTACHMENT_TYPE STREQUAL "envoy")
|
||||||
|
set(ATTACHMENTS_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/core/include/attachments)
|
||||||
|
set(NANO_ATTACHMENT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/attachments/nano_attachment)
|
||||||
|
set(SHMEM_LIBRARY_DIR ${CMAKE_BINARY_DIR}/core/shmem_ipc_2)
|
||||||
|
set(NANO_ATTACHMENT_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment)
|
||||||
|
set(NANO_ATTACHMENT_UTIL_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment/nano_attachment_util)
|
||||||
|
set(LIBRARIES "-lnano_attachment -lnano_attachment_util -lshmem_ipc_2")
|
||||||
|
set(ENVOY_ATTACHMENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
get_filename_component(CURRENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
|
||||||
|
# Configure the build.sh script from the template
|
||||||
|
configure_file(
|
||||||
|
${PROJECT_SOURCE_DIR}/attachments/envoy/${CURRENT_DIR}/build_template
|
||||||
|
${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define a custom command to run the bash script
|
||||||
|
add_custom_target(
|
||||||
|
envoy_attachment${CURRENT_DIR} ALL
|
||||||
|
COMMAND chmod +x ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
COMMAND ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/attachments/envoy
|
||||||
|
COMMENT "Building envoy attachment ${CURRENT_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(envoy_attachment${CURRENT_DIR} shmem_ipc_2 nano_attachment nano_attachment_util)
|
||||||
|
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION envoy/${CURRENT_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
endif()
|
||||||
|
|
13
attachments/envoy/1.31/build_template
Executable file
13
attachments/envoy/1.31/build_template
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
SHMEM_LIBRARY_DIR="@SHMEM_LIBRARY_DIR@"
|
||||||
|
NANO_ATTACHMENT_LIBRARY_DIR="@NANO_ATTACHMENT_LIBRARY_DIR@"
|
||||||
|
NANO_ATTACHMENT_UTIL_LIBRARY_DIR="@NANO_ATTACHMENT_UTIL_LIBRARY_DIR@"
|
||||||
|
LIBRARIES="@LIBRARIES@"
|
||||||
|
ENVOY_ATTACHMENT_DIR="@ENVOY_ATTACHMENT_DIR@"
|
||||||
|
|
||||||
|
cd $ENVOY_ATTACHMENT_DIR
|
||||||
|
|
||||||
|
# Run the go build command
|
||||||
|
CGO_CFLAGS="-I@ATTACHMENTS_INCLUDE_DIR@ -I@NANO_ATTACHMENT_INCLUDE_DIR@" go build -o ${ENVOY_ATTACHMENT_DIR}/libenvoy_attachment.so -buildmode=c-shared -ldflags="-w -s -extldflags '-L${SHMEM_LIBRARY_DIR} -L${NANO_ATTACHMENT_LIBRARY_DIR} -L${NANO_ATTACHMENT_UTIL_LIBRARY_DIR} ${LIBRARIES}'"
|
@ -154,7 +154,7 @@ func configurationServer() {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
last_keep_alive = time.Time{}
|
last_keep_alive = time.Time{}
|
||||||
envoyHttp.RegisterHttpFilterConfigFactoryAndParser(Name, ConfigFactory, &parser{})
|
envoyHttp.RegisterHttpFilterFactoryAndConfigParser(Name, ConfigFactory, &parser{})
|
||||||
go configurationServer()
|
go configurationServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,13 +239,12 @@ func (p *parser) Merge(parent interface{}, child interface{}) interface{} {
|
|||||||
return &newConfig
|
return &newConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConfigFactory(c interface{}) api.StreamFilterFactory {
|
func ConfigFactory(c interface{}, callbacks api.FilterCallbackHandler) api.StreamFilter {
|
||||||
conf, ok := c.(*config)
|
conf, ok := c.(*config)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("unexpected config type")
|
panic("unexpected config type")
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(callbacks api.FilterCallbackHandler) api.StreamFilter {
|
|
||||||
worker_thread_id := int(C.get_thread_id())
|
worker_thread_id := int(C.get_thread_id())
|
||||||
api.LogDebugf("worker_thread_id: %d", worker_thread_id)
|
api.LogDebugf("worker_thread_id: %d", worker_thread_id)
|
||||||
if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
|
if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
|
||||||
@ -278,7 +277,6 @@ func ConfigFactory(c interface{}) api.StreamFilterFactory {
|
|||||||
session_data: session_data,
|
session_data: session_data,
|
||||||
request_structs: attachment_to_filter_request_structs[worker_id],
|
request_structs: attachment_to_filter_request_structs[worker_id],
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {}
|
func main() {}
|
@ -154,6 +154,11 @@ func (f *filter) sendData(data unsafe.Pointer, chunkType C.HttpChunkType) C.Atta
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *filter) handleCustomResponse(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
func (f *filter) handleCustomResponse(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
||||||
|
if verdict_response.web_response_data.web_response_type == C.RESPONSE_CODE_ONLY {
|
||||||
|
response_code := C.GetResponseCode((*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
return f.sendLocalReplyInternal(int(response_code), "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
if verdict_response.web_response_data.web_response_type == C.CUSTOM_WEB_RESPONSE {
|
if verdict_response.web_response_data.web_response_type == C.CUSTOM_WEB_RESPONSE {
|
||||||
headers := map[string][]string{
|
headers := map[string][]string{
|
||||||
"Content-Type": []string{"text/html"},
|
"Content-Type": []string{"text/html"},
|
||||||
@ -231,6 +236,7 @@ func (f *filter) sendBody(buffer api.BufferInstance, is_req bool) C.AttachmentVe
|
|||||||
data := buffer.Bytes()
|
data := buffer.Bytes()
|
||||||
data_len := len(data)
|
data_len := len(data)
|
||||||
buffer_size := 8 * 1024
|
buffer_size := 8 * 1024
|
||||||
|
|
||||||
num_of_buffers := ((data_len - 1) / buffer_size) + 1
|
num_of_buffers := ((data_len - 1) / buffer_size) + 1
|
||||||
|
|
||||||
// TO DO: FIX THIS ASAP
|
// TO DO: FIX THIS ASAP
|
||||||
@ -296,7 +302,7 @@ func (f *filter) handleStartTransaction(header api.RequestHeaderMap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *filter) sendLocalReplyInternal(ret_code int, custom_response string, headers map[string][]string) api.StatusType {
|
func (f *filter) sendLocalReplyInternal(ret_code int, custom_response string, headers map[string][]string) api.StatusType {
|
||||||
f.callbacks.SendLocalReply(ret_code, custom_response, headers, 0, "")
|
f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "")
|
||||||
return api.LocalReply
|
return api.LocalReply
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ go 1.20
|
|||||||
// NOTICE: these lines could be generated automatically by "go mod tidy"
|
// NOTICE: these lines could be generated automatically by "go mod tidy"
|
||||||
require (
|
require (
|
||||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa
|
||||||
github.com/envoyproxy/envoy v1.29.8-0.20240702140355-f3e7e90ed021
|
github.com/envoyproxy/envoy v1.31.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
)
|
)
|
||||||
|
|
@ -1,9 +1,5 @@
|
|||||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
||||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||||
github.com/envoyproxy/envoy v1.28.1-0.20231218050644-ca5d45d1887a h1:PQveCjvjXZS400K7z+uuouN/Q/dLhLpB5a/6GIC4v34=
|
|
||||||
github.com/envoyproxy/envoy v1.28.1-0.20231218050644-ca5d45d1887a/go.mod h1:STO/nOGQMw2DNOFTaokM1VY72GJBs0mbXq0I1lJr0XQ=
|
|
||||||
github.com/envoyproxy/envoy v1.29.8-0.20240702140355-f3e7e90ed021 h1:mTisjPVHGpxlWi7Yj7PnpxD0GeoauHcWvEgch069i+M=
|
|
||||||
github.com/envoyproxy/envoy v1.29.8-0.20240702140355-f3e7e90ed021/go.mod h1:ujBFxE543X8OePZG+FbeR9LnpBxTLu64IAU7A20EB9A=
|
|
||||||
github.com/envoyproxy/envoy v1.31.0 h1:NsTo+medzu0bMffXAjl+zKaViLOShKuIZWQnKKYq0/4=
|
github.com/envoyproxy/envoy v1.31.0 h1:NsTo+medzu0bMffXAjl+zKaViLOShKuIZWQnKKYq0/4=
|
||||||
github.com/envoyproxy/envoy v1.31.0/go.mod h1:ujBFxE543X8OePZG+FbeR9LnpBxTLu64IAU7A20EB9A=
|
github.com/envoyproxy/envoy v1.31.0/go.mod h1:ujBFxE543X8OePZG+FbeR9LnpBxTLu64IAU7A20EB9A=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
33
attachments/envoy/1.32/CMakeLists.txt
Executable file
33
attachments/envoy/1.32/CMakeLists.txt
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND ATTACHMENT_TYPE STREQUAL "envoy")
|
||||||
|
set(ATTACHMENTS_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/core/include/attachments)
|
||||||
|
set(NANO_ATTACHMENT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/attachments/nano_attachment)
|
||||||
|
set(SHMEM_LIBRARY_DIR ${CMAKE_BINARY_DIR}/core/shmem_ipc_2)
|
||||||
|
set(NANO_ATTACHMENT_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment)
|
||||||
|
set(NANO_ATTACHMENT_UTIL_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment/nano_attachment_util)
|
||||||
|
set(LIBRARIES "-lnano_attachment -lnano_attachment_util -lshmem_ipc_2")
|
||||||
|
set(ENVOY_ATTACHMENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
get_filename_component(CURRENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
|
||||||
|
# Configure the build.sh script from the template
|
||||||
|
configure_file(
|
||||||
|
${PROJECT_SOURCE_DIR}/attachments/envoy/${CURRENT_DIR}/build_template
|
||||||
|
${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define a custom command to run the bash script
|
||||||
|
add_custom_target(
|
||||||
|
envoy_attachment${CURRENT_DIR} ALL
|
||||||
|
COMMAND chmod +x ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
COMMAND ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/attachments/envoy
|
||||||
|
COMMENT "Building envoy attachment ${CURRENT_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(envoy_attachment${CURRENT_DIR} shmem_ipc_2 nano_attachment nano_attachment_util)
|
||||||
|
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION envoy/${CURRENT_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
endif()
|
||||||
|
|
282
attachments/envoy/1.32/config.go
Executable file
282
attachments/envoy/1.32/config.go
Executable file
@ -0,0 +1,282 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
|
||||||
|
xds "github.com/cncf/xds/go/xds/type/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
envoyHttp "github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
unsigned long get_thread_id() {
|
||||||
|
return (unsigned long)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
const Name = "cp_nano_filter"
|
||||||
|
const admin_api_server_info = "http://127.0.0.1:%s/server_info"
|
||||||
|
const keep_alive_interval = 10 * time.Second
|
||||||
|
|
||||||
|
var filter_id atomic.Int64
|
||||||
|
var attachments_map map[int]*nano_attachment = nil
|
||||||
|
var thread_to_attachment_mapping map[int]int = nil
|
||||||
|
var attachment_to_thread_mapping map[int]int = nil
|
||||||
|
var attachment_to_filter_request_structs map[int]*filterRequestStructs = nil
|
||||||
|
var mutex sync.Mutex
|
||||||
|
var last_keep_alive time.Time
|
||||||
|
|
||||||
|
type nano_attachment C.struct_NanoAttachment
|
||||||
|
|
||||||
|
// EnvoyServerInfo represents the structure of the JSON response from /server_info
|
||||||
|
type EnvoyServerInfo struct {
|
||||||
|
Concurrency int `json:"concurrency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEnvoyConcurrency() int {
|
||||||
|
concurrency_method := getEnv("CONCURRENCY_CALC", "numOfCores")
|
||||||
|
|
||||||
|
if concurrency_method == "numOfCores" {
|
||||||
|
api.LogWarnf("using number of CPU cores")
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
var conc_number string
|
||||||
|
|
||||||
|
switch concurrency_method {
|
||||||
|
case "istioCpuLimit":
|
||||||
|
conc_number = getEnv("ISTIO_CPU_LIMIT", "-1")
|
||||||
|
api.LogWarnf("using istioCpuLimit, conc_number %s", conc_number)
|
||||||
|
case "custom":
|
||||||
|
conc_number = getEnv("CONCURRENCY_NUMBER", "-1")
|
||||||
|
api.LogWarnf("using custom concurrency number, conc_number %s", conc_number)
|
||||||
|
default:
|
||||||
|
api.LogWarnf("unknown concurrency method %s, using number of CPU cores", concurrency_method)
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
if conc_number == "-1" {
|
||||||
|
api.LogWarnf("concurrency number is not set as an env variable, using number of CPU cores")
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
conc_num, err := strconv.Atoi(conc_number)
|
||||||
|
if err != nil || conc_num <= 0 {
|
||||||
|
api.LogWarnf("error converting concurrency number %s, using number of CPU cores", conc_number)
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
return conc_num
|
||||||
|
}
|
||||||
|
|
||||||
|
func configurationServer() {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
|
||||||
|
r.Get("/load-config", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
worker_ids := make([]int, 0)
|
||||||
|
workersParam := r.URL.Query().Get("workers")
|
||||||
|
num_of_workers := len(attachments_map) // concurrency
|
||||||
|
if workersParam == "" {
|
||||||
|
for i := 0; i < num_of_workers; i++ {
|
||||||
|
worker_ids = append(worker_ids, i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
workers := strings.Split(workersParam, ",")
|
||||||
|
for _, worker := range workers {
|
||||||
|
worker_id, err := strconv.Atoi(worker)
|
||||||
|
|
||||||
|
if worker_id >= num_of_workers {
|
||||||
|
api.LogWarnf(
|
||||||
|
"Can not load configuration of invalid worker ID %d. worker ID should be lower than: %d",
|
||||||
|
worker_id,
|
||||||
|
num_of_workers)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil || worker_id >= num_of_workers {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(fmt.Sprintf(`{"error": "invalid worker ID: %s"}`, worker)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
worker_ids = append(worker_ids, worker_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workers_reload_status := make(map[string]string, len(worker_ids))
|
||||||
|
res := C.NANO_OK
|
||||||
|
for _, worker_id := range worker_ids {
|
||||||
|
worker_reload_res := C.RestartAttachmentConfiguration((*C.NanoAttachment)(attachments_map[worker_id]))
|
||||||
|
if worker_reload_res == C.NANO_ERROR {
|
||||||
|
res = C.NANO_ERROR
|
||||||
|
workers_reload_status[strconv.Itoa(worker_id)] = "Reload Configuraiton Failed"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers_reload_status[strconv.Itoa(worker_id)] = "Reload Configuraiton Succeded"
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := json.Marshal(workers_reload_status)
|
||||||
|
if err != nil {
|
||||||
|
api.LogWarnf("Error while sending reponse about reload configuration. Err: %s", err.Error())
|
||||||
|
response = []byte(`{"error": "Internal Error"}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res == C.NANO_ERROR || err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.ListenAndServe(":8119", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
last_keep_alive = time.Time{}
|
||||||
|
envoyHttp.RegisterHttpFilterFactoryAndConfigParser(Name, ConfigFactory, &parser{})
|
||||||
|
go configurationServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {}
|
||||||
|
|
||||||
|
type parser struct {}
|
||||||
|
|
||||||
|
func sendKeepAlive() {
|
||||||
|
for {
|
||||||
|
attachment_ptr := (*C.NanoAttachment)(attachments_map[0])
|
||||||
|
if attachment_ptr == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
C.SendKeepAlive(attachment_ptr)
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) initFilterStructs() *filterRequestStructs {
|
||||||
|
return &filterRequestStructs {
|
||||||
|
http_start_data: (*C.HttpRequestFilterData)(C.malloc(C.sizeof_HttpRequestFilterData)),
|
||||||
|
http_meta_data: (*C.HttpMetaData)(C.malloc(C.sizeof_HttpMetaData)),
|
||||||
|
http_headers: (*C.HttpHeaders)(C.malloc(C.sizeof_HttpHeaders)),
|
||||||
|
http_headers_data: (*C.HttpHeaderData)(C.malloc(10000 * C.sizeof_HttpHeaderData)),
|
||||||
|
http_res_headers: (*C.ResHttpHeaders)(C.malloc(C.sizeof_ResHttpHeaders)),
|
||||||
|
http_body_data: (*C.nano_str_t)(C.malloc(10000 * C.sizeof_nano_str_t)),
|
||||||
|
attachment_data: (*C.AttachmentData)(C.malloc(C.sizeof_AttachmentData)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the filter configuration. We can call the ConfigCallbackHandler to control the filter's
|
||||||
|
// behavior
|
||||||
|
func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (interface{}, error) {
|
||||||
|
conf := &config{}
|
||||||
|
|
||||||
|
if attachments_map != nil {
|
||||||
|
api.LogInfof("Waf Configuration already loaded")
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
num_of_workers := getEnvoyConcurrency()
|
||||||
|
|
||||||
|
configStruct := &xds.TypedStruct{}
|
||||||
|
if err := any.UnmarshalTo(configStruct); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments_map = make(map[int]*nano_attachment)
|
||||||
|
attachment_to_filter_request_structs = make(map[int]*filterRequestStructs)
|
||||||
|
attachment_to_thread_mapping = make(map[int]int, 0)
|
||||||
|
thread_to_attachment_mapping = make(map[int]int, 0)
|
||||||
|
api.LogInfof("Number of worker threds: %d", num_of_workers)
|
||||||
|
for worker_id := 0; worker_id < num_of_workers; worker_id++ {
|
||||||
|
|
||||||
|
attachment := C.InitNanoAttachment(C.uint8_t(0), C.int(worker_id), C.int(num_of_workers), C.int(C.fileno(C.stdout)))
|
||||||
|
for attachment == nil {
|
||||||
|
api.LogWarnf("attachment is nill going to sleep for two seconds and retry")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
attachment = C.InitNanoAttachment(C.uint8_t(0), C.int(worker_id), C.int(num_of_workers), C.int(C.fileno(C.stdout)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//mutex.Lock()
|
||||||
|
attachments_map[worker_id] = (*nano_attachment)(attachment)
|
||||||
|
attachment_to_filter_request_structs[worker_id] = p.initFilterStructs()
|
||||||
|
//mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
go func (){
|
||||||
|
sendKeepAlive()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge configuration from the inherited parent configuration
|
||||||
|
func (p *parser) Merge(parent interface{}, child interface{}) interface{} {
|
||||||
|
parentConfig := parent.(*config)
|
||||||
|
|
||||||
|
// copy one, do not update parentConfig directly.
|
||||||
|
newConfig := *parentConfig
|
||||||
|
return &newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConfigFactory(c interface{}, callbacks api.FilterCallbackHandler) api.StreamFilter {
|
||||||
|
conf, ok := c.(*config)
|
||||||
|
if !ok {
|
||||||
|
panic("unexpected config type")
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_thread_id := int(C.get_thread_id())
|
||||||
|
api.LogDebugf("worker_thread_id: %d", worker_thread_id)
|
||||||
|
if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
|
||||||
|
api.LogDebugf("need to add new thread to the map")
|
||||||
|
map_size := len(attachment_to_thread_mapping)
|
||||||
|
if map_size < len(attachments_map) {
|
||||||
|
attachment_to_thread_mapping[map_size] = worker_thread_id
|
||||||
|
thread_to_attachment_mapping[worker_thread_id] = map_size
|
||||||
|
api.LogDebugf("len(attachment_to_thread_mapping): %d", len(attachment_to_thread_mapping))
|
||||||
|
api.LogDebugf("thread_to_attachment_mapping: %v", thread_to_attachment_mapping)
|
||||||
|
api.LogDebugf("attachment_to_thread_mapping: %v", attachment_to_thread_mapping)
|
||||||
|
} else {
|
||||||
|
panic("unexpected thread id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_id := thread_to_attachment_mapping[int(worker_thread_id)]
|
||||||
|
api.LogDebugf("worker_id: %d", worker_id)
|
||||||
|
|
||||||
|
filter_id.Add(1)
|
||||||
|
session_id := filter_id.Load()
|
||||||
|
attachment_ptr := attachments_map[worker_id]
|
||||||
|
session_data := C.InitSessionData((*C.NanoAttachment)(attachment_ptr), C.SessionID(session_id))
|
||||||
|
|
||||||
|
return &filter{
|
||||||
|
callbacks: callbacks,
|
||||||
|
config: conf,
|
||||||
|
session_id: session_id,
|
||||||
|
cp_attachment: attachment_ptr,
|
||||||
|
session_data: session_data,
|
||||||
|
request_structs: attachment_to_filter_request_structs[worker_id],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {}
|
495
attachments/envoy/1.32/filter.go
Executable file
495
attachments/envoy/1.32/filter.go
Executable file
@ -0,0 +1,495 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
unsigned long get_thread_id_2() {
|
||||||
|
return (unsigned long)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
|
||||||
|
HttpHeaderData* createHttpHeaderDataArray(int size) {
|
||||||
|
return (HttpHeaderData*)malloc(size * sizeof(HttpHeaderData));
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpMetaData* createHttpMetaData() {
|
||||||
|
return (HttpMetaData*)malloc(sizeof(HttpMetaData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHeaderElement(HttpHeaderData* arr, int index, nano_str_t key, nano_str_t value) {
|
||||||
|
if (arr == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr[index].key = key;
|
||||||
|
arr[index].value = value;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertBlockPageToString(block_page C.BlockPageData) string {
|
||||||
|
block_page_size := block_page.title_prefix.len +
|
||||||
|
block_page.title.len +
|
||||||
|
block_page.body_prefix.len +
|
||||||
|
block_page.body.len +
|
||||||
|
block_page.uuid_prefix.len +
|
||||||
|
block_page.uuid.len +
|
||||||
|
block_page.uuid_suffix.len
|
||||||
|
|
||||||
|
block_page_bytes := make([]byte, block_page_size)
|
||||||
|
|
||||||
|
location := 0
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.title_prefix.data),
|
||||||
|
C.size_t(block_page.title_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.title.data),
|
||||||
|
C.size_t(block_page.title.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.body_prefix.data),
|
||||||
|
C.size_t(block_page.body_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.body.data),
|
||||||
|
C.size_t(block_page.body.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid_prefix.data),
|
||||||
|
C.size_t(block_page.uuid_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid.data),
|
||||||
|
C.size_t(block_page.uuid.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid_suffix.data),
|
||||||
|
C.size_t(block_page.uuid_suffix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
return string(block_page_bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The callbacks in the filter, like `DecodeHeaders`, can be implemented on demand.
|
||||||
|
// Because api.PassThroughStreamFilter provides a default implementation.
|
||||||
|
type filter struct {
|
||||||
|
api.PassThroughStreamFilter
|
||||||
|
|
||||||
|
callbacks api.FilterCallbackHandler
|
||||||
|
path string
|
||||||
|
config *config
|
||||||
|
session_id int64
|
||||||
|
session_data *C.HttpSessionData
|
||||||
|
cp_attachment *nano_attachment
|
||||||
|
request_structs *filterRequestStructs
|
||||||
|
body_buffer_chunk int
|
||||||
|
}
|
||||||
|
|
||||||
|
type filterRequestStructs struct {
|
||||||
|
http_start_data *C.HttpRequestFilterData
|
||||||
|
http_meta_data *C.HttpMetaData
|
||||||
|
http_headers *C.HttpHeaders
|
||||||
|
http_headers_data *C.HttpHeaderData
|
||||||
|
http_res_headers *C.ResHttpHeaders
|
||||||
|
http_body_data *C.nano_str_t
|
||||||
|
attachment_data *C.AttachmentData
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filterRequestStructs) ZeroInitialize() {
|
||||||
|
if f.http_start_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_start_data), 0, C.size_t(unsafe.Sizeof(*f.http_start_data)))
|
||||||
|
}
|
||||||
|
if f.http_meta_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_meta_data), 0, C.size_t(unsafe.Sizeof(*f.http_meta_data)))
|
||||||
|
}
|
||||||
|
if f.http_headers != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_headers), 0, C.size_t(unsafe.Sizeof(*f.http_headers)))
|
||||||
|
}
|
||||||
|
if f.http_headers_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_headers_data), 0, C.size_t(unsafe.Sizeof(*f.http_headers_data)))
|
||||||
|
}
|
||||||
|
if f.attachment_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.attachment_data), 0, C.size_t(unsafe.Sizeof(*f.attachment_data)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) isSessionFinalized() bool {
|
||||||
|
return C.IsSessionFinalized((*C.NanoAttachment)(f.cp_attachment), (*C.HttpSessionData)(f.session_data)) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendData(data unsafe.Pointer, chunkType C.HttpChunkType) C.AttachmentVerdictResponse {
|
||||||
|
|
||||||
|
attachment_data := f.request_structs.attachment_data
|
||||||
|
attachment_data.session_id = C.uint32_t(f.session_id)
|
||||||
|
attachment_data.chunk_type = chunkType // Adjust type as needed
|
||||||
|
attachment_data.session_data = f.session_data // Ensure `f.session_data` is compatible
|
||||||
|
attachment_data.data = C.DataBuffer(data) // Ensure `data` is compatible with `C.DataBuffer`
|
||||||
|
|
||||||
|
return C.SendDataNanoAttachment((*C.NanoAttachment)(f.cp_attachment), attachment_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleCustomResponse(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
||||||
|
if verdict_response.web_response_data.web_response_type == C.RESPONSE_CODE_ONLY {
|
||||||
|
response_code := C.GetResponseCode((*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
return f.sendLocalReplyInternal(int(response_code), "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verdict_response.web_response_data.web_response_type == C.CUSTOM_WEB_RESPONSE {
|
||||||
|
headers := map[string][]string{
|
||||||
|
"Content-Type": []string{"text/html"},
|
||||||
|
}
|
||||||
|
block_page_parts := C.GetBlockPage(
|
||||||
|
(*C.NanoAttachment)(f.cp_attachment),
|
||||||
|
(*C.HttpSessionData)(f.session_data),
|
||||||
|
(*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
return f.sendLocalReplyInternal(int(block_page_parts.response_code), convertBlockPageToString(block_page_parts), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect_data := C.GetRedirectPage(
|
||||||
|
(*C.NanoAttachment)(f.cp_attachment),
|
||||||
|
(*C.HttpSessionData)(f.session_data),
|
||||||
|
(*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
redirect_location := redirect_data.redirect_location
|
||||||
|
|
||||||
|
redirect_location_slice := unsafe.Slice((*byte)(unsafe.Pointer(redirect_location.data)), redirect_location.len)
|
||||||
|
headers := map[string][]string{
|
||||||
|
"Location": []string{string(redirect_location_slice)},
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.sendLocalReplyInternal(307, "", headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) finalizeRequest(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
||||||
|
if C.AttachmentVerdict(verdict_response.verdict) == C.ATTACHMENT_VERDICT_DROP {
|
||||||
|
return f.handleCustomResponse(verdict_response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleHeaders(header api.HeaderMap) {
|
||||||
|
const envoy_headers_prefix = "x-envoy"
|
||||||
|
i := 0
|
||||||
|
header.Range(func(key, value string) bool {
|
||||||
|
if i > 10000 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
api.LogInfof("inserting headers: key %s, value %s", key, value)
|
||||||
|
|
||||||
|
if strings.HasPrefix(key, envoy_headers_prefix) ||
|
||||||
|
key == "x-request-id" ||
|
||||||
|
key == ":method" ||
|
||||||
|
key == ":path" ||
|
||||||
|
key == ":scheme" ||
|
||||||
|
key == "x-forwarded-proto" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == ":authority" {
|
||||||
|
key = "Host"
|
||||||
|
}
|
||||||
|
|
||||||
|
key_nano_str := createNanoStrWithoutCopy(key)
|
||||||
|
value_nano_str := createNanoStrWithoutCopy(value)
|
||||||
|
C.setHeaderElement((*C.HttpHeaderData)(f.request_structs.http_headers_data), C.int(i), key_nano_str, value_nano_str)
|
||||||
|
i++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
http_headers := f.request_structs.http_headers
|
||||||
|
http_headers.data = f.request_structs.http_headers_data
|
||||||
|
http_headers.headers_count = C.size_t(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendBody(buffer api.BufferInstance, is_req bool) C.AttachmentVerdictResponse {
|
||||||
|
chunk_type := C.HTTP_REQUEST_BODY
|
||||||
|
if !is_req {
|
||||||
|
chunk_type = C.HTTP_RESPONSE_BODY
|
||||||
|
}
|
||||||
|
|
||||||
|
data := buffer.Bytes()
|
||||||
|
data_len := len(data)
|
||||||
|
buffer_size := 8 * 1024
|
||||||
|
|
||||||
|
num_of_buffers := ((data_len - 1) / buffer_size) + 1
|
||||||
|
|
||||||
|
// TO DO: FIX THIS ASAP
|
||||||
|
if num_of_buffers > 10000 {
|
||||||
|
num_of_buffers = 10000
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for i := 0; i < num_of_buffers; i++ {
|
||||||
|
nanoStrPtr := (*C.nano_str_t)(unsafe.Pointer(uintptr(unsafe.Pointer(f.request_structs.http_body_data)) + uintptr(i)*unsafe.Sizeof(*f.request_structs.http_body_data)))
|
||||||
|
nanoStrPtr.data = (*C.uchar)(unsafe.Pointer(&data[i * buffer_size]))
|
||||||
|
|
||||||
|
if i + 1 == num_of_buffers {
|
||||||
|
nanoStrPtr.len = C.size_t(data_len - (i * buffer_size))
|
||||||
|
} else {
|
||||||
|
nanoStrPtr.len = C.size_t(buffer_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
http_chunks_array := C.HttpBody{
|
||||||
|
data: f.request_structs.http_body_data,
|
||||||
|
bodies_count: C.size_t(num_of_buffers),
|
||||||
|
}
|
||||||
|
|
||||||
|
api.LogInfof("sending body data: %+v", http_chunks_array)
|
||||||
|
return f.sendData(unsafe.Pointer(&http_chunks_array), C.HttpChunkType(chunk_type))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendStartTransaction(start_transaction_data *C.HttpRequestFilterData) C.AttachmentVerdictResponse {
|
||||||
|
return f.sendData(unsafe.Pointer(&start_transaction_data), C.HTTP_REQUEST_FILTER)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleStartTransaction(header api.RequestHeaderMap) {
|
||||||
|
stream_info := f.callbacks.StreamInfo()
|
||||||
|
|
||||||
|
ip_location := 0
|
||||||
|
port_location := 1
|
||||||
|
|
||||||
|
listening_address := stream_info.DownstreamLocalAddress()
|
||||||
|
listening_address_arr := strings.Split(listening_address, ":")
|
||||||
|
listening_port, _ := strconv.Atoi(listening_address_arr[port_location])
|
||||||
|
|
||||||
|
client_address := stream_info.DownstreamRemoteAddress()
|
||||||
|
client_addr_arr := strings.Split(client_address, ":")
|
||||||
|
client_port, _ := strconv.Atoi(client_addr_arr[port_location])
|
||||||
|
|
||||||
|
host := strings.Split(header.Host(), ":")[0]
|
||||||
|
|
||||||
|
protocol, _ := stream_info.Protocol()
|
||||||
|
|
||||||
|
// init start transaction struct
|
||||||
|
meta_data := f.request_structs.http_meta_data
|
||||||
|
meta_data.http_protocol = createNanoStr(protocol)
|
||||||
|
meta_data.method_name = createNanoStr(header.Method())
|
||||||
|
meta_data.host = createNanoStr(host)
|
||||||
|
meta_data.listening_ip = createNanoStr(listening_address_arr[ip_location])
|
||||||
|
meta_data.listening_port = C.uint16_t(listening_port)
|
||||||
|
meta_data.uri = createNanoStr(header.Path())
|
||||||
|
meta_data.client_ip = createNanoStr(client_addr_arr[ip_location])
|
||||||
|
meta_data.client_port = C.uint16_t(client_port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendLocalReplyInternal(ret_code int, custom_response string, headers map[string][]string) api.StatusType {
|
||||||
|
f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "")
|
||||||
|
return api.LocalReply
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) endInspectionPart(chunk_type C.HttpChunkType) api.StatusType {
|
||||||
|
api.LogInfof("Ending inspection for current chunk")
|
||||||
|
res := f.sendData(nil, chunk_type)
|
||||||
|
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks which are called in request path
|
||||||
|
// The endStream is true if the request doesn't have body
|
||||||
|
func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
api.LogInfof("session has already been inspected, no need for further inspection")
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f.handleStartTransaction(header)
|
||||||
|
f.handleHeaders(header)
|
||||||
|
|
||||||
|
http_start_data := f.request_structs.http_start_data
|
||||||
|
http_start_data.meta_data = f.request_structs.http_meta_data
|
||||||
|
http_start_data.req_headers = f.request_structs.http_headers
|
||||||
|
http_start_data.contains_body = C.bool(!endStream)
|
||||||
|
|
||||||
|
res := f.sendData(unsafe.Pointer(http_start_data), C.HTTP_REQUEST_FILTER)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeData might be called multiple times during handling the request body.
|
||||||
|
// The endStream is true when handling the last piece of the body.
|
||||||
|
func (f *filter) DecodeData(buffer api.BufferInstance, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream && buffer.Len() == 0 {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_REQUEST_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
res := f.sendBody(buffer, true)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_REQUEST_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks which are called in response path
|
||||||
|
// The endStream is true if the response doesn't have body
|
||||||
|
func (f *filter) EncodeHeaders(header api.ResponseHeaderMap, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const content_length_key = "content-length"
|
||||||
|
const status_code_key = ":status"
|
||||||
|
|
||||||
|
|
||||||
|
content_length_str, _ := header.Get(content_length_key)
|
||||||
|
status_code_str, _ := header.Get(status_code_key)
|
||||||
|
content_length, _ := strconv.Atoi(content_length_str)
|
||||||
|
status_code, _ := strconv.Atoi(status_code_str)
|
||||||
|
|
||||||
|
f.handleHeaders(header)
|
||||||
|
res_http_headers := f.request_structs.http_res_headers
|
||||||
|
res_http_headers.headers = f.request_structs.http_headers
|
||||||
|
res_http_headers.content_length = C.uint64_t(content_length)
|
||||||
|
res_http_headers.response_code = C.uint16_t(status_code)
|
||||||
|
|
||||||
|
res := f.sendData(unsafe.Pointer(res_http_headers), C.HTTP_RESPONSE_HEADER)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func injectBodyChunk(
|
||||||
|
curr_modification *C.struct_NanoHttpModificationList,
|
||||||
|
body_buffer_chunk int,
|
||||||
|
buffer *api.BufferInstance) {
|
||||||
|
for curr_modification != nil {
|
||||||
|
if (int(curr_modification.modification.orig_buff_index) == body_buffer_chunk) {
|
||||||
|
mod := curr_modification.modification // type: HttpInjectData
|
||||||
|
modifications := C.GoString(curr_modification.modification_buffer)
|
||||||
|
new_buffer:= insertAtPosition((*buffer).String(), modifications, int(mod.injection_pos))
|
||||||
|
(*buffer).SetString(new_buffer)
|
||||||
|
}
|
||||||
|
curr_modification = curr_modification.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeData might be called multiple times during handling the response body.
|
||||||
|
// The endStream is true when handling the last piece of the body.
|
||||||
|
func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream && buffer.Len() == 0 {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
res := f.sendBody(buffer, false)
|
||||||
|
injectBodyChunk(res.modifications, f.body_buffer_chunk, &buffer)
|
||||||
|
f.body_buffer_chunk++
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// ____________NOT IMPLEMENTED AT THE MOMENT____________
|
||||||
|
func (f *filter) DecodeTrailers(trailers api.RequestTrailerMap) api.StatusType {
|
||||||
|
// support suspending & resuming the filter in a background goroutine
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) EncodeTrailers(trailers api.ResponseTrailerMap) api.StatusType {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnLog is called when the HTTP stream is ended on HTTP Connection Manager filter.
|
||||||
|
func (f *filter) OnLog(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {}
|
||||||
|
|
||||||
|
// OnLogDownstreamStart is called when HTTP Connection Manager filter receives a new HTTP request
|
||||||
|
// (required the corresponding access log type is enabled)
|
||||||
|
func (f *filter) OnLogDownstreamStart(api.RequestHeaderMap) {}
|
||||||
|
|
||||||
|
// OnLogDownstreamPeriodic is called on any HTTP Connection Manager periodic log record
|
||||||
|
// (required the corresponding access log type is enabled)
|
||||||
|
func (f *filter) OnLogDownstreamPeriodic(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {}
|
||||||
|
|
||||||
|
func (f *filter) OnDestroy(reason api.DestroyReason) {
|
||||||
|
freeHttpMetaDataFields(f.request_structs.http_meta_data)
|
||||||
|
f.request_structs.ZeroInitialize()
|
||||||
|
C.FiniSessionData((*C.NanoAttachment)(f.cp_attachment), f.session_data)
|
||||||
|
}
|
22
attachments/envoy/1.32/go.mod
Executable file
22
attachments/envoy/1.32/go.mod
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
module gitlab.ngen.checkpoint.com/Ngen/agent-core/attachments/envoy
|
||||||
|
|
||||||
|
// the version should >= 1.18
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
toolchain go1.22.5
|
||||||
|
|
||||||
|
// NOTICE: these lines could be generated automatically by "go mod tidy"
|
||||||
|
require (
|
||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa
|
||||||
|
github.com/envoyproxy/envoy v1.32.1
|
||||||
|
google.golang.org/protobuf v1.35.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require github.com/go-chi/chi/v5 v5.1.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||||
|
)
|
23
attachments/envoy/1.32/go.sum
Executable file
23
attachments/envoy/1.32/go.sum
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||||
|
github.com/envoyproxy/envoy v1.32.1 h1:+HeajIC+S9PH3mjY/bVqJabjprqxA7h6pSQ+Ie1Ziww=
|
||||||
|
github.com/envoyproxy/envoy v1.32.1/go.mod h1:KGS+IUehDX1mSIdqodPTWskKOo7bZMLLy3GHxvOKcJk=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||||
|
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||||
|
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
108
attachments/envoy/1.32/utils.go
Executable file
108
attachments/envoy/1.32/utils.go
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <string.h>
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
func getEnv(key, defaultValue string) string {
|
||||||
|
value, exists := os.LookupEnv(key)
|
||||||
|
if !exists {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
var INSERT_POS_ERR_MSG = "Got invalid insertion position, will not insert."
|
||||||
|
|
||||||
|
func copyToSlice(dest []byte, src unsafe.Pointer, size C.size_t, location int) int {
|
||||||
|
C.memcpy(unsafe.Pointer(&dest[location]), src, size)
|
||||||
|
return location + int(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNanoStr(data []byte) *C.nano_str_t {
|
||||||
|
nanoStr := (*C.nano_str_t)(C.malloc(C.size_t(unsafe.Sizeof(C.nano_str_t{}))))
|
||||||
|
if nanoStr == nil {
|
||||||
|
panic("failed to allocate memory for nano_str_t struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
nanoStr.len = C.size_t(len(data))
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertAtPosition(buff string, injection string, pos int) string {
|
||||||
|
if pos < 0 || pos > len(buff) {
|
||||||
|
api.LogDebugf(
|
||||||
|
INSERT_POS_ERR_MSG +
|
||||||
|
" Position: " +
|
||||||
|
strconv.Itoa(pos) +
|
||||||
|
", buffer's lenght: " +
|
||||||
|
strconv.Itoa(len(buff)))
|
||||||
|
return buff
|
||||||
|
}
|
||||||
|
return_buff := buff[:pos] + injection + buff[pos:]
|
||||||
|
return return_buff
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNanoStr(str string) C.nano_str_t {
|
||||||
|
c_str := C.CString(str)
|
||||||
|
nanoStr := C.nano_str_t{
|
||||||
|
len: C.size_t(len(str)),
|
||||||
|
data: (*C.uchar)(unsafe.Pointer(c_str)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNanoStrWithoutCopy(str string) C.nano_str_t {
|
||||||
|
nanoStr := C.nano_str_t{
|
||||||
|
len: C.size_t(len(str)),
|
||||||
|
data: (*C.uchar)(unsafe.Pointer((*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeNanoStr(str *C.nano_str_t) {
|
||||||
|
C.free(unsafe.Pointer(str.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeHttpMetaDataFields(meta_data *C.HttpMetaData) {
|
||||||
|
freeNanoStr(&(*meta_data).http_protocol)
|
||||||
|
freeNanoStr(&(*meta_data).method_name)
|
||||||
|
freeNanoStr(&(*meta_data).host)
|
||||||
|
freeNanoStr(&(*meta_data).listening_ip)
|
||||||
|
freeNanoStr(&(*meta_data).uri)
|
||||||
|
freeNanoStr(&(*meta_data).client_ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeHeaders(header_arr *C.HttpHeaderData, header_slice []C.HttpHeaderData) {
|
||||||
|
C.free(unsafe.Pointer(header_arr))
|
||||||
|
|
||||||
|
for _, header := range header_slice {
|
||||||
|
freeNanoStr(&(header.key))
|
||||||
|
freeNanoStr(&(header.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecoverPanic(ret *api.StatusType) {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
const size = 64 << 10
|
||||||
|
buf := make([]byte, size)
|
||||||
|
buf = buf[:runtime.Stack(buf, false)]
|
||||||
|
api.LogErrorf("http: panic serving: %v\n%s", e, buf)
|
||||||
|
|
||||||
|
*ret = api.Continue
|
||||||
|
}
|
||||||
|
}
|
33
attachments/envoy/1.33/CMakeLists.txt
Executable file
33
attachments/envoy/1.33/CMakeLists.txt
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND ATTACHMENT_TYPE STREQUAL "envoy")
|
||||||
|
set(ATTACHMENTS_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/core/include/attachments)
|
||||||
|
set(NANO_ATTACHMENT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/attachments/nano_attachment)
|
||||||
|
set(SHMEM_LIBRARY_DIR ${CMAKE_BINARY_DIR}/core/shmem_ipc_2)
|
||||||
|
set(NANO_ATTACHMENT_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment)
|
||||||
|
set(NANO_ATTACHMENT_UTIL_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment/nano_attachment_util)
|
||||||
|
set(LIBRARIES "-lnano_attachment -lnano_attachment_util -lshmem_ipc_2")
|
||||||
|
set(ENVOY_ATTACHMENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
get_filename_component(CURRENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
|
||||||
|
# Configure the build.sh script from the template
|
||||||
|
configure_file(
|
||||||
|
${PROJECT_SOURCE_DIR}/attachments/envoy/${CURRENT_DIR}/build_template
|
||||||
|
${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define a custom command to run the bash script
|
||||||
|
add_custom_target(
|
||||||
|
envoy_attachment${CURRENT_DIR} ALL
|
||||||
|
COMMAND chmod +x ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
COMMAND ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR}/build.sh
|
||||||
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/attachments/envoy
|
||||||
|
COMMENT "Building envoy attachment ${CURRENT_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(envoy_attachment${CURRENT_DIR} shmem_ipc_2 nano_attachment nano_attachment_util)
|
||||||
|
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION ${CMAKE_BINARY_DIR}/attachments/envoy/${CURRENT_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
install(FILES libenvoy_attachment.so DESTINATION envoy/${CURRENT_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
||||||
|
endif()
|
||||||
|
|
13
attachments/envoy/1.33/build_template
Executable file
13
attachments/envoy/1.33/build_template
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
SHMEM_LIBRARY_DIR="@SHMEM_LIBRARY_DIR@"
|
||||||
|
NANO_ATTACHMENT_LIBRARY_DIR="@NANO_ATTACHMENT_LIBRARY_DIR@"
|
||||||
|
NANO_ATTACHMENT_UTIL_LIBRARY_DIR="@NANO_ATTACHMENT_UTIL_LIBRARY_DIR@"
|
||||||
|
LIBRARIES="@LIBRARIES@"
|
||||||
|
ENVOY_ATTACHMENT_DIR="@ENVOY_ATTACHMENT_DIR@"
|
||||||
|
|
||||||
|
cd $ENVOY_ATTACHMENT_DIR
|
||||||
|
|
||||||
|
# Run the go build command
|
||||||
|
CGO_CFLAGS="-I@ATTACHMENTS_INCLUDE_DIR@ -I@NANO_ATTACHMENT_INCLUDE_DIR@" go build -o ${ENVOY_ATTACHMENT_DIR}/libenvoy_attachment.so -buildmode=c-shared -ldflags="-extldflags '-L${SHMEM_LIBRARY_DIR} -L${NANO_ATTACHMENT_LIBRARY_DIR} -L${NANO_ATTACHMENT_UTIL_LIBRARY_DIR} ${LIBRARIES}'"
|
282
attachments/envoy/1.33/config.go
Executable file
282
attachments/envoy/1.33/config.go
Executable file
@ -0,0 +1,282 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
|
||||||
|
xds "github.com/cncf/xds/go/xds/type/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
envoyHttp "github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
unsigned long get_thread_id() {
|
||||||
|
return (unsigned long)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_initializer.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
const Name = "cp_nano_filter"
|
||||||
|
const admin_api_server_info = "http://127.0.0.1:%s/server_info"
|
||||||
|
const keep_alive_interval = 10 * time.Second
|
||||||
|
|
||||||
|
var filter_id atomic.Int64
|
||||||
|
var attachments_map map[int]*nano_attachment = nil
|
||||||
|
var thread_to_attachment_mapping map[int]int = nil
|
||||||
|
var attachment_to_thread_mapping map[int]int = nil
|
||||||
|
var attachment_to_filter_request_structs map[int]*filterRequestStructs = nil
|
||||||
|
var mutex sync.Mutex
|
||||||
|
var last_keep_alive time.Time
|
||||||
|
|
||||||
|
type nano_attachment C.struct_NanoAttachment
|
||||||
|
|
||||||
|
// EnvoyServerInfo represents the structure of the JSON response from /server_info
|
||||||
|
type EnvoyServerInfo struct {
|
||||||
|
Concurrency int `json:"concurrency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEnvoyConcurrency() int {
|
||||||
|
concurrency_method := getEnv("CONCURRENCY_CALC", "numOfCores")
|
||||||
|
|
||||||
|
if concurrency_method == "numOfCores" {
|
||||||
|
api.LogWarnf("using number of CPU cores")
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
var conc_number string
|
||||||
|
|
||||||
|
switch concurrency_method {
|
||||||
|
case "istioCpuLimit":
|
||||||
|
conc_number = getEnv("ISTIO_CPU_LIMIT", "-1")
|
||||||
|
api.LogWarnf("using istioCpuLimit, conc_number %s", conc_number)
|
||||||
|
case "custom":
|
||||||
|
conc_number = getEnv("CONCURRENCY_NUMBER", "-1")
|
||||||
|
api.LogWarnf("using custom concurrency number, conc_number %s", conc_number)
|
||||||
|
default:
|
||||||
|
api.LogWarnf("unknown concurrency method %s, using number of CPU cores", concurrency_method)
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
if conc_number == "-1" {
|
||||||
|
api.LogWarnf("concurrency number is not set as an env variable, using number of CPU cores")
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
conc_num, err := strconv.Atoi(conc_number)
|
||||||
|
if err != nil || conc_num <= 0 {
|
||||||
|
api.LogWarnf("error converting concurrency number %s, using number of CPU cores", conc_number)
|
||||||
|
return runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
|
return conc_num
|
||||||
|
}
|
||||||
|
|
||||||
|
func configurationServer() {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
|
||||||
|
r.Get("/load-config", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
worker_ids := make([]int, 0)
|
||||||
|
workersParam := r.URL.Query().Get("workers")
|
||||||
|
num_of_workers := len(attachments_map) // concurrency
|
||||||
|
if workersParam == "" {
|
||||||
|
for i := 0; i < num_of_workers; i++ {
|
||||||
|
worker_ids = append(worker_ids, i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
workers := strings.Split(workersParam, ",")
|
||||||
|
for _, worker := range workers {
|
||||||
|
worker_id, err := strconv.Atoi(worker)
|
||||||
|
|
||||||
|
if worker_id >= num_of_workers {
|
||||||
|
api.LogWarnf(
|
||||||
|
"Can not load configuration of invalid worker ID %d. worker ID should be lower than: %d",
|
||||||
|
worker_id,
|
||||||
|
num_of_workers)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil || worker_id >= num_of_workers {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(fmt.Sprintf(`{"error": "invalid worker ID: %s"}`, worker)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
worker_ids = append(worker_ids, worker_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workers_reload_status := make(map[string]string, len(worker_ids))
|
||||||
|
res := C.NANO_OK
|
||||||
|
for _, worker_id := range worker_ids {
|
||||||
|
worker_reload_res := C.RestartAttachmentConfiguration((*C.NanoAttachment)(attachments_map[worker_id]))
|
||||||
|
if worker_reload_res == C.NANO_ERROR {
|
||||||
|
res = C.NANO_ERROR
|
||||||
|
workers_reload_status[strconv.Itoa(worker_id)] = "Reload Configuraiton Failed"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
workers_reload_status[strconv.Itoa(worker_id)] = "Reload Configuraiton Succeded"
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := json.Marshal(workers_reload_status)
|
||||||
|
if err != nil {
|
||||||
|
api.LogWarnf("Error while sending reponse about reload configuration. Err: %s", err.Error())
|
||||||
|
response = []byte(`{"error": "Internal Error"}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res == C.NANO_ERROR || err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.ListenAndServe(":8119", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
last_keep_alive = time.Time{}
|
||||||
|
envoyHttp.RegisterHttpFilterFactoryAndConfigParser(Name, ConfigFactory, &parser{})
|
||||||
|
go configurationServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {}
|
||||||
|
|
||||||
|
type parser struct {}
|
||||||
|
|
||||||
|
func sendKeepAlive() {
|
||||||
|
for {
|
||||||
|
attachment_ptr := (*C.NanoAttachment)(attachments_map[0])
|
||||||
|
if attachment_ptr == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
C.SendKeepAlive(attachment_ptr)
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) initFilterStructs() *filterRequestStructs {
|
||||||
|
return &filterRequestStructs {
|
||||||
|
http_start_data: (*C.HttpRequestFilterData)(C.malloc(C.sizeof_HttpRequestFilterData)),
|
||||||
|
http_meta_data: (*C.HttpMetaData)(C.malloc(C.sizeof_HttpMetaData)),
|
||||||
|
http_headers: (*C.HttpHeaders)(C.malloc(C.sizeof_HttpHeaders)),
|
||||||
|
http_headers_data: (*C.HttpHeaderData)(C.malloc(10000 * C.sizeof_HttpHeaderData)),
|
||||||
|
http_res_headers: (*C.ResHttpHeaders)(C.malloc(C.sizeof_ResHttpHeaders)),
|
||||||
|
http_body_data: (*C.nano_str_t)(C.malloc(10000 * C.sizeof_nano_str_t)),
|
||||||
|
attachment_data: (*C.AttachmentData)(C.malloc(C.sizeof_AttachmentData)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the filter configuration. We can call the ConfigCallbackHandler to control the filter's
|
||||||
|
// behavior
|
||||||
|
func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (interface{}, error) {
|
||||||
|
conf := &config{}
|
||||||
|
|
||||||
|
if attachments_map != nil {
|
||||||
|
api.LogInfof("Waf Configuration already loaded")
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
num_of_workers := getEnvoyConcurrency()
|
||||||
|
|
||||||
|
configStruct := &xds.TypedStruct{}
|
||||||
|
if err := any.UnmarshalTo(configStruct); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments_map = make(map[int]*nano_attachment)
|
||||||
|
attachment_to_filter_request_structs = make(map[int]*filterRequestStructs)
|
||||||
|
attachment_to_thread_mapping = make(map[int]int, 0)
|
||||||
|
thread_to_attachment_mapping = make(map[int]int, 0)
|
||||||
|
api.LogInfof("Number of worker threds: %d", num_of_workers)
|
||||||
|
for worker_id := 0; worker_id < num_of_workers; worker_id++ {
|
||||||
|
|
||||||
|
attachment := C.InitNanoAttachment(C.uint8_t(0), C.int(worker_id), C.int(num_of_workers), C.int(C.fileno(C.stdout)))
|
||||||
|
for attachment == nil {
|
||||||
|
api.LogWarnf("attachment is nill going to sleep for two seconds and retry")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
attachment = C.InitNanoAttachment(C.uint8_t(0), C.int(worker_id), C.int(num_of_workers), C.int(C.fileno(C.stdout)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//mutex.Lock()
|
||||||
|
attachments_map[worker_id] = (*nano_attachment)(attachment)
|
||||||
|
attachment_to_filter_request_structs[worker_id] = p.initFilterStructs()
|
||||||
|
//mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
go func (){
|
||||||
|
sendKeepAlive()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge configuration from the inherited parent configuration
|
||||||
|
func (p *parser) Merge(parent interface{}, child interface{}) interface{} {
|
||||||
|
parentConfig := parent.(*config)
|
||||||
|
|
||||||
|
// copy one, do not update parentConfig directly.
|
||||||
|
newConfig := *parentConfig
|
||||||
|
return &newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConfigFactory(c interface{}, callbacks api.FilterCallbackHandler) api.StreamFilter {
|
||||||
|
conf, ok := c.(*config)
|
||||||
|
if !ok {
|
||||||
|
panic("unexpected config type")
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_thread_id := int(C.get_thread_id())
|
||||||
|
api.LogDebugf("worker_thread_id: %d", worker_thread_id)
|
||||||
|
if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
|
||||||
|
api.LogDebugf("need to add new thread to the map")
|
||||||
|
map_size := len(attachment_to_thread_mapping)
|
||||||
|
if map_size < len(attachments_map) {
|
||||||
|
attachment_to_thread_mapping[map_size] = worker_thread_id
|
||||||
|
thread_to_attachment_mapping[worker_thread_id] = map_size
|
||||||
|
api.LogDebugf("len(attachment_to_thread_mapping): %d", len(attachment_to_thread_mapping))
|
||||||
|
api.LogDebugf("thread_to_attachment_mapping: %v", thread_to_attachment_mapping)
|
||||||
|
api.LogDebugf("attachment_to_thread_mapping: %v", attachment_to_thread_mapping)
|
||||||
|
} else {
|
||||||
|
panic("unexpected thread id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_id := thread_to_attachment_mapping[int(worker_thread_id)]
|
||||||
|
api.LogDebugf("worker_id: %d", worker_id)
|
||||||
|
|
||||||
|
filter_id.Add(1)
|
||||||
|
session_id := filter_id.Load()
|
||||||
|
attachment_ptr := attachments_map[worker_id]
|
||||||
|
session_data := C.InitSessionData((*C.NanoAttachment)(attachment_ptr), C.SessionID(session_id))
|
||||||
|
|
||||||
|
return &filter{
|
||||||
|
callbacks: callbacks,
|
||||||
|
config: conf,
|
||||||
|
session_id: session_id,
|
||||||
|
cp_attachment: attachment_ptr,
|
||||||
|
session_data: session_data,
|
||||||
|
request_structs: attachment_to_filter_request_structs[worker_id],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {}
|
495
attachments/envoy/1.33/filter.go
Executable file
495
attachments/envoy/1.33/filter.go
Executable file
@ -0,0 +1,495 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
unsigned long get_thread_id_2() {
|
||||||
|
return (unsigned long)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
|
||||||
|
HttpHeaderData* createHttpHeaderDataArray(int size) {
|
||||||
|
return (HttpHeaderData*)malloc(size * sizeof(HttpHeaderData));
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpMetaData* createHttpMetaData() {
|
||||||
|
return (HttpMetaData*)malloc(sizeof(HttpMetaData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHeaderElement(HttpHeaderData* arr, int index, nano_str_t key, nano_str_t value) {
|
||||||
|
if (arr == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr[index].key = key;
|
||||||
|
arr[index].value = value;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertBlockPageToString(block_page C.BlockPageData) string {
|
||||||
|
block_page_size := block_page.title_prefix.len +
|
||||||
|
block_page.title.len +
|
||||||
|
block_page.body_prefix.len +
|
||||||
|
block_page.body.len +
|
||||||
|
block_page.uuid_prefix.len +
|
||||||
|
block_page.uuid.len +
|
||||||
|
block_page.uuid_suffix.len
|
||||||
|
|
||||||
|
block_page_bytes := make([]byte, block_page_size)
|
||||||
|
|
||||||
|
location := 0
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.title_prefix.data),
|
||||||
|
C.size_t(block_page.title_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.title.data),
|
||||||
|
C.size_t(block_page.title.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.body_prefix.data),
|
||||||
|
C.size_t(block_page.body_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.body.data),
|
||||||
|
C.size_t(block_page.body.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid_prefix.data),
|
||||||
|
C.size_t(block_page.uuid_prefix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
location = copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid.data),
|
||||||
|
C.size_t(block_page.uuid.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
copyToSlice(
|
||||||
|
block_page_bytes,
|
||||||
|
unsafe.Pointer(block_page.uuid_suffix.data),
|
||||||
|
C.size_t(block_page.uuid_suffix.len),
|
||||||
|
location)
|
||||||
|
|
||||||
|
return string(block_page_bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The callbacks in the filter, like `DecodeHeaders`, can be implemented on demand.
|
||||||
|
// Because api.PassThroughStreamFilter provides a default implementation.
|
||||||
|
type filter struct {
|
||||||
|
api.PassThroughStreamFilter
|
||||||
|
|
||||||
|
callbacks api.FilterCallbackHandler
|
||||||
|
path string
|
||||||
|
config *config
|
||||||
|
session_id int64
|
||||||
|
session_data *C.HttpSessionData
|
||||||
|
cp_attachment *nano_attachment
|
||||||
|
request_structs *filterRequestStructs
|
||||||
|
body_buffer_chunk int
|
||||||
|
}
|
||||||
|
|
||||||
|
type filterRequestStructs struct {
|
||||||
|
http_start_data *C.HttpRequestFilterData
|
||||||
|
http_meta_data *C.HttpMetaData
|
||||||
|
http_headers *C.HttpHeaders
|
||||||
|
http_headers_data *C.HttpHeaderData
|
||||||
|
http_res_headers *C.ResHttpHeaders
|
||||||
|
http_body_data *C.nano_str_t
|
||||||
|
attachment_data *C.AttachmentData
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filterRequestStructs) ZeroInitialize() {
|
||||||
|
if f.http_start_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_start_data), 0, C.size_t(unsafe.Sizeof(*f.http_start_data)))
|
||||||
|
}
|
||||||
|
if f.http_meta_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_meta_data), 0, C.size_t(unsafe.Sizeof(*f.http_meta_data)))
|
||||||
|
}
|
||||||
|
if f.http_headers != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_headers), 0, C.size_t(unsafe.Sizeof(*f.http_headers)))
|
||||||
|
}
|
||||||
|
if f.http_headers_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.http_headers_data), 0, C.size_t(unsafe.Sizeof(*f.http_headers_data)))
|
||||||
|
}
|
||||||
|
if f.attachment_data != nil {
|
||||||
|
C.memset(unsafe.Pointer(f.attachment_data), 0, C.size_t(unsafe.Sizeof(*f.attachment_data)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) isSessionFinalized() bool {
|
||||||
|
return C.IsSessionFinalized((*C.NanoAttachment)(f.cp_attachment), (*C.HttpSessionData)(f.session_data)) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendData(data unsafe.Pointer, chunkType C.HttpChunkType) C.AttachmentVerdictResponse {
|
||||||
|
|
||||||
|
attachment_data := f.request_structs.attachment_data
|
||||||
|
attachment_data.session_id = C.uint32_t(f.session_id)
|
||||||
|
attachment_data.chunk_type = chunkType // Adjust type as needed
|
||||||
|
attachment_data.session_data = f.session_data // Ensure `f.session_data` is compatible
|
||||||
|
attachment_data.data = C.DataBuffer(data) // Ensure `data` is compatible with `C.DataBuffer`
|
||||||
|
|
||||||
|
return C.SendDataNanoAttachment((*C.NanoAttachment)(f.cp_attachment), attachment_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleCustomResponse(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
||||||
|
if verdict_response.web_response_data.web_response_type == C.RESPONSE_CODE_ONLY {
|
||||||
|
response_code := C.GetResponseCode((*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
return f.sendLocalReplyInternal(int(response_code), "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verdict_response.web_response_data.web_response_type == C.CUSTOM_WEB_RESPONSE {
|
||||||
|
headers := map[string][]string{
|
||||||
|
"Content-Type": []string{"text/html"},
|
||||||
|
}
|
||||||
|
block_page_parts := C.GetBlockPage(
|
||||||
|
(*C.NanoAttachment)(f.cp_attachment),
|
||||||
|
(*C.HttpSessionData)(f.session_data),
|
||||||
|
(*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
return f.sendLocalReplyInternal(int(block_page_parts.response_code), convertBlockPageToString(block_page_parts), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect_data := C.GetRedirectPage(
|
||||||
|
(*C.NanoAttachment)(f.cp_attachment),
|
||||||
|
(*C.HttpSessionData)(f.session_data),
|
||||||
|
(*C.AttachmentVerdictResponse)(verdict_response))
|
||||||
|
redirect_location := redirect_data.redirect_location
|
||||||
|
|
||||||
|
redirect_location_slice := unsafe.Slice((*byte)(unsafe.Pointer(redirect_location.data)), redirect_location.len)
|
||||||
|
headers := map[string][]string{
|
||||||
|
"Location": []string{string(redirect_location_slice)},
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.sendLocalReplyInternal(307, "", headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) finalizeRequest(verdict_response *C.AttachmentVerdictResponse) api.StatusType {
|
||||||
|
if C.AttachmentVerdict(verdict_response.verdict) == C.ATTACHMENT_VERDICT_DROP {
|
||||||
|
return f.handleCustomResponse(verdict_response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleHeaders(header api.HeaderMap) {
|
||||||
|
const envoy_headers_prefix = "x-envoy"
|
||||||
|
i := 0
|
||||||
|
header.Range(func(key, value string) bool {
|
||||||
|
if i > 10000 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
api.LogInfof("inserting headers: key %s, value %s", key, value)
|
||||||
|
|
||||||
|
if strings.HasPrefix(key, envoy_headers_prefix) ||
|
||||||
|
key == "x-request-id" ||
|
||||||
|
key == ":method" ||
|
||||||
|
key == ":path" ||
|
||||||
|
key == ":scheme" ||
|
||||||
|
key == "x-forwarded-proto" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == ":authority" {
|
||||||
|
key = "Host"
|
||||||
|
}
|
||||||
|
|
||||||
|
key_nano_str := createNanoStrWithoutCopy(key)
|
||||||
|
value_nano_str := createNanoStrWithoutCopy(value)
|
||||||
|
C.setHeaderElement((*C.HttpHeaderData)(f.request_structs.http_headers_data), C.int(i), key_nano_str, value_nano_str)
|
||||||
|
i++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
http_headers := f.request_structs.http_headers
|
||||||
|
http_headers.data = f.request_structs.http_headers_data
|
||||||
|
http_headers.headers_count = C.size_t(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendBody(buffer api.BufferInstance, is_req bool) C.AttachmentVerdictResponse {
|
||||||
|
chunk_type := C.HTTP_REQUEST_BODY
|
||||||
|
if !is_req {
|
||||||
|
chunk_type = C.HTTP_RESPONSE_BODY
|
||||||
|
}
|
||||||
|
|
||||||
|
data := buffer.Bytes()
|
||||||
|
data_len := len(data)
|
||||||
|
buffer_size := 8 * 1024
|
||||||
|
|
||||||
|
num_of_buffers := ((data_len - 1) / buffer_size) + 1
|
||||||
|
|
||||||
|
// TO DO: FIX THIS ASAP
|
||||||
|
if num_of_buffers > 10000 {
|
||||||
|
num_of_buffers = 10000
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for i := 0; i < num_of_buffers; i++ {
|
||||||
|
nanoStrPtr := (*C.nano_str_t)(unsafe.Pointer(uintptr(unsafe.Pointer(f.request_structs.http_body_data)) + uintptr(i)*unsafe.Sizeof(*f.request_structs.http_body_data)))
|
||||||
|
nanoStrPtr.data = (*C.uchar)(unsafe.Pointer(&data[i * buffer_size]))
|
||||||
|
|
||||||
|
if i + 1 == num_of_buffers {
|
||||||
|
nanoStrPtr.len = C.size_t(data_len - (i * buffer_size))
|
||||||
|
} else {
|
||||||
|
nanoStrPtr.len = C.size_t(buffer_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
http_chunks_array := C.HttpBody{
|
||||||
|
data: f.request_structs.http_body_data,
|
||||||
|
bodies_count: C.size_t(num_of_buffers),
|
||||||
|
}
|
||||||
|
|
||||||
|
api.LogInfof("sending body data: %+v", http_chunks_array)
|
||||||
|
return f.sendData(unsafe.Pointer(&http_chunks_array), C.HttpChunkType(chunk_type))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendStartTransaction(start_transaction_data *C.HttpRequestFilterData) C.AttachmentVerdictResponse {
|
||||||
|
return f.sendData(unsafe.Pointer(&start_transaction_data), C.HTTP_REQUEST_FILTER)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) handleStartTransaction(header api.RequestHeaderMap) {
|
||||||
|
stream_info := f.callbacks.StreamInfo()
|
||||||
|
|
||||||
|
ip_location := 0
|
||||||
|
port_location := 1
|
||||||
|
|
||||||
|
listening_address := stream_info.DownstreamLocalAddress()
|
||||||
|
listening_address_arr := strings.Split(listening_address, ":")
|
||||||
|
listening_port, _ := strconv.Atoi(listening_address_arr[port_location])
|
||||||
|
|
||||||
|
client_address := stream_info.DownstreamRemoteAddress()
|
||||||
|
client_addr_arr := strings.Split(client_address, ":")
|
||||||
|
client_port, _ := strconv.Atoi(client_addr_arr[port_location])
|
||||||
|
|
||||||
|
host := strings.Split(header.Host(), ":")[0]
|
||||||
|
|
||||||
|
protocol, _ := stream_info.Protocol()
|
||||||
|
|
||||||
|
// init start transaction struct
|
||||||
|
meta_data := f.request_structs.http_meta_data
|
||||||
|
meta_data.http_protocol = createNanoStr(protocol)
|
||||||
|
meta_data.method_name = createNanoStr(header.Method())
|
||||||
|
meta_data.host = createNanoStr(host)
|
||||||
|
meta_data.listening_ip = createNanoStr(listening_address_arr[ip_location])
|
||||||
|
meta_data.listening_port = C.uint16_t(listening_port)
|
||||||
|
meta_data.uri = createNanoStr(header.Path())
|
||||||
|
meta_data.client_ip = createNanoStr(client_addr_arr[ip_location])
|
||||||
|
meta_data.client_port = C.uint16_t(client_port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) sendLocalReplyInternal(ret_code int, custom_response string, headers map[string][]string) api.StatusType {
|
||||||
|
f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "")
|
||||||
|
return api.LocalReply
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) endInspectionPart(chunk_type C.HttpChunkType) api.StatusType {
|
||||||
|
api.LogInfof("Ending inspection for current chunk")
|
||||||
|
res := f.sendData(nil, chunk_type)
|
||||||
|
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks which are called in request path
|
||||||
|
// The endStream is true if the request doesn't have body
|
||||||
|
func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
api.LogInfof("session has already been inspected, no need for further inspection")
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f.handleStartTransaction(header)
|
||||||
|
f.handleHeaders(header)
|
||||||
|
|
||||||
|
http_start_data := f.request_structs.http_start_data
|
||||||
|
http_start_data.meta_data = f.request_structs.http_meta_data
|
||||||
|
http_start_data.req_headers = f.request_structs.http_headers
|
||||||
|
http_start_data.contains_body = C.bool(!endStream)
|
||||||
|
|
||||||
|
res := f.sendData(unsafe.Pointer(http_start_data), C.HTTP_REQUEST_FILTER)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeData might be called multiple times during handling the request body.
|
||||||
|
// The endStream is true when handling the last piece of the body.
|
||||||
|
func (f *filter) DecodeData(buffer api.BufferInstance, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream && buffer.Len() == 0 {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_REQUEST_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
res := f.sendBody(buffer, true)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_REQUEST_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks which are called in response path
|
||||||
|
// The endStream is true if the response doesn't have body
|
||||||
|
func (f *filter) EncodeHeaders(header api.ResponseHeaderMap, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const content_length_key = "content-length"
|
||||||
|
const status_code_key = ":status"
|
||||||
|
|
||||||
|
|
||||||
|
content_length_str, _ := header.Get(content_length_key)
|
||||||
|
status_code_str, _ := header.Get(status_code_key)
|
||||||
|
content_length, _ := strconv.Atoi(content_length_str)
|
||||||
|
status_code, _ := strconv.Atoi(status_code_str)
|
||||||
|
|
||||||
|
f.handleHeaders(header)
|
||||||
|
res_http_headers := f.request_structs.http_res_headers
|
||||||
|
res_http_headers.headers = f.request_structs.http_headers
|
||||||
|
res_http_headers.content_length = C.uint64_t(content_length)
|
||||||
|
res_http_headers.response_code = C.uint16_t(status_code)
|
||||||
|
|
||||||
|
res := f.sendData(unsafe.Pointer(res_http_headers), C.HTTP_RESPONSE_HEADER)
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func injectBodyChunk(
|
||||||
|
curr_modification *C.struct_NanoHttpModificationList,
|
||||||
|
body_buffer_chunk int,
|
||||||
|
buffer *api.BufferInstance) {
|
||||||
|
for curr_modification != nil {
|
||||||
|
if (int(curr_modification.modification.orig_buff_index) == body_buffer_chunk) {
|
||||||
|
mod := curr_modification.modification // type: HttpInjectData
|
||||||
|
modifications := C.GoString(curr_modification.modification_buffer)
|
||||||
|
new_buffer:= insertAtPosition((*buffer).String(), modifications, int(mod.injection_pos))
|
||||||
|
(*buffer).SetString(new_buffer)
|
||||||
|
}
|
||||||
|
curr_modification = curr_modification.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeData might be called multiple times during handling the response body.
|
||||||
|
// The endStream is true when handling the last piece of the body.
|
||||||
|
func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.StatusType {
|
||||||
|
ret := api.Continue
|
||||||
|
|
||||||
|
defer RecoverPanic(&ret)
|
||||||
|
|
||||||
|
if f.isSessionFinalized() {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream && buffer.Len() == 0 {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
res := f.sendBody(buffer, false)
|
||||||
|
injectBodyChunk(res.modifications, f.body_buffer_chunk, &buffer)
|
||||||
|
f.body_buffer_chunk++
|
||||||
|
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||||
|
api.LogInfof("got final verict: %v", res.verdict)
|
||||||
|
return f.finalizeRequest(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endStream {
|
||||||
|
return f.endInspectionPart(C.HttpChunkType(C.HTTP_RESPONSE_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// ____________NOT IMPLEMENTED AT THE MOMENT____________
|
||||||
|
func (f *filter) DecodeTrailers(trailers api.RequestTrailerMap) api.StatusType {
|
||||||
|
// support suspending & resuming the filter in a background goroutine
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filter) EncodeTrailers(trailers api.ResponseTrailerMap) api.StatusType {
|
||||||
|
return api.Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnLog is called when the HTTP stream is ended on HTTP Connection Manager filter.
|
||||||
|
func (f *filter) OnLog(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {}
|
||||||
|
|
||||||
|
// OnLogDownstreamStart is called when HTTP Connection Manager filter receives a new HTTP request
|
||||||
|
// (required the corresponding access log type is enabled)
|
||||||
|
func (f *filter) OnLogDownstreamStart(api.RequestHeaderMap) {}
|
||||||
|
|
||||||
|
// OnLogDownstreamPeriodic is called on any HTTP Connection Manager periodic log record
|
||||||
|
// (required the corresponding access log type is enabled)
|
||||||
|
func (f *filter) OnLogDownstreamPeriodic(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {}
|
||||||
|
|
||||||
|
func (f *filter) OnDestroy(reason api.DestroyReason) {
|
||||||
|
freeHttpMetaDataFields(f.request_structs.http_meta_data)
|
||||||
|
f.request_structs.ZeroInitialize()
|
||||||
|
C.FiniSessionData((*C.NanoAttachment)(f.cp_attachment), f.session_data)
|
||||||
|
}
|
22
attachments/envoy/1.33/go.mod
Executable file
22
attachments/envoy/1.33/go.mod
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
module gitlab.ngen.checkpoint.com/Ngen/agent-core/attachments/envoy
|
||||||
|
|
||||||
|
// the version should >= 1.18
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
toolchain go1.22.5
|
||||||
|
|
||||||
|
// NOTICE: these lines could be generated automatically by "go mod tidy"
|
||||||
|
require (
|
||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa
|
||||||
|
github.com/envoyproxy/envoy v1.33.0
|
||||||
|
google.golang.org/protobuf v1.36.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require github.com/go-chi/chi/v5 v5.1.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||||
|
)
|
23
attachments/envoy/1.33/go.sum
Executable file
23
attachments/envoy/1.33/go.sum
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||||
|
github.com/envoyproxy/envoy v1.33.0 h1:6YYKae/owrJ29psB4ELUpXTtbjaiNSKOX36yZ4ROU2Y=
|
||||||
|
github.com/envoyproxy/envoy v1.33.0/go.mod h1:faFqv1XeNGX/ph6Zto5Culdcpk4Klxp730Q6XhWarV4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||||
|
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||||
|
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||||
|
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
108
attachments/envoy/1.33/utils.go
Executable file
108
attachments/envoy/1.33/utils.go
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <string.h>
|
||||||
|
#include "nano_attachment_common.h"
|
||||||
|
#include "nano_attachment.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
|
||||||
|
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
func getEnv(key, defaultValue string) string {
|
||||||
|
value, exists := os.LookupEnv(key)
|
||||||
|
if !exists {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
var INSERT_POS_ERR_MSG = "Got invalid insertion position, will not insert."
|
||||||
|
|
||||||
|
func copyToSlice(dest []byte, src unsafe.Pointer, size C.size_t, location int) int {
|
||||||
|
C.memcpy(unsafe.Pointer(&dest[location]), src, size)
|
||||||
|
return location + int(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNanoStr(data []byte) *C.nano_str_t {
|
||||||
|
nanoStr := (*C.nano_str_t)(C.malloc(C.size_t(unsafe.Sizeof(C.nano_str_t{}))))
|
||||||
|
if nanoStr == nil {
|
||||||
|
panic("failed to allocate memory for nano_str_t struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
nanoStr.len = C.size_t(len(data))
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertAtPosition(buff string, injection string, pos int) string {
|
||||||
|
if pos < 0 || pos > len(buff) {
|
||||||
|
api.LogDebugf(
|
||||||
|
INSERT_POS_ERR_MSG +
|
||||||
|
" Position: " +
|
||||||
|
strconv.Itoa(pos) +
|
||||||
|
", buffer's lenght: " +
|
||||||
|
strconv.Itoa(len(buff)))
|
||||||
|
return buff
|
||||||
|
}
|
||||||
|
return_buff := buff[:pos] + injection + buff[pos:]
|
||||||
|
return return_buff
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNanoStr(str string) C.nano_str_t {
|
||||||
|
c_str := C.CString(str)
|
||||||
|
nanoStr := C.nano_str_t{
|
||||||
|
len: C.size_t(len(str)),
|
||||||
|
data: (*C.uchar)(unsafe.Pointer(c_str)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNanoStrWithoutCopy(str string) C.nano_str_t {
|
||||||
|
nanoStr := C.nano_str_t{
|
||||||
|
len: C.size_t(len(str)),
|
||||||
|
data: (*C.uchar)(unsafe.Pointer((*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return nanoStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeNanoStr(str *C.nano_str_t) {
|
||||||
|
C.free(unsafe.Pointer(str.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeHttpMetaDataFields(meta_data *C.HttpMetaData) {
|
||||||
|
freeNanoStr(&(*meta_data).http_protocol)
|
||||||
|
freeNanoStr(&(*meta_data).method_name)
|
||||||
|
freeNanoStr(&(*meta_data).host)
|
||||||
|
freeNanoStr(&(*meta_data).listening_ip)
|
||||||
|
freeNanoStr(&(*meta_data).uri)
|
||||||
|
freeNanoStr(&(*meta_data).client_ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func freeHeaders(header_arr *C.HttpHeaderData, header_slice []C.HttpHeaderData) {
|
||||||
|
C.free(unsafe.Pointer(header_arr))
|
||||||
|
|
||||||
|
for _, header := range header_slice {
|
||||||
|
freeNanoStr(&(header.key))
|
||||||
|
freeNanoStr(&(header.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecoverPanic(ret *api.StatusType) {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
const size = 64 << 10
|
||||||
|
buf := make([]byte, size)
|
||||||
|
buf = buf[:runtime.Stack(buf, false)]
|
||||||
|
api.LogErrorf("http: panic serving: %v\n%s", e, buf)
|
||||||
|
|
||||||
|
*ret = api.Continue
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +1,3 @@
|
|||||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND ATTACHMENT_TYPE STREQUAL "envoy")
|
add_subdirectory(1.31)
|
||||||
set(ATTACHMENTS_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/core/include/attachments)
|
add_subdirectory(1.32)
|
||||||
set(NANO_ATTACHMENT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/attachments/nano_attachment)
|
add_subdirectory(1.33)
|
||||||
set(SHMEM_LIBRARY_DIR ${CMAKE_BINARY_DIR}/core/shmem_ipc_2)
|
|
||||||
set(NANO_ATTACHMENT_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment)
|
|
||||||
set(NANO_ATTACHMENT_UTIL_LIBRARY_DIR ${CMAKE_BINARY_DIR}/attachments/nano_attachment/nano_attachment_util)
|
|
||||||
set(LIBRARIES "-lnano_attachment -lnano_attachment_util -lshmem_ipc_2")
|
|
||||||
set(ENVOY_ATTACHMENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
|
|
||||||
# Configure the build.sh script from the template
|
|
||||||
configure_file(
|
|
||||||
${PROJECT_SOURCE_DIR}/attachments/envoy/build_template
|
|
||||||
${CMAKE_BINARY_DIR}/attachments/envoy/build.sh
|
|
||||||
@ONLY
|
|
||||||
)
|
|
||||||
|
|
||||||
# Define a custom command to run the bash script
|
|
||||||
add_custom_target(
|
|
||||||
envoy_attachment ALL
|
|
||||||
COMMAND chmod +x ${CMAKE_BINARY_DIR}/attachments/envoy/build.sh
|
|
||||||
COMMAND ${CMAKE_BINARY_DIR}/attachments/envoy/build.sh
|
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/attachments/envoy
|
|
||||||
COMMENT "Building envoy attachment"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_dependencies(envoy_attachment shmem_ipc_2 nano_attachment nano_attachment_util)
|
|
||||||
|
|
||||||
install(FILES libenvoy_attachment.so DESTINATION ${CMAKE_BINARY_DIR}/attachments/envoy PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
|
||||||
install(FILES libenvoy_attachment.so DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)
|
|
||||||
endif()
|
|
||||||
|
|
8
attachments/nano_attachment/nano_attachment.c
Normal file → Executable file
8
attachments/nano_attachment/nano_attachment.c
Normal file → Executable file
@ -502,6 +502,14 @@ GetBlockPage(NanoAttachment *attachment, HttpSessionData *session_data, Attachme
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
GetResponseCode(AttachmentVerdictResponse *response)
|
||||||
|
{
|
||||||
|
WebResponseData *web_response_data = response->web_response_data;
|
||||||
|
CustomResponseData *custom_response_data;
|
||||||
|
custom_response_data = (CustomResponseData *) web_response_data->data;
|
||||||
|
return custom_response_data->response_code;
|
||||||
|
}
|
||||||
|
|
||||||
RedirectPageData
|
RedirectPageData
|
||||||
GetRedirectPage(NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response)
|
GetRedirectPage(NanoAttachment *attachment, HttpSessionData *session_data, AttachmentVerdictResponse *response)
|
||||||
|
8
attachments/nano_attachment/nano_attachment_io.c
Normal file → Executable file
8
attachments/nano_attachment/nano_attachment_io.c
Normal file → Executable file
@ -604,6 +604,14 @@ handle_custom_web_response(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (title.len == 0 || body.len == 0) {
|
||||||
|
custom_response_data->response_code = web_response_data->response_data.custom_response_data.response_code;
|
||||||
|
new_response_data->web_response_type = RESPONSE_CODE_ONLY;
|
||||||
|
new_response_data->data = custom_response_data;
|
||||||
|
*ctx_response_data = new_response_data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Setting custom web response title's data.
|
// Setting custom web response title's data.
|
||||||
if (title.len > 0) {
|
if (title.len > 0) {
|
||||||
title.data = (u_char *)web_response_data->response_data.custom_response_data.data;
|
title.data = (u_char *)web_response_data->response_data.custom_response_data.data;
|
||||||
|
@ -183,6 +183,17 @@ BlockPageData GetBlockPage(
|
|||||||
AttachmentVerdictResponse *response
|
AttachmentVerdictResponse *response
|
||||||
);
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Retrieves the response code for a response.
|
||||||
|
///
|
||||||
|
/// @param response The AttachmentVerdictResponse object containing the verdict.
|
||||||
|
///
|
||||||
|
/// @return
|
||||||
|
///
|
||||||
|
uint16_t GetResponseCode(
|
||||||
|
AttachmentVerdictResponse *response
|
||||||
|
);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Retrieves the redict page data for a response.
|
/// @brief Retrieves the redict page data for a response.
|
||||||
///
|
///
|
||||||
|
1
core/include/attachments/nano_attachment_common.h
Normal file → Executable file
1
core/include/attachments/nano_attachment_common.h
Normal file → Executable file
@ -40,6 +40,7 @@ typedef enum NanoWebResponseType
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
CUSTOM_WEB_RESPONSE,
|
CUSTOM_WEB_RESPONSE,
|
||||||
|
RESPONSE_CODE_ONLY,
|
||||||
REDIRECT_WEB_RESPONSE,
|
REDIRECT_WEB_RESPONSE,
|
||||||
|
|
||||||
NO_WEB_RESPONSE
|
NO_WEB_RESPONSE
|
||||||
|
@ -6,3 +6,6 @@ add_custom_command(
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_custom_target(docker DEPENDS ${CMAKE_INSTALL_PREFIX}/nginx-docker.img)
|
add_custom_target(docker DEPENDS ${CMAKE_INSTALL_PREFIX}/nginx-docker.img)
|
||||||
|
|
||||||
|
add_subdirectory(openappsec-envoy-attachments)
|
||||||
|
add_subdirectory(openappsec-waf-webhook)
|
||||||
|
10
docker/openappsec-envoy-attachments/CMakeLists.txt
Executable file
10
docker/openappsec-envoy-attachments/CMakeLists.txt
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
message(STATUS "OUTPUT_ENVOY_FILTERS_DOCKER_IMAGE = ${OUTPUT_ENVOY_FILTERS_DOCKER_IMAGE}")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_INSTALL_PREFIX}/envoy-filters-docker.img
|
||||||
|
COMMAND docker build -t envoy-filters-docker -f ${CMAKE_CURRENT_SOURCE_DIR}/Dockerfile ${CMAKE_INSTALL_PREFIX}
|
||||||
|
COMMAND docker tag envoy-filters-docker ${OUTPUT_ENVOY_FILTERS_DOCKER_IMAGE}
|
||||||
|
COMMAND docker image save envoy-filters-docker -o ${CMAKE_INSTALL_PREFIX}/envoy-filters-docker.img
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(envoy-filters-docker DEPENDS ${CMAKE_INSTALL_PREFIX}/envoy-filters-docker.img)
|
9
docker/openappsec-envoy-attachments/Dockerfile
Executable file
9
docker/openappsec-envoy-attachments/Dockerfile
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
RUN apk add --no-cache bash
|
||||||
|
|
||||||
|
COPY envoy /envoy/attachment/versions
|
||||||
|
COPY lib/libnano_attachment.so /envoy/attachment/libnano_attachment.so
|
||||||
|
COPY lib/libshmem_ipc_2.so /envoy/attachment/libshmem_ipc_2.so
|
||||||
|
COPY lib/libnano_attachment_util.so /envoy/attachment/libnano_attachment_util.so
|
||||||
|
COPY lib/libosrc_compression_utils.so /envoy/attachment/libosrc_compression_utils.so
|
9
docker/openappsec-waf-webhook/CMakeLists.txt
Executable file
9
docker/openappsec-waf-webhook/CMakeLists.txt
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
message(STATUS "OUTPUT_ENVOY_FILTERS_DOCKER_IMAGE = ${OUTPUT_ENVOY_FILTERS_DOCKER_IMAGE}")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_INSTALL_PREFIX}/waf-webhook-docker.img
|
||||||
|
COMMAND docker build -t waf-webhook-docker -f ${CMAKE_CURRENT_SOURCE_DIR}/Dockerfile ${CMAKE_INSTALL_PREFIX}
|
||||||
|
COMMAND docker tag waf-webhook-docker ${OUTPUT_WEBHOOK_DOCKER_IMAGE}
|
||||||
|
COMMAND docker image save waf-webhook-docker -o ${CMAKE_INSTALL_PREFIX}/waf-webhook-docker.img
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(waf-webhook-docker DEPENDS ${CMAKE_INSTALL_PREFIX}/waf-webhook-docker.img)
|
@ -4,6 +4,8 @@ import logging
|
|||||||
import base64
|
import base64
|
||||||
import secretgen
|
import secretgen
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
from kubernetes import client, config
|
from kubernetes import client, config
|
||||||
from flask import Flask, request, jsonify, Response
|
from flask import Flask, request, jsonify, Response
|
||||||
|
|
||||||
@ -12,7 +14,12 @@ app = Flask(__name__)
|
|||||||
# Read agent image and tag from environment variables
|
# Read agent image and tag from environment variables
|
||||||
AGENT_IMAGE = os.getenv('AGENT_IMAGE', 'ghcr.io/openappsec/agent')
|
AGENT_IMAGE = os.getenv('AGENT_IMAGE', 'ghcr.io/openappsec/agent')
|
||||||
AGENT_TAG = os.getenv('AGENT_TAG', 'latest')
|
AGENT_TAG = os.getenv('AGENT_TAG', 'latest')
|
||||||
|
AGENT_CPU = os.getenv('AGENT_CPU', '200m')
|
||||||
|
INIT_CONTAINER_IMAGE = os.getenv('INIT_CONTAINER_IMAGE', 'ghcr.io/openappsec/openappsec-envoy-filters')
|
||||||
|
INIT_CONTAINER_TAG = os.getenv('INIT_CONTAINER_TAG', 'latest')
|
||||||
|
ISTIOD_PORT = os.getenv('ISTIOD_PORT', '15014')
|
||||||
FULL_AGENT_IMAGE = f"{AGENT_IMAGE}:{AGENT_TAG}"
|
FULL_AGENT_IMAGE = f"{AGENT_IMAGE}:{AGENT_TAG}"
|
||||||
|
FULL_INIT_CONTAINER_IMAGE = f"{INIT_CONTAINER_IMAGE}:{INIT_CONTAINER_TAG}"
|
||||||
|
|
||||||
config.load_incluster_config()
|
config.load_incluster_config()
|
||||||
|
|
||||||
@ -64,8 +71,8 @@ def get_sidecar_container():
|
|||||||
|
|
||||||
if persistence_enabled:
|
if persistence_enabled:
|
||||||
volume_mounts.extend([
|
volume_mounts.extend([
|
||||||
{"name": "appsec-conf", "mountPath": "/etc/cp/conf"},
|
{"name": "open-appsec-conf", "mountPath": "/etc/cp/conf"},
|
||||||
{"name": "appsec-data", "mountPath": "/etc/cp/data"}
|
{"name": "open-appsec-data", "mountPath": "/etc/cp/data"}
|
||||||
])
|
])
|
||||||
|
|
||||||
args = []
|
args = []
|
||||||
@ -103,7 +110,7 @@ def get_sidecar_container():
|
|||||||
env.append({"name": var_name, "value": var_value})
|
env.append({"name": var_name, "value": var_value})
|
||||||
|
|
||||||
sidecar = {
|
sidecar = {
|
||||||
"name": "infinity-next-nano-agent",
|
"name": "open-appsec-nano-agent",
|
||||||
"image": FULL_AGENT_IMAGE,
|
"image": FULL_AGENT_IMAGE,
|
||||||
"imagePullPolicy": "Always",
|
"imagePullPolicy": "Always",
|
||||||
"command": ["/cp-nano-agent"],
|
"command": ["/cp-nano-agent"],
|
||||||
@ -112,7 +119,7 @@ def get_sidecar_container():
|
|||||||
"volumeMounts": volume_mounts,
|
"volumeMounts": volume_mounts,
|
||||||
"resources": {
|
"resources": {
|
||||||
"requests": {
|
"requests": {
|
||||||
"cpu": "200m"
|
"cpu": AGENT_CPU
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"envFrom": [
|
"envFrom": [
|
||||||
@ -138,15 +145,58 @@ def get_sidecar_container():
|
|||||||
app.logger.debug("Exiting get_sidecar_container()")
|
app.logger.debug("Exiting get_sidecar_container()")
|
||||||
return sidecar
|
return sidecar
|
||||||
|
|
||||||
|
def get_istio_version():
|
||||||
|
url = f"http://istiod.istio-system:{ISTIOD_PORT}/version"
|
||||||
|
response = requests.get(url)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.text.strip().split('-')[0] # Extracting version
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to get Istio version: {response.status_code}")
|
||||||
|
|
||||||
|
def get_envoy_sha(istio_version):
|
||||||
|
url = f"https://raw.githubusercontent.com/istio/proxy/{istio_version}/WORKSPACE"
|
||||||
|
response = requests.get(url)
|
||||||
|
if response.status_code == 200:
|
||||||
|
match = re.search(r'ENVOY_SHA = \"([a-f0-9]+)\"', response.text)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
else:
|
||||||
|
raise Exception("Envoy SHA not found in WORKSPACE file")
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to get WORKSPACE file: {response.status_code}")
|
||||||
|
|
||||||
|
def get_envoy_version(envoy_sha):
|
||||||
|
url = f"https://raw.githubusercontent.com/envoyproxy/envoy/{envoy_sha}/VERSION.txt"
|
||||||
|
response = requests.get(url)
|
||||||
|
if response.status_code == 200:
|
||||||
|
version = response.text.strip()
|
||||||
|
match = re.search(r'(\d+\.\d+)', version)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
else:
|
||||||
|
raise Exception("Failed to extract major.minor version")
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to get Envoy version: {response.status_code}")
|
||||||
|
|
||||||
|
|
||||||
def get_init_container():
|
def get_init_container():
|
||||||
# Define the initContainer you want to inject
|
# Define the initContainer you want to inject
|
||||||
|
istio_version = get_istio_version()
|
||||||
|
app.logger.debug(f"Istio Version: {istio_version}")
|
||||||
|
|
||||||
|
envoy_sha = get_envoy_sha(istio_version)
|
||||||
|
app.logger.debug(f"Envoy SHA: {envoy_sha}")
|
||||||
|
|
||||||
|
envoy_version = get_envoy_version(envoy_sha)
|
||||||
|
app.logger.info(f"Envoy Version: {envoy_version}")
|
||||||
|
|
||||||
init_container = {
|
init_container = {
|
||||||
"name": "prepare-attachment",
|
"name": "prepare-attachment",
|
||||||
"image": FULL_AGENT_IMAGE,
|
"image": FULL_INIT_CONTAINER_IMAGE,
|
||||||
"imagePullPolicy": "Always",
|
"imagePullPolicy": "Always",
|
||||||
"command": [
|
"command": [
|
||||||
"sh", "-c",
|
"sh", "-c",
|
||||||
"mkdir -p /envoy/attachment/shared && cp -r /envoy/attachment/lib* /envoy/attachment/shared"
|
f"mkdir -p /envoy/attachment/shared && cp -r /envoy/attachment/lib* /envoy/attachment/shared && cp /envoy/attachment/versions/{envoy_version}/lib* /envoy/attachment/shared"
|
||||||
],
|
],
|
||||||
"volumeMounts": [
|
"volumeMounts": [
|
||||||
{
|
{
|
||||||
@ -173,10 +223,39 @@ def get_volume_mount():
|
|||||||
# Volume definition for the pod
|
# Volume definition for the pod
|
||||||
def get_volume_definition():
|
def get_volume_definition():
|
||||||
app.logger.debug("Entering get_volume_definition()")
|
app.logger.debug("Entering get_volume_definition()")
|
||||||
volume_def = {
|
|
||||||
|
persistence_enabled = os.getenv("APPSEC_PERSISTENCE_ENABLED", "false").lower() == "true"
|
||||||
|
|
||||||
|
volume_def = [
|
||||||
|
{
|
||||||
"name": "envoy-attachment-shared",
|
"name": "envoy-attachment-shared",
|
||||||
"emptyDir": {}
|
"emptyDir": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "advanced-model",
|
||||||
|
"configMap": {
|
||||||
|
"name": "advanced-model-config",
|
||||||
|
"optional": True
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if persistence_enabled:
|
||||||
|
volume_def.extend([
|
||||||
|
{
|
||||||
|
"name": "open-appsec-conf",
|
||||||
|
"persistentVolumeClaim": {
|
||||||
|
"claimName": "open-appsec-conf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "open-appsec-data",
|
||||||
|
"persistentVolumeClaim": {
|
||||||
|
"claimName": "open-appsec-data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
app.logger.debug(f"Volume definition: {volume_def}")
|
app.logger.debug(f"Volume definition: {volume_def}")
|
||||||
app.logger.debug("Exiting get_volume_definition()")
|
app.logger.debug("Exiting get_volume_definition()")
|
||||||
return volume_def
|
return volume_def
|
||||||
@ -478,10 +557,10 @@ def mutate():
|
|||||||
init_containers = obj.get('spec', {}).get('initContainers', [])
|
init_containers = obj.get('spec', {}).get('initContainers', [])
|
||||||
volumes = obj.get('spec', {}).get('volumes', [])
|
volumes = obj.get('spec', {}).get('volumes', [])
|
||||||
app.logger.debug("Current containers in the pod: %s", json.dumps(containers, indent=2))
|
app.logger.debug("Current containers in the pod: %s", json.dumps(containers, indent=2))
|
||||||
sidecar_exists = any(container['name'] == 'infinity-next-nano-agent' for container in containers)
|
sidecar_exists = any(container['name'] == 'open-appsec-nano-agent' for container in containers)
|
||||||
init_container_exist = any(init_container['name'] == 'prepare-attachment' for init_container in init_containers)
|
init_container_exist = any(init_container['name'] == 'prepare-attachment' for init_container in init_containers)
|
||||||
volume_exist = any(volume['name'] == 'envoy-attachment-shared' for volume in volumes)
|
volume_exist = any(volume['name'] == 'envoy-attachment-shared' for volume in volumes)
|
||||||
app.logger.debug("Does sidecar 'infinity-next-nano-agent' exist? %s", sidecar_exists)
|
app.logger.debug("Does sidecar 'open-appsec-nano-agent' exist? %s", sidecar_exists)
|
||||||
|
|
||||||
# Determine if we should remove the injected data
|
# Determine if we should remove the injected data
|
||||||
REMOVE_WAF = os.getenv('REMOVE_INJECTED_DATA', 'false').lower() == 'true'
|
REMOVE_WAF = os.getenv('REMOVE_INJECTED_DATA', 'false').lower() == 'true'
|
||||||
@ -542,7 +621,7 @@ def mutate():
|
|||||||
"path": f"/spec/containers/{idx}/volumeMounts/{idx_v}"
|
"path": f"/spec/containers/{idx}/volumeMounts/{idx_v}"
|
||||||
})
|
})
|
||||||
app.logger.debug(f"Removed volumeMount: {patches[-1]}")
|
app.logger.debug(f"Removed volumeMount: {patches[-1]}")
|
||||||
if container['name'] == 'infinity-next-nano-agent':
|
if container['name'] == 'open-appsec-nano-agent':
|
||||||
patches.append({
|
patches.append({
|
||||||
"op": "remove",
|
"op": "remove",
|
||||||
"path": f"/spec/containers/{idx}"
|
"path": f"/spec/containers/{idx}"
|
||||||
@ -561,7 +640,7 @@ def mutate():
|
|||||||
break # Stop once we find and remove the target container
|
break # Stop once we find and remove the target container
|
||||||
|
|
||||||
else:
|
else:
|
||||||
app.logger.debug("Before if: Sidecar 'infinity-next-nano-agent' does not exist. Preparing to add it.")
|
app.logger.debug("Before if: Sidecar 'open-appsec-nano-agent' does not exist. Preparing to add it.")
|
||||||
|
|
||||||
# Define the sidecar container
|
# Define the sidecar container
|
||||||
sidecar = get_sidecar_container()
|
sidecar = get_sidecar_container()
|
||||||
@ -616,10 +695,11 @@ def mutate():
|
|||||||
app.logger.debug("Added volume mount patch to istio-proxy: %s", patches[-1])
|
app.logger.debug("Added volume mount patch to istio-proxy: %s", patches[-1])
|
||||||
|
|
||||||
# Add the new volume definition
|
# Add the new volume definition
|
||||||
|
for volume in volume_def:
|
||||||
patches.append({
|
patches.append({
|
||||||
"op": "add",
|
"op": "add",
|
||||||
"path": "/spec/volumes/-",
|
"path": "/spec/volumes/-",
|
||||||
"value": volume_def
|
"value": volume
|
||||||
})
|
})
|
||||||
app.logger.debug("Added volume definition patch: %s", patches[-1])
|
app.logger.debug("Added volume definition patch: %s", patches[-1])
|
||||||
|
|
||||||
@ -628,11 +708,11 @@ def mutate():
|
|||||||
envoy_filter_name = RELEASE_NAME + "-waf-filter"
|
envoy_filter_name = RELEASE_NAME + "-waf-filter"
|
||||||
create_or_update_envoy_filter(envoy_filter_name, namespace, SELECTOR_LABEL_NAME, SELECTOR_LABEL_VALUE)
|
create_or_update_envoy_filter(envoy_filter_name, namespace, SELECTOR_LABEL_NAME, SELECTOR_LABEL_VALUE)
|
||||||
else:
|
else:
|
||||||
app.logger.debug("Before else: Sidecar 'infinity-next-nano-agent' already exists. Checking for image updates.")
|
app.logger.debug("Before else: Sidecar 'open-appsec-nano-agent' already exists. Checking for image updates.")
|
||||||
|
|
||||||
# Optionally, update the sidecar image and tag if necessary
|
# Optionally, update the sidecar image and tag if necessary
|
||||||
for idx, container in enumerate(containers):
|
for idx, container in enumerate(containers):
|
||||||
if container['name'] == 'infinity-next-nano-agent':
|
if container['name'] == 'open-appsec-nano-agent':
|
||||||
current_image = container.get('image', '')
|
current_image = container.get('image', '')
|
||||||
app.logger.debug("Current sidecar image: %s", current_image)
|
app.logger.debug("Current sidecar image: %s", current_image)
|
||||||
app.logger.debug("Desired sidecar image: %s", FULL_AGENT_IMAGE)
|
app.logger.debug("Desired sidecar image: %s", FULL_AGENT_IMAGE)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user