Skip to content

Commit

Permalink
Merge pull request #121 from telekom-mms/feature/add-method-dumpstate…
Browse files Browse the repository at this point in the history
…-to-dbus-api

Add method "DumpState" to D-Bus API
  • Loading branch information
hwipl authored Sep 5, 2024
2 parents 96e12e5 + 8e129f7 commit f9d91de
Show file tree
Hide file tree
Showing 27 changed files with 788 additions and 53 deletions.
4 changes: 4 additions & 0 deletions configs/dbus/com.telekom_mms.oc_daemon.Daemon.conf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<allow send_destination="com.telekom_mms.oc_daemon.Daemon"
send_interface="com.telekom_mms.oc_daemon.Daemon"
send_member="Disconnect"/>

<allow send_destination="com.telekom_mms.oc_daemon.Daemon"
send_interface="com.telekom_mms.oc_daemon.Daemon"
send_member="DumpState"/>
</policy>

<policy context="default">
Expand Down
18 changes: 18 additions & 0 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,24 @@ func getStatus() error {
return printStatus(status)
}

// dumpState dumps the internal state of the daemon.
func dumpState() error {
// create client
c, err := clientNewClient(config)
if err != nil {
return fmt.Errorf("error creating client: %w", err)
}
defer func() { _ = c.Close() }()

// get status
state, err := c.DumpState()
if err != nil {
return fmt.Errorf("error getting status: %w", err)
}
fmt.Println(state)
return nil
}

// monitor subscribes to VPN status updates from the daemon and displays them.
func monitor() error {
// create client
Expand Down
35 changes: 35 additions & 0 deletions internal/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
type testClient struct {
querErr error
status *vpnstatus.Status
dumpErr error
dumpSta string
authErr error
connErr error
discErr error
Expand All @@ -33,6 +35,7 @@ func (t *testClient) Subscribe() (chan *vpnstatus.Status, error) { return t.subs
func (t *testClient) Authenticate() error { return t.authErr }
func (t *testClient) Connect() error { return t.connErr }
func (t *testClient) Disconnect() error { return t.discErr }
func (t *testClient) DumpState() (string, error) { return t.dumpSta, t.dumpErr }
func (t *testClient) Close() error { return nil }

// TestListServers tests listServers.
Expand Down Expand Up @@ -205,6 +208,38 @@ func TestGetStatus(t *testing.T) {
}
}

// TestDumpState tests dumpState.
func TestDumpState(t *testing.T) {
defer func() { clientNewClient = client.NewClient }()

// test with client error
clientNewClient = func(*client.Config) (client.Client, error) {
return nil, errors.New("test error")
}

if err := dumpState(); err == nil {
t.Error("client error should return error")
}

// test with dump state error
clientNewClient = func(*client.Config) (client.Client, error) {
return &testClient{dumpErr: errors.New("test error")}, nil
}

if err := dumpState(); err == nil {
t.Error("dump state error should return error")
}

// test without error
clientNewClient = func(*client.Config) (client.Client, error) {
return &testClient{dumpSta: "test state"}, nil
}

if err := dumpState(); err != nil {
t.Error("dump state should not return error")
}
}

// TestMonitor tests monitor.
func TestMonitor(t *testing.T) {
defer func() { clientNewClient = client.NewClient }()
Expand Down
2 changes: 2 additions & 0 deletions internal/client/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ func run(args []string) error {
return reconnectVPN()
case "status":
return getStatus()
case "dumpstate":
return dumpState()
case "monitor":
return monitor()
case "save":
Expand Down
1 change: 1 addition & 0 deletions internal/client/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func TestRun(t *testing.T) {
"reconnect",
"status",
"monitor",
"dumpstate",
} {
if err := run([]string{"test",
"-cert", "cert-file",
Expand Down
34 changes: 34 additions & 0 deletions internal/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package daemon

import (
"context"
"encoding/json"
"fmt"
"net"
"net/netip"
Expand Down Expand Up @@ -473,6 +474,33 @@ func (d *Daemon) handleClientRequest(request *api.Request) {
}
}

// dumpState returns the internal daemon state as json string.
func (d *Daemon) dumpState() string {
// define state type
type State struct {
TrafficPolicing *trafpol.State
VPNSetup *vpnsetup.State
}

// collect internal state
state := State{}
if d.trafpol != nil {
state.TrafficPolicing = d.trafpol.GetState()
}
if d.vpnsetup != nil {
state.VPNSetup = d.vpnsetup.GetState()
}

// convert to json
b, err := json.Marshal(state)
if err != nil {
log.WithError(err).Error("Daemon could not convert internal state to JSON")
return ""
}

return string(b)
}

// handleDBusRequest handles a D-Bus API client request.
func (d *Daemon) handleDBusRequest(request *dbusapi.Request) {
defer request.Close()
Expand Down Expand Up @@ -505,6 +533,12 @@ func (d *Daemon) handleDBusRequest(request *dbusapi.Request) {
// diconnect VPN
log.Info("Daemon got disconnect request from client")
d.disconnectVPN()

case dbusapi.RequestDumpState:
// dump state
state := d.dumpState()
log.WithField("state", state).Info("Daemon got dump state request from client")
request.Results = []any{state}
}
}

Expand Down
41 changes: 33 additions & 8 deletions internal/dbusapi/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,14 @@ const (
const (
MethodConnect = Interface + ".Connect"
MethodDisconnect = Interface + ".Disconnect"
MethodDumpState = Interface + ".DumpState"
)

// Request Names.
const (
RequestConnect = "Connect"
RequestDisconnect = "Disconnect"
RequestDumpState = "DumpState"
)

// Request is a D-Bus client request.
Expand Down Expand Up @@ -212,6 +214,27 @@ func (d daemon) Disconnect(sender dbus.Sender) *dbus.Error {
return nil
}

// DumpState is the "DumpState" method of the D-Bus interface.
func (d daemon) DumpState(sender dbus.Sender) (string, *dbus.Error) {
log.WithField("sender", sender).Debug("Received D-Bus DumpState() call")
request := &Request{
Name: RequestDumpState,
wait: make(chan struct{}),
done: d.done,
}
select {
case d.requests <- request:
case <-d.done:
return "", dbus.NewError(Interface+".DumpStateAborted", []any{"DumpState aborted"})
}

request.Wait()
if request.Error != nil {
return "", dbus.NewError(Interface+".DumpStateAborted", []any{request.Error.Error()})
}
return request.Results[0].(string), nil
}

// propertyUpdate is an update of a property.
type propertyUpdate struct {
name string
Expand Down Expand Up @@ -431,16 +454,18 @@ func (s *Service) Start() error {
// set names of method arguments
introMeths := introspect.Methods(meths)
for _, m := range introMeths {
if m.Name != "Connect" {
continue
if m.Name == "Connect" {
m.Args[0].Name = "server"
m.Args[1].Name = "cookie"
m.Args[2].Name = "host"
m.Args[3].Name = "connect_url"
m.Args[4].Name = "fingerprint"
m.Args[5].Name = "resolve"
}
m.Args[0].Name = "server"
m.Args[1].Name = "cookie"
m.Args[2].Name = "host"
m.Args[3].Name = "connect_url"
m.Args[4].Name = "fingerprint"
m.Args[5].Name = "resolve"

if m.Name == "DumpState" {
m.Args[0].Name = "state"
}
}
// set peer interface
peerData := introspect.Interface{
Expand Down
67 changes: 67 additions & 0 deletions internal/dbusapi/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,73 @@ func TestDaemonDisconnect(t *testing.T) {
}
}

// TestDaemonDumpStateErrors tests DumpState of daemon, errors.
func TestDaemonDumpStateErrors(t *testing.T) {
// create daemon
requests := make(chan *Request)
done := make(chan struct{})
daemon := daemon{
requests: requests,
done: done,
}

// error when handling request
go func() {
r := <-requests
r.Error = errors.New("test error")
r.Close()
}()
if _, err := daemon.DumpState(""); err == nil {
t.Error("should return error")
}

// closed daemon
close(done)
if _, err := daemon.DumpState(""); err == nil {
t.Error("should return error")
}
}

// TestDaemonDumpState tests DumpState of daemon.
func TestDaemonDumpState(t *testing.T) {
// create daemon
requests := make(chan *Request)
done := make(chan struct{})
daemon := daemon{
requests: requests,
done: done,
}

// run disconnect and get results
want := &Request{
Name: RequestDumpState,
Results: []any{"test state"},
done: done,
}
got := &Request{}
go func() {
r := <-requests
r.Results = append(r.Results, "test state")
got = r
r.Close()
}()
state, err := daemon.DumpState("sender")
if err != nil {
t.Error(err)
}

// check results
if got.Name != want.Name ||
!reflect.DeepEqual(got.Parameters, want.Parameters) ||
!reflect.DeepEqual(got.Results, want.Results) ||
got.Error != want.Error ||
got.done != want.done ||
state != "test state" {
// not equal
t.Errorf("got %v, want %v", got, want)
}
}

// testConn implements the dbusConn interface for testing.
type testConn struct {
reqNameReply dbus.RequestNameReply
Expand Down
19 changes: 19 additions & 0 deletions internal/dnsproxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ import (
log "github.com/sirupsen/logrus"
)

// State is the internal state of the DNS Proxy.
type State struct {
Config *Config
Remotes map[string][]string
Watches []string
TempWatches []string
}

// Proxy is a DNS proxy.
type Proxy struct {
config *Config
Expand Down Expand Up @@ -247,6 +255,17 @@ func (p *Proxy) SetWatches(watches []string) {
}
}

// GetState returns the internal state of the DNS Proxy.
func (p *Proxy) GetState() *State {
watches, tempWatches := p.watches.List()
return &State{
Config: p.config,
Remotes: p.remotes.List(),
Watches: watches,
TempWatches: tempWatches,
}
}

// NewProxy returns a new Proxy that listens on address.
func NewProxy(config *Config) *Proxy {
var udp *dns.Server
Expand Down
29 changes: 29 additions & 0 deletions internal/dnsproxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"net"
"net/netip"
"reflect"
"testing"

"github.com/miekg/dns"
Expand Down Expand Up @@ -272,6 +273,34 @@ func TestProxySetWatches(_ *testing.T) {
p.SetWatches(watches)
}

// TestProxyGetState tests GetState of Proxy.
func TestProxyGetState(t *testing.T) {
p := NewProxy(getTestConfig())

// set remotes
getRemotes := func() map[string][]string {
return map[string][]string{".": {"192.168.1.1"}}
}
p.SetRemotes(getRemotes())

// set watches
p.watches.Add("example.com.")
p.watches.AddTempCNAME("cname.example.com.", 300)
p.watches.AddTempDNAME("dname.example.com.", 300)

// check state
want := &State{
Config: getTestConfig(),
Remotes: getRemotes(),
Watches: []string{"example.com."},
TempWatches: []string{"cname.example.com.", "dname.example.com."},
}
got := p.GetState()
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}

// TestNewProxy tests NewProxy.
func TestNewProxy(t *testing.T) {
p := NewProxy(getTestConfig())
Expand Down
Loading

0 comments on commit f9d91de

Please sign in to comment.