87 lines
2.5 KiB
Go
87 lines
2.5 KiB
Go
//go:build linux
|
|
|
|
package hooks
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.pcux.cn/xuans/Smail/utils/credential"
|
|
)
|
|
|
|
func startPluginEgress(spec *pluginLaunchSpec, uid, gid int) error {
|
|
logicalID := ""
|
|
for _, item := range spec.procAttr.Env {
|
|
if strings.HasPrefix(item, "SMAIL_PLUGIN_ID=") {
|
|
logicalID = strings.TrimPrefix(item, "SMAIL_PLUGIN_ID=")
|
|
}
|
|
}
|
|
if logicalID == "" {
|
|
return errors.New("plugin egress identity is unavailable")
|
|
}
|
|
token, err := newPluginAuthToken()
|
|
if err != nil {
|
|
return errors.New("plugin egress authorization generation failed")
|
|
}
|
|
socketPath := filepath.Join(spec.runtimeDir, filepath.Base(credential.PluginEgressSocket))
|
|
listener, err := net.ListenUnix("unix", &net.UnixAddr{Name: socketPath, Net: "unix"})
|
|
if err != nil {
|
|
return errors.New("plugin egress listener creation failed")
|
|
}
|
|
if err := os.Chmod(socketPath, 0600); err != nil {
|
|
_ = listener.Close()
|
|
return errors.New("plugin egress socket permissions failed")
|
|
}
|
|
if err := os.Chown(socketPath, uid, gid); err != nil {
|
|
_ = listener.Close()
|
|
return errors.New("plugin egress socket identity failed")
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
server := &http.Server{
|
|
Handler: credential.NewPluginEgressHandler(token, func() []credential.NetworkTarget {
|
|
instance, _, ok := pluginInstanceForStartup(logicalID)
|
|
if !ok || validatePluginRuntimeBinding(logicalID, instance) != nil {
|
|
return nil
|
|
}
|
|
canNetwork := false
|
|
for _, capability := range instance.Permissions.Capabilities {
|
|
canNetwork = canNetwork || capability == "network"
|
|
}
|
|
if !canNetwork {
|
|
return nil
|
|
}
|
|
targets := make([]credential.NetworkTarget, 0, len(instance.Permissions.Network))
|
|
for _, target := range instance.Permissions.Network {
|
|
if target.Scheme == "https" {
|
|
targets = append(targets, credential.NetworkTarget{Scheme: target.Scheme, Host: target.Host, Port: target.Port})
|
|
}
|
|
}
|
|
return targets
|
|
}),
|
|
BaseContext: func(net.Listener) context.Context { return ctx },
|
|
ReadHeaderTimeout: 5 * time.Second,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 65 * time.Second,
|
|
IdleTimeout: 5 * time.Second,
|
|
MaxHeaderBytes: 32 << 10,
|
|
ErrorLog: log.New(io.Discard, "", 0),
|
|
}
|
|
server.SetKeepAlivesEnabled(false)
|
|
spec.egressStop = func() {
|
|
cancel()
|
|
_ = listener.Close()
|
|
_ = server.Close()
|
|
}
|
|
spec.procAttr.Env = appendPluginEnv(spec.procAttr.Env, "SMAIL_PLUGIN_EGRESS_TOKEN", token)
|
|
go func() { _ = server.Serve(listener) }()
|
|
return nil
|
|
}
|