### Full Example: Load IKE Connection and Initiate SA Source: https://context7.com/strongswan/govici/llms.txt This example demonstrates loading an IKE connection configuration using `MarshalMessage` and `load-conn`, then initiating SA establishment with `initiate` and streaming log output. Ensure correct struct tags for marshaling. ```go package main import ( "context" "fmt" "time" "github.com/strongswan/govici/vici" ) type connection struct { Name string // No vici tag — NOT marshaled into the message LocalAddrs []string `vici:"local_addrs" Local *localOpts `vici:"local" Remote *remoteOpts `vici:"remote" Children map[string]*childSA `vici:"children" Version int `vici:"version" Proposals []string `vici:"proposals" } type localOpts struct { Auth string `vici:"auth" Certs []string `vici:"certs" ID string `vici:"id" } type remoteOpts struct { Auth string `vici:"auth" } type childSA struct { LocalTrafficSelectors []string `vici:"local_ts" Updown string `vici:"updown" ESPProposals []string `vici:"esp_proposals" } func loadConn(s *vici.Session, conn connection) error { c, err := vici.MarshalMessage(&conn) if err != nil { return err } in := vici.NewMessage() if err := in.Set(conn.Name, c); err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() resp, err := s.Call(ctx, "load-conn", in) if err != nil { return err } return resp.Err() } func initiate(s *vici.Session, ike, child string) error { in := vici.NewMessage() _ = in.Set("ike", ike) _ = in.Set("child", child) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // "initiate" streams "control-log" events with live log output for m, err := range s.CallStreaming(ctx, "initiate", "control-log", in) { if err != nil { return err } fmt.Println("LOG:", m.Get("msg")) } return nil } func main() { s, err := vici.NewSession() if err != nil { panic(err) } defer s.Close() conn := connection{ Name: "rw", LocalAddrs: []string{"192.168.0.1"}, Local: &localOpts{ Auth: "pubkey", Certs: []string{"moonCert.pem"}, ID: "moon.strongswan.org", }, Remote: &remoteOpts{Auth: "pubkey"}, Children: map[string]*childSA{ "net": { LocalTrafficSelectors: []string{"10.1.0.0/16"}, Updown: "/usr/local/libexec/ipsec/_updown iptables", ESPProposals: []string{"aes128gcm128-x25519"}, }, }, Version: 2, Proposals: []string{"aes128-sha256-x25519"}, } if err := loadConn(s, conn); err != nil { panic(err) } if err := initiate(s, "rw", "net"); err != nil { panic(err) } } ``` -------------------------------- ### Example swanctl.conf Configuration Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md This is an example `swanctl.conf` configuration for a road warrior scenario with certificate-based authentication. ```ini connections { rw { local_addrs = 192.168.0.1 local { auth = pubkey certs = moonCert.pem id = moon.strongswan.org } remote { auth = pubkey } children { net { local_ts = 10.1.0.0/16 updown = /usr/local/libexec/ipsec/_updown iptables esp_proposals = aes128gcm128-x25519 } } version = 2 proposals = aes128-sha256-x25519 } } ``` -------------------------------- ### Logging Example in Go Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md This Go code snippet demonstrates how to log messages. It includes error handling and printing log messages to the console. ```go return err } fmt.Println("LOG:", m.Get("msg")) } return nil } ``` -------------------------------- ### Import Govici Package Source: https://github.com/strongswan/govici/blob/master/README.md Import the necessary Govici package to start using the VICI client library in your Go application. ```go import ( "github.com/strongswan/govici/vici" ) ``` -------------------------------- ### Get Human-Readable VICI Message String Source: https://context7.com/strongswan/govici/llms.txt Generate a string representation of a Message, formatted like the swanctl.conf file. Ideal for debugging and logging. ```go m, _ := s.Call(ctx, "version", nil) fmt.Println(m.String()) // { // daemon = charon-systemd // version = 5.9.13 // sysname = Linux // release = 6.14.0-29-generic // machine = x86_64 // } ``` -------------------------------- ### Get strongSwan Daemon Version Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Retrieves the version information of the running charon daemon using the 'version' command. This command requires no arguments and returns details about the daemon, OS, and hardware. A context with a timeout is used to prevent indefinite waiting. ```go package main import ( "context" "fmt" "os" "time" "github.com/strongswan/govici/vici" ) func showVersion() error { s, err := vici.NewSession() if err != nil { return err } defer s.Close() ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() m, err := s.Call(ctx, "version", nil) if err != nil { return err } fmt.Println(m) return nil } func main() { if err := showVersion(); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` -------------------------------- ### Customize vici session with custom dial function Source: https://context7.com/strongswan/govici/llms.txt Provides a custom `DialContext` function for creating the underlying net.Conn. Useful for testing, proxies, or non-standard transport setups. ```go import "net" customDialer := func(ctx context.Context, network, addr string) (net.Conn, error) { d := net.Dialer{Timeout: 2 * time.Second} return d.DialContext(ctx, network, addr) } s, err := vici.NewSession(vici.WithDialContext(customDialer)) if err != nil { panic(err) } deferr s.Close() ``` -------------------------------- ### WithDialContext - Session option: custom dial function Source: https://context7.com/strongswan/govici/llms.txt Provides a custom `DialContext` function for creating the underlying net.Conn. Useful for testing, proxies, or non-standard transport setups. ```APIDOC ## WithDialContext ### Description Session option to provide a custom `DialContext` function for establishing the network connection. ### Method `WithDialContext(dialer net.Dialer) SessionOption` ### Parameters - **dialer** (`net.Dialer`): A custom dialer function that implements `net.Dialer`. ### Returns - `SessionOption`: A session option function. ### Example ```go import "net" customDialer := func(ctx context.Context, network, addr string) (net.Conn, error) { d := net.Dialer{Timeout: 2 * time.Second} return d.DialContext(ctx, network, addr) } s, err := vici.NewSession(vici.WithDialContext(customDialer)) if err != nil { panic(err) } defer s.Close() ``` ``` -------------------------------- ### Subscribe to Server Events with Go Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Use Session.Subscribe to listen for specific event types. Register a channel with Session.NotifyEvents to receive events. Ensure the session is active and the channel is properly managed with Session.StopEvents. ```go package main import ( "errors" "flag" "fmt" "os" "github.com/strongswan/govici/vici" ) func monitor(ike string) error { if ike == "" { return errors.New("must specify IKE SA name") } s, err := vici.NewSession() if err != nil { return err } defer s.Close() ec := make(chan vici.Event, 16) s.NotifyEvents(ec) defer s.StopEvents(ec) // Subscribe to 'ike-updown' and 'log' events. if err := s.Subscribe("ike-updown", "log"); err != nil { return err } for { e, ok := <-ec if !ok { // Event listener closed. return nil } // The Event.Name field corresponds to the event name // we used to make the subscription. The Event.Message // field contains the Message from the server. switch e.Name { case "ike-updown": m, ok := e.Message.Get(ike).(*vici.Message) if !ok { // This message is not about the IKE SA we are // monitoring. Ignore. continue } fmt.Printf("IKE-UPDOWN: %s state changed: %s\n", ike, m.Get("state")) case "log": if s, ok := e.Message.Get("ikesa-name").(string); !ok || s != ike { // This message is not about the IKE SA we are // monitoring. Ignore. continue } // Log events contain a 'msg' field with the log message fmt.Println("LOG:", e.Message.Get("msg")) } } } func main() { var ike string flag.StringVar(&ike, "ike", "", "Name of IKE SA to monitor.") flag.Parse() if err := monitor(ike); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` -------------------------------- ### Create a vici Client Session Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Establishes a new vici client session. Ensure the strongSwan charon daemon is running with the vici plugin enabled. The session should be closed when no longer needed. ```go s, err := vici.NewSession() if err != nil { return err } defer s.Close() ``` -------------------------------- ### Load connection using govici Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md This function `loadConn` marshals a Go `connection` struct into a VICI message and sends it to the StrongSwan daemon using the `load-conn` command. It includes a 5-second context timeout. ```go package main import ( "context" "fmt" "time" "github.com/strongswan/govici/vici" ) type connection struct { Name string // This field will NOT be marshaled! LocalAddrs []string `vici:"local_addrs"` Local *localOpts `vici:"local"` Remote *remoteOpts `vici:"remote"` Children map[string]*childSA `vici:"children"` Version int `vici:"version"` Proposals []string `vici:"proposals"` } type localOpts struct { Auth string `vici:"auth"` Certs []string `vici:"certs"` ID string `vici:"id"` } type remoteOpts struct { Auth string `vici:"auth"` } type childSA struct { LocalTrafficSelectors []string `vici:"local_ts"` Updown string `vici:"updown"` ESPProposals []string `vici:"esp_proposals"` } func loadConn(s *vici.Session, conn connection) error { c, err := vici.MarshalMessage(&conn) if err != nil { return err } in := vici.NewMessage() if err := in.Set(conn.Name, c); err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _, err = s.Call(ctx, "load-conn", in) return err } func initiate(s *vici.Session, ike, child string) error { in := vici.NewMessage() if err := in.Set("ike", ike); err != nil { return err } if err := in.Set("child", child); err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() for m, err := range s.CallStreaming(ctx, "initiate", "control-log", in) { if err != nil { ``` -------------------------------- ### Create a vici client session Source: https://context7.com/strongswan/govici/llms.txt Opens a connection to the charon daemon's vici socket. By default, connects to the Unix socket at /var/run/charon.vici. The session must be closed when done. ```go package main import ( "fmt" "github.com/strongswan/govici/vici" ) func main() { // Default: connects to /var/run/charon.vici s, err := vici.NewSession() if err != nil { fmt.Println("Failed to connect:", err) return } defer s.Close() fmt.Println("Connected to charon daemon") } ``` -------------------------------- ### Customize vici session with custom Unix socket path Source: https://context7.com/strongswan/govici/llms.txt Overrides the default socket path. Use this when charon is configured to listen on a non-standard path. ```go s, err := vici.NewSession(vici.WithSocketPath("/run/strongswan/charon.vici")) if err != nil { panic(err) } deferr s.Close() ``` -------------------------------- ### Define Go structs for local and remote options Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Define Go structs `localOpts` and `remoteOpts` to represent the local and remote authentication options within a connection. ```go type localOpts struct { Auth string `vici:"auth"` Certs []string `vici:"certs"` ID string `vici:"id"` } type remoteOpts struct { Auth string `vici:"auth"` } ``` -------------------------------- ### NewSession - Create a vici client session Source: https://context7.com/strongswan/govici/llms.txt Opens a connection to the charon daemon's vici socket. By default, connects to the Unix socket at /var/run/charon.vici. Accepts zero or more SessionOption values to customize the connection. Returns a *Session and an error; the session must be closed when done. ```APIDOC ## NewSession ### Description Opens a connection to the charon daemon's vici socket. By default, connects to the Unix socket at `/var/run/charon.vici`. Accepts zero or more `SessionOption` values to customize the connection. Returns a `*Session` and an error; the session must be closed when done. ### Method `NewSession(options ...SessionOption) (*Session, error)` ### Parameters #### Options - `SessionOption`: Zero or more options to customize the session connection. ### Returns - `*Session`: A pointer to the established VICI session. - `error`: An error if the connection fails. ### Example ```go package main import ( "fmt" "github.com/strongswan/govici/vici" ) func main() { // Default: connects to /var/run/charon.vici s, err := vici.NewSession() if err != nil { fmt.Println("Failed to connect:", err) return } defer s.Close() fmt.Println("Connected to charon daemon") } ``` ``` -------------------------------- ### Customize vici session with custom network and address Source: https://context7.com/strongswan/govici/llms.txt Specifies both the network type (e.g., "unix", "tcp") and address for the charon socket. Useful for TCP-based configurations, though Unix sockets are strongly recommended for security. ```go // Connect over TCP (not recommended for production; no auth/encryption in vici itself) s, err := vici.NewSession(vici.WithAddr("tcp", "127.0.0.1:4502")) if err != nil { panic(err) } deferr s.Close() ``` -------------------------------- ### Load Certificate into strongSwan Daemon Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md This function reads a certificate from a file, marshals it into a VICI message using `MarshalMessage`, and sends it to the strongSwan daemon via a VICI session. It handles file reading, PEM decoding, and session management. ```go package main import ( "context" "encoding/pem" "errors" "flag" "fmt" "io/ioutil" "os" "time" "github.com/strongswan/govici/vici" ) type cert struct { Type string `vici:"type"` Flag string `vici:"flag"` Data string `vici:"data"` } func loadX509Cert(path string) error { if path == "" { return errors.New("must specify path") } s, err := vici.NewSession() if err != nil { return err } defer s.Close() // Read cert data from the file data, err := ioutil.ReadFile(path) if err != nil { return err } block, _ := pem.Decode(data) cert := cert{ Type: "X509", Flag: "NONE", Data: string(block.Bytes), } in, err := vici.MarshalMessage(&cert) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _, err = s.Call(ctx, "load-cert", in) return err } func main() { var path string flag.StringVar(&path, "-path", "", "Path to certificate to load") flag.Parse() if err := loadX509Cert(path); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` -------------------------------- ### Create a New VICI Message Source: https://context7.com/strongswan/govici/llms.txt Initialize an empty Message object to manually construct command input. Fields can be added using the Set method. ```go m := vici.NewMessage() if err := m.Set("ike", "my-connection"); err != nil { panic(err) } if err := m.Set("child", "my-child-sa"); err != nil { panic(err) } ``` -------------------------------- ### Session.Call - Send a single command to charon Source: https://context7.com/strongswan/govici/llms.txt Sends a named vici command with an optional input `*Message` and returns the response `*Message`. The context controls timeout and cancellation. Pass `nil` for the message if the command requires no input parameters. ```APIDOC ## Session.Call ### Description Sends a named VICI command to the charon daemon with an optional input message and returns the response message. The provided context is used for managing timeouts and cancellations. ### Method `(*Session) Call(ctx context.Context, command string, message *Message) (*Message, error)` ### Parameters - **ctx** (`context.Context`): The context for managing request lifecycle (timeout, cancellation). - **command** (string): The name of the VICI command to execute. - **message** (`*Message`): An optional input message containing command parameters. Pass `nil` if the command requires no input. ### Returns - `*Message`: The response message from the charon daemon. - `error`: An error if the command execution fails. ### Example ```go package main import ( "context" "fmt" "os" "time" "github.com/strongswan/govici/vici" ) func showVersion() error { s, err := vici.NewSession() if err != nil { return err } defer s.Close() ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() // "version" command requires no input parameters m, err := s.Call(ctx, "version", nil) if err != nil { return err } // m.String() formats output similar to swanctl.conf fmt.Println(m) // Output: // { // daemon = charon-systemd // version = 5.9.13 // sysname = Linux // release = 6.14.0-29-generic // machine = x86_64 // } return nil } func main() { if err := showVersion(); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` ``` -------------------------------- ### Subscribe to and Handle VICI Events Source: https://context7.com/strongswan/govici/llms.txt Register a channel to receive server-issued events and subscribe to specific event types. Events include name, payload, and timestamp. ```go ec := make(chan vici.Event, 32) s.NotifyEvents(ec) s.Subscribe("child-updown") for e := range ec { fmt.Printf("[%s] Event: %s\n", e.Timestamp.Format(time.RFC3339), e.Name) // Access event payload fmt.Println(e.Message) } ``` -------------------------------- ### List Connections with Streaming Events in Go Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Use `Session.CallStreaming` to list connections, streaming `list-conn` events. This function optionally filters connections by IKE SA name. Ensure the vici session is properly closed after use. ```go package main import ( "context" "flag" "fmt" "os" "time" "github.com/strongswan/govici/vici" ) func showConns(ike string) error { s, err := vici.NewSession() if err != nil { return err } defer s.Close() var in *vici.Message if ike != "" { in = vici.NewMessage() if err := in.Set("ike", ike); err != nil { return err } } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() for m, err := range s.CallStreaming(ctx, "list-conns", "list-conn", in) { if err != nil { return err } fmt.Println(m) } return nil } func main() { var ike string flag.StringVar(&ike, "-ike", "", "Filter conns by IKE SA name") flag.Parse() if err := showConns(ike); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` -------------------------------- ### Register Channel for Event Notifications with `Session.NotifyEvents` Source: https://context7.com/strongswan/govici/llms.txt Register a channel to receive events. Each registered channel receives a copy of every event. Writes to the channel are silently discarded if they would block, so ensure sufficient buffer size. The channel is closed when the session closes. ```Go package main import ( "errors" "flag" "fmt" "os" "github.com/strongswan/govici/vici" ) func monitor(ike string) error { if ike == "" { return errors.New("must specify IKE SA name") } s, err := vici.NewSession() if err != nil { return err } defer s.Close() ec := make(chan vici.Event, 16) s.NotifyEvents(ec) defer s.StopEvents(ec) if err := s.Subscribe("ike-updown", "log"); err != nil { return err } for { e, ok := <-ec if !ok { return nil // Session closed } switch e.Name { case "ike-updown": m, ok := e.Message.Get(ike).(*vici.Message) if !ok { continue // Not about our SA } fmt.Printf("IKE-UPDOWN: %s state changed: %s\n", ike, m.Get("state")) case "log": if s, ok := e.Message.Get("ikesa-name").(string); !ok || s != ike { continue } fmt.Println("LOG:", e.Message.Get("msg")) } } } func main() { var ike string flag.StringVar(&ike, "-ike", "", "Name of IKE SA to monitor.") flag.Parse() if err := monitor(ike); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` -------------------------------- ### Send a single command to charon Source: https://context7.com/strongswan/govici/llms.txt Sends a named vici command with an optional input `*Message` and returns the response `*Message`. The context controls timeout and cancellation. Pass `nil` for the message if the command requires no input parameters. ```go package main import ( "context" "fmt" "os" "time" "github.com/strongswan/govici/vici" ) func showVersion() error { s, err := vici.NewSession() if err != nil { return err } defer s.Close() ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() // "version" command requires no input parameters m, err := s.Call(ctx, "version", nil) if err != nil { return err } // m.String() formats output similar to swanctl.conf fmt.Println(m) // Output: // { // daemon = charon-systemd // version = 5.9.13 // sysname = Linux // release = 6.14.0-29-generic // machine = x86_64 // } return nil } func main() { if err := showVersion(); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` -------------------------------- ### List All Keys in a VICI Message Source: https://context7.com/strongswan/govici/llms.txt Obtain an ordered list of all keys present in a Message. Useful for iterating through message contents. ```go m, _ := s.Call(ctx, "version", nil) for _, key := range m.Keys() { fmt.Printf("%s = %v\n", key, m.Get(key)) } // daemon = charon-systemd // version = 5.9.13 // sysname = Linux // release = 6.14.0-29-generic // machine = x86_64 ``` -------------------------------- ### Subscribe to Server-Issued Events with `Session.Subscribe` Source: https://context7.com/strongswan/govici/llms.txt Register the session to receive specific event types from the charon daemon, such as `"ike-updown"` or `"log"`. This must be called before registering channels with `NotifyEvents`. ```Go s, err := vici.NewSession() if err != nil { panic(err) } defer s.Close() // Subscribe to IKE state changes and log events if err := s.Subscribe("ike-updown", "log"); err != nil { panic(err) } ``` -------------------------------- ### WithSocketPath - Session option: custom Unix socket path Source: https://context7.com/strongswan/govici/llms.txt Overrides the default socket path. Use this when charon is configured to listen on a non-standard path. ```APIDOC ## WithSocketPath ### Description Session option to override the default Unix socket path for the charon daemon. ### Method `WithSocketPath(path string) SessionOption` ### Parameters - **path** (string): The custom path to the charon VICI socket. ### Returns - `SessionOption`: A session option function. ### Example ```go s, err := vici.NewSession(vici.WithSocketPath("/run/strongswan/charon.vici")) if err != nil { panic(err) } defer s.Close() ``` ``` -------------------------------- ### Define Go struct for connection Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Define a Go struct `connection` to represent the `swanctl.conf` connection configuration. The `vici` tags map struct fields to configuration options. ```go type connection struct { Name string // This field will NOT be marshaled! LocalAddrs []string `vici:"local_addrs"` Local *localOpts `vici:"local"` Remote *remoteOpts `vici:"remote"` Children map[string]*childSA `vici:"children"` Version int `vici:"version"` Proposals []string `vici:"proposals"` } ``` -------------------------------- ### Message.String Source: https://context7.com/strongswan/govici/llms.txt Returns a human-readable string representation of the Message, formatted like `swanctl.conf`. ```APIDOC ## Message.String — Get a human-readable representation of a Message ### Description Returns a string formatted similarly to the `swanctl.conf` configuration file format. Useful for debugging and logging. ### Usage ```go m, _ := s.Call(ctx, "version", nil) fmt.Println(m.String()) // { // daemon = charon-systemd // version = 5.9.13 // sysname = Linux // release = 6.14.0-29-generic // machine = x86_64 // } ``` ``` -------------------------------- ### Send Streaming Command and Iterate Events with `Session.CallStreaming` Source: https://context7.com/strongswan/govici/llms.txt Use `CallStreaming` for vici commands that stream events during execution, such as `list-sas` or `list-conns`. The `event` parameter specifies the type of event to stream. Ensure proper context management with timeouts. ```Go package main import ( "context" "flag" "fmt" "os" "time" "github.com/strongswan/govici/vici" ) func showConns(ike string) error { s, err := vici.NewSession() if err != nil { return err } defer s.Close() var in *vici.Message // Optionally filter by IKE SA name if ike != "" { in = vici.NewMessage() if err := in.Set("ike", ike); err != nil { return err } } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // "list-conns" streams "list-conn" events until complete for m, err := range s.CallStreaming(ctx, "list-conns", "list-conn", in) { if err != nil { return err } fmt.Println(m) } return nil } func main() { var ike string flag.StringVar(&ike, "-ike", "", "Filter conns by IKE SA name") flag.Parse() if err := showConns(ike); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } } ``` -------------------------------- ### WithAddr - Session option: custom network and address Source: https://context7.com/strongswan/govici/llms.txt Specifies both the network type (e.g., "unix", "tcp") and address for the charon socket. Useful for TCP-based configurations, though Unix sockets are strongly recommended for security. ```APIDOC ## WithAddr ### Description Session option to specify a custom network and address for the charon socket connection. ### Method `WithAddr(network, address string) SessionOption` ### Parameters - **network** (string): The network type (e.g., "unix", "tcp"). - **address** (string): The address of the charon socket. ### Returns - `SessionOption`: A session option function. ### Example ```go // Connect over TCP (not recommended for production; no auth/encryption in vici itself) s, err := vici.NewSession(vici.WithAddr("tcp", "127.0.0.1:4502")) if err != nil { panic(err) } defer s.Close() ``` ``` -------------------------------- ### Define Certificate Struct for VICI Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Define a Go struct with `vici` tags that map directly to the VICI message parameters for the `load-cert` command. Ensure struct fields are exported and tags match VICI field names. ```go type cert struct { Type string `vici:"type"` Flag string `vici:"flag"` Data string `vici:"data"` } ``` -------------------------------- ### Session.Subscribe Source: https://context7.com/strongswan/govici/llms.txt Registers the session to receive named event types from the charon daemon. Event names correspond to the **Server-issued events** section of the vici protocol spec (e.g., `"ike-updown"`, `"child-updown"`, `"log"`). Must be called before events will be delivered to channels registered with `NotifyEvents`. ```APIDOC ## Session.Subscribe ### Description Registers the session to receive named event types from the charon daemon. Event names correspond to the **Server-issued events** section of the vici protocol spec (e.g., `"ike-updown"`, `"child-updown"`, `"log"`). Must be called before events will be delivered to channels registered with `NotifyEvents`. ### Method Signature `func (s *Session) Subscribe(events ...string) error` ### Parameters - `events` ([]string): A variadic list of event names to subscribe to. ### Example ```go // Subscribe to IKE state changes and log events if err := s.Subscribe("ike-updown", "log"); err != nil { panic(err) } ``` ``` -------------------------------- ### Check VICI Message Response for Errors Source: https://context7.com/strongswan/govici/llms.txt Examine a response message for the 'success' field. Returns an error if 'success' is not 'yes' or absent, wrapping the 'errmsg' field. ```go resp, err := s.Call(ctx, "unload-conn", in) if err != nil { return err } if err := resp.Err(); err != nil { return fmt.Errorf("unload-conn failed: %w", err) } ``` -------------------------------- ### Session.CallStreaming Source: https://context7.com/strongswan/govici/llms.txt Send a streaming command and iterate over events. Used for vici commands that stream events during execution (e.g., `list-sas`, `list-conns`, `initiate`). Returns an `iter.Seq2[*Message, error]` iterator. The `event` parameter names the event type the daemon will stream for this command. ```APIDOC ## Session.CallStreaming ### Description Send a streaming command and iterate over events. Used for vici commands that stream events during execution (e.g., `list-sas`, `list-conns`, `initiate`). Returns an `iter.Seq2[*Message, error]` iterator. The `event` parameter names the event type the daemon will stream for this command. ### Method Signature `func (s *Session) CallStreaming(ctx context.Context, command string, event string, in *Message) <-chan *Message` ### Parameters - `ctx` (context.Context): Context for the operation. - `command` (string): The VICI command to execute. - `event` (string): The name of the event type to stream. - `in` (*vici.Message): Optional input message for the command. ### Returns - `<-chan *vici.Message`: A channel that streams VICI messages (events). ### Example ```go // Optionally filter by IKE SA name var in *vici.Message if ike != "" { in = vici.NewMessage() if err := in.Set("ike", ike); err != nil { return err } } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) def cancel() // Ensure cancel is called // "list-conns" streams "list-conn" events until complete for m, err := range s.CallStreaming(ctx, "list-conns", "list-conn", in) { if err != nil { return err } fmt.Println(m) } ``` ``` -------------------------------- ### Message.Keys Source: https://context7.com/strongswan/govici/llms.txt Returns a list of all keys present in the Message in their order of insertion. ```APIDOC ## Message.Keys — List all keys in a Message ### Description Returns a copy of the ordered key list for the message. ### Usage ```go m, _ := s.Call(ctx, "version", nil) for _, key := range m.Keys() { fmt.Printf("%s = %v\n", key, m.Get(key)) } // daemon = charon-systemd // version = 5.9.13 // sysname = Linux // release = 6.14.0-29-generic // machine = x86_64 ``` ``` -------------------------------- ### NewMessage Source: https://context7.com/strongswan/govici/llms.txt Creates a new, empty Message object that can be populated with fields. ```APIDOC ## NewMessage — Create an empty Message ### Description Returns a new, empty `*Message` ready to have fields set on it. Used to build command input messages manually. ### Usage ```go m := vici.NewMessage() if err := m.Set("ike", "my-connection"); err != nil { panic(err) } if err := m.Set("child", "my-child-sa"); err != nil { panic(err) } ``` ``` -------------------------------- ### Unsubscribe from All Events with `Session.UnsubscribeAll` Source: https://context7.com/strongswan/govici/llms.txt Removes all active event subscriptions for the session. ```Go if err := s.UnsubscribeAll(); err != nil { fmt.Println("Error:", err) } ``` -------------------------------- ### MarshalMessage Source: https://context7.com/strongswan/govici/llms.txt Encodes a Go struct or map into a vici Message object, using struct tags for key mapping. ```APIDOC ## MarshalMessage — Encode a Go struct or map into a Message ### Description Converts a struct (or pointer to struct) or map into a `*Message`. Only exported struct fields with a `vici` struct tag are marshaled. The tag value defines the message key name. Fields that would produce an empty message element are omitted. Embedded structs can be inlined with the `vici:",inline"` tag option. ### Usage ```go type cert struct { Type string `vici:"type"` Flag string `vici:"flag"` Data string `vici:"data"` } func loadX509Cert(s *vici.Session, pemData []byte) error { block, _ := pem.Decode(pemData) c := cert{ Type: "X509", Flag: "NONE", Data: string(block.Bytes), } in, err := vici.MarshalMessage(&c) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() resp, err := s.Call(ctx, "load-cert", in) if err != nil { return err } return resp.Err() } ``` ``` -------------------------------- ### Set Fields on a VICI Message Source: https://context7.com/strongswan/govici/llms.txt Add or update key-value pairs in a Message. Supports various types including strings, integers, booleans, slices, and nested messages. Booleans are converted to 'yes'/'no'. ```go m := vici.NewMessage() _ = m.Set("version", 2) // int → "2" _ = m.Set("enabled", true) // bool → "yes" _ = m.Set("proposals", []string{"aes128-sha256-x25519", "aes256-sha384-x25519"}) _ = m.Set("local_addrs", "192.168.0.1") fmt.Println(m) // { // version = 2 // enabled = yes // proposals = aes128-sha256-x25519,aes256-sha384-x25519 // local_addrs = 192.168.0.1 // } ``` -------------------------------- ### Event Subscription Source: https://context7.com/strongswan/govici/llms.txt Subscribing to events and processing them using the Event struct. Events carry the event name, payload, and timestamp. ```APIDOC ## Event Subscription ### Description Subscribes to events and processes them using the `Event` struct. The `Event` struct carries the event name, the associated message payload, and a timestamp of when the client received it. ### Usage ```go ec := make(chan vici.Event, 32) s.NotifyEvents(ec) s.Subscribe("child-updown") for e := range ec { fmt.Printf("[%s] Event: %s\n", e.Timestamp.Format(time.RFC3339), e.Name) // Access event payload fmt.Println(e.Message) } ``` ``` -------------------------------- ### Decode VICI Message to Go Struct Source: https://context7.com/strongswan/govici/llms.txt Use `UnmarshalMessage` to populate a Go struct from a `*Message`. Ensure exported fields have `vici` struct tags. Numeric types are parsed from strings, and booleans map 'yes'/'no'. ```go type versionInfo struct { Daemon string `vici:"daemon" Version string `vici:"version" SysName string `vici:"sysname" Release string `vici:"release" Machine string `vici:"machine" } func getVersion(s *vici.Session) (*versionInfo, error) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() m, err := s.Call(ctx, "version", nil) if err != nil { return nil, err } var info versionInfo if err := vici.UnmarshalMessage(m, &info); err != nil { return nil, err } // info.Daemon = "charon-systemd" // info.Version = "5.9.13" // info.Machine = "x86_64" return &info, nil } ``` -------------------------------- ### Session.NotifyEvents Source: https://context7.com/strongswan/govici/llms.txt Registers a `chan<- vici.Event` to receive events. Multiple channels can be registered independently; each receives its own copy of every event. If a write to the channel would block, the event is silently discarded — ensure the channel has sufficient buffer. The channel is closed when the session closes or the event listener exits. ```APIDOC ## Session.NotifyEvents ### Description Registers a `chan<- vici.Event` to receive events. Multiple channels can be registered independently; each receives its own copy of every event. If a write to the channel would block, the event is silently discarded — ensure the channel has sufficient buffer. The channel is closed when the session closes or the event listener exits. ### Method Signature `func (s *Session) NotifyEvents(ec chan<- Event)` ### Parameters - `ec` (chan<- vici.Event): The channel to send events to. ### Example ```go ec := make(chan vici.Event, 16) s.NotifyEvents(ec) // ... later, stop receiving events on this channel s.StopEvents(ec) ``` ``` -------------------------------- ### Define Go struct for child SA Source: https://github.com/strongswan/govici/blob/master/docs/getting_started.md Define a Go struct `childSA` to represent the child Security Association (SA) configuration, including traffic selectors and proposals. ```go type childSA struct { LocalTrafficSelectors []string `vici:"local_ts"` Updown string `vici:"updown"` ESPProposals []string `vici:"esp_proposals"` } ``` -------------------------------- ### Message.Get Source: https://context7.com/strongswan/govici/llms.txt Retrieves a field's value from a Message by its key. Returns the value as `any`, which needs to be type-asserted. ```APIDOC ## Message.Get — Retrieve a field from a Message ### Description Returns the value associated with the given key as `any`. The underlying type is always one of `string`, `[]string`, or `*Message`. Returns `nil` if the key does not exist. Type-assert the result for use. ### Usage ```go m, _ := s.Call(ctx, "version", nil) daemon := m.Get("daemon").(string) fmt.Println("Daemon:", daemon) // e.g., "charon-systemd" // For sub-sections, the type is *vici.Message sas, _ := s.Call(ctx, "stats", nil) ikeSAs := sas.Get("ikesas").(*vici.Message) fmt.Println(ikeSAs) ``` ``` -------------------------------- ### Retrieve Fields from a VICI Message Source: https://context7.com/strongswan/govici/llms.txt Access message fields by key, returning the value as 'any'. The underlying type will be string, []string, or *vici.Message. Type assertion is required for use. ```go m, _ := s.Call(ctx, "version", nil) daemon := m.Get("daemon").(string) fmt.Println("Daemon:", daemon) // e.g., "charon-systemd" // For sub-sections, the type is *vici.Message sas, _ := s.Call(ctx, "stats", nil) ikeSAs := sas.Get("ikesas").(*vici.Message) fmt.Println(ikeSAs) ``` -------------------------------- ### Session.Close - Close the session Source: https://context7.com/strongswan/govici/llms.txt Closes the underlying connection to the charon daemon. Always defer this after a successful `NewSession`. ```APIDOC ## Session.Close ### Description Closes the underlying connection to the charon daemon. ### Method `(*Session) Close() error` ### Returns - `error`: An error if closing the connection fails, otherwise `nil`. ### Example ```go s, err := vici.NewSession() if err != nil { panic(err) } defer s.Close() // Ensures cleanup on function exit ``` ``` -------------------------------- ### Close the vici session Source: https://context7.com/strongswan/govici/llms.txt Closes the underlying connection to the charon daemon. Always defer this after a successful `NewSession`. ```go s, err := vici.NewSession() if err != nil { panic(err) } deferr s.Close() // Ensures cleanup on function exit ``` -------------------------------- ### Unsubscribe from Specific Events with `Session.Unsubscribe` Source: https://context7.com/strongswan/govici/llms.txt Stop receiving specific event types. Returns an error if any specified event name is not currently registered. ```Go // Stop listening for log events but keep ike-updown if err := s.Unsubscribe("log"); err != nil { fmt.Println("Unsubscribe error:", err) } ```