The strongSwan vici protocol is used for external applications to monitor, configure, and control the IKE daemon charon. This Go package provides a pure-go implementation of a vici client library.
The package documentation can be found on godoc.
go get -u github.com/strongswan/govici
Below are some examples of how to use vici.Session
. For a complete list of supported commands, message parameters, and event types, see the vici README.
This example shows how a command request can be made to get version information about the running charon daemon. The first argument to CommandRequest
is the command name. No additional arguments are required, so nil
is given. Iterating over the response Message
's keys will give all information returned by the daemon.
package main
import (
"fmt"
"github.com/strongswan/govici"
)
func main() {
session, err := vici.NewSession()
if err != nil {
fmt.Println(err)
return
}
m, err := session.CommandRequest("version", nil)
if err != nil {
fmt.Println(err)
return
}
for _, k := range m.Keys() {
fmt.Printf("%v: %v\n", k, m.Get(k))
}
}
This example shows how CommandRequest
can be used to get a list of connection names that have been loaded over vici. Note that Get
returns interface{}
, so a type assertion is needed to iterate over the items returned in the "conns"
field.
package main
import (
"fmt"
"github.com/strongswan/govici"
)
func main() {
session, err := vici.NewSession()
if err != nil {
fmt.Println(err)
return
}
m, err := session.CommandRequest("get-conns", nil)
if err != nil {
fmt.Println(err)
return
}
conns := m.Get("conns")
if conns == nil {
fmt.Println("Expected connections field in message")
return
}
for _, conn := range conns.([]string) {
fmt.Println(conn)
}
}
Use Set
to populate a Message
with the arguments needed for a command. Here, the command "install"
accepts a child SA name and an optional IKE SA name to find the child under. The success of the command can be checked using Err
.
package main
import (
"fmt"
"github.com/strongswan/govici"
)
func main() {
session, err := vici.NewSession()
if err != nil {
fmt.Println(err)
return
}
m := vici.NewMessage()
err = m.Set("child", "child_sa_name")
if err != nil {
fmt.Println(err)
return
}
err = m.Set("ike", "ike_sa_name")
if err != nil {
fmt.Println(err)
return
}
resp, err := session.CommandRequest("install", m)
if err != nil {
fmt.Println(err)
return
}
if resp.Err() != nil {
fmt.Println("Command failed:", err)
}
fmt.Println("Command succeeded")
}
This example shows how to use StreamedCommandRequest
. The command "initiate"
initiates an SA while streaming "control-log"
events. A MessageStream
is returned after all messages have been received, and the session has stopped listening for "control-log"
events (unless otherwise specified using Listen
).
This also shows how MarshalMessage
can be used to construct a Message
from a struct by using struct tags.
package main
import (
"fmt"
"github.com/strongswan/govici"
)
type initiateOptions struct {
child string `vici:"child"`
ike string `vici:"ike"`
timeout string `vici:"timeout"`
initLimits string `vici:"init-limits"`
logLevel string `vici:"loglevel"`
}
func main() {
session, err := vici.NewSession()
if err != nil {
fmt.Println(err)
return
}
initOpts := initiateOptions{}
// Populate struct
//
// ...
//
m, err := vici.MarshalMessage(initOpts)
if err != nil {
fmt.Println(err)
return
}
ms, err := session.StreamedCommandRequest("initiate", "control-log", m)
if err != nil {
fmt.Println(err)
return
}
for _, m := range ms.Messages() {
fmt.Println(m)
}
fmt.Println("Initiated SA")
}
This example shows a session that registers for "ike-updown"
and "child-updown"
events. Listen
does not return unless the event channel is closed, so it should be run in another goroutine. Events received by the listener are given by NextEvent
. If there is no event in the buffer at the time NextEvent
is called, it will block until an event is received.
package main
import (
"fmt"
"github.com/strongswan/govici"
)
func main() {
session, err := vici.NewSession()
if err != nil {
fmt.Println(err)
return
}
events := []string{"ike-updown", "child-updown"}
go session.Listen(events)
for {
m, err := session.NextEvent()
if err != nil {
fmt.Print(err)
continue
}
fmt.Println(m)
}
}