| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- //go:build linux
- package ims
- import (
- "context"
- "errors"
- "fmt"
- "os/exec"
- "strings"
- "sync"
- )
- type linuxIPSecInstaller struct {
- ipCommand string
- }
- func defaultIPSecInstaller() IPSecSAInstaller {
- return linuxIPSecInstaller{ipCommand: "ip"}
- }
- type linuxIPSecHandle struct {
- mu sync.Mutex
- ipCommand string
- config IPSecSAConfig
- closed bool
- }
- func (installer linuxIPSecInstaller) Install(ctx context.Context, config IPSecSAConfig) (IPSecSAHandle, error) {
- command := installer.ipCommand
- if command == "" {
- command = "ip"
- }
- if _, err := exec.LookPath(command); err != nil {
- return nil, errors.New("ims: Linux iproute2 is required for ipsec-3gpp")
- }
- install, err := buildXFRMInstallPlan(config)
- if err != nil {
- return nil, err
- }
- handle := &linuxIPSecHandle{
- ipCommand: command,
- config: cloneIPSecSAConfig(config),
- }
- for _, operation := range install {
- if err := runIPCommand(ctx, command, operation); err != nil {
- _ = handle.cleanup(context.Background())
- zeroBytes(handle.config.EncryptionKey)
- zeroBytes(handle.config.IntegrityKey)
- return nil, fmt.Errorf("%w: %v", ErrIPSecInstall, err)
- }
- }
- zeroBytes(handle.config.EncryptionKey)
- zeroBytes(handle.config.IntegrityKey)
- return handle, nil
- }
- func (handle *linuxIPSecHandle) Close(ctx context.Context) error {
- handle.mu.Lock()
- defer handle.mu.Unlock()
- if handle.closed {
- return nil
- }
- handle.closed = true
- return handle.cleanup(ctx)
- }
- func (handle *linuxIPSecHandle) cleanup(ctx context.Context) error {
- var cleanupErrors []error
- for _, operation := range buildXFRMCleanupPlan(handle.config) {
- if err := runIPCommand(ctx, handle.ipCommand, operation); err != nil {
- cleanupErrors = append(cleanupErrors, err)
- }
- }
- return errors.Join(cleanupErrors...)
- }
- func runIPCommand(ctx context.Context, command string, operation xfrmOperation) error {
- output, err := exec.CommandContext(ctx, command, operation.arguments...).CombinedOutput()
- if err == nil {
- return nil
- }
- message := strings.TrimSpace(string(output))
- if message == "" {
- message = err.Error()
- }
- // Operation descriptions contain no SPI keys or subscriber identity.
- return fmt.Errorf("%s: %s", operation.description, message)
- }
|