diff --git a/ZitiTunneler/MainWindow.xaml b/ZitiTunneler/MainWindow.xaml
index 9465d0d9..2d3c3770 100644
--- a/ZitiTunneler/MainWindow.xaml
+++ b/ZitiTunneler/MainWindow.xaml
@@ -147,5 +147,6 @@
+
diff --git a/ZitiTunneler/MainWindow.xaml.cs b/ZitiTunneler/MainWindow.xaml.cs
index be53804b..1b7ffffd 100644
--- a/ZitiTunneler/MainWindow.xaml.cs
+++ b/ZitiTunneler/MainWindow.xaml.cs
@@ -71,6 +71,7 @@ namespace ZitiTunneler {
// add a new service client
serviceClient = new Client();
+ serviceClient.OnTunnelStatusUpdate += ServiceClient_OnTunnelStatusUpdated;
Application.Current.Properties.Add("ServiceClient", serviceClient);
Application.Current.Properties.Add("Identities", new List());
MainMenu.OnAttachmentChange += AttachmentChanged;
@@ -85,8 +86,12 @@ namespace ZitiTunneler {
IdentityMenu.OnForgot += IdentityForgotten;
}
+ private void ServiceClient_OnTunnelStatusUpdated(object sender, TunnelStatus e)
+ {
+ }
+
private void IdentityForgotten(ZitiIdentity forgotten) {
- ZitiTunnelStatus status = serviceClient.GetStatus();
+ TunnelStatus status = serviceClient.GetStatus().Status;
identities.Clear();
foreach (var id in status.Identities) {
var zid = ZitiIdentity.FromClient(id);
@@ -112,7 +117,7 @@ namespace ZitiTunneler {
}
private void LoadStatusFromService() {
- ZitiTunnelStatus status = serviceClient.GetStatus();
+ TunnelStatus status = serviceClient.GetStatus().Status;
if (status != null) {
if (status.Active) {
InitializeTimer((int)status.Duration);
@@ -257,5 +262,10 @@ namespace ZitiTunneler {
e.Cancel = true;
}
}
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ //
+ }
}
}
diff --git a/ZitiTunneler/ServiceClient/ClientImpl.cs b/ZitiTunneler/ServiceClient/ClientImpl.cs
index 5f570679..5065a197 100644
--- a/ZitiTunneler/ServiceClient/ClientImpl.cs
+++ b/ZitiTunneler/ServiceClient/ClientImpl.cs
@@ -6,7 +6,8 @@ using System.Security.Principal;
using System.Security.AccessControl;
using Newtonsoft.Json;
-
+using System.Threading;
+using System.Threading.Tasks;
///
/// The implementation will abstract away the setup of the communication to
@@ -19,13 +20,35 @@ using Newtonsoft.Json;
///
namespace ZitiTunneler.ServiceClient
{
+
internal class Client
{
+ public event EventHandler OnTunnelStatusUpdate;
+ public event EventHandler OnMetricsUpdate;
+
+ protected virtual void ZitiTunnelStatusUpdate(TunnelStatus e)
+ {
+ EventHandler handler = OnTunnelStatusUpdate;
+ if (handler != null)
+ {
+ handler(this, e);
+ }
+ }
+ protected virtual void MetricsUpdate(Metrics e)
+ {
+ EventHandler handler = OnMetricsUpdate;
+ if (handler != null)
+ {
+ handler(this, e);
+ }
+ }
+
JsonSerializer serializer = new JsonSerializer();
private object namedPipeSyncLock = new object();
const string ipcPipe = @"NetFoundry\tunneler\ipc";
const string logPipe = @"NetFoundry\tunneler\logs";
+ const string eventPipe = @"NetFoundry\tunneler\events";
const string localPipeServer = ".";
const PipeDirection inOut = PipeDirection.InOut;
const int ServiceConnectTimeout = 500;
@@ -38,6 +61,23 @@ namespace ZitiTunneler.ServiceClient
{
//establish the named pipe to the service
setupPipe();
+
+ Task.Run(() => {
+ Console.WriteLine("THREAD BEGINS");
+ NamedPipeClientStream eventClient = new NamedPipeClientStream(localPipeServer, eventPipe, PipeDirection.In);
+ eventClient.Connect();
+ StreamReader eventReader = new StreamReader(eventClient);
+ while (true)
+ {
+ var r = read("event: ", eventReader);
+ if (eventReader.EndOfStream)
+ {
+ break;
+ }
+ Debug.WriteLine(r.Payload);
+ }
+ Console.WriteLine("THREAD DONE");
+ });
}
PipeSecurity CreateSystemIOPipeSecurity()
{
@@ -91,7 +131,7 @@ namespace ZitiTunneler.ServiceClient
try
{
send(new ServiceFunction() { Function = "Status" });
- var rtn = read();
+ var rtn = read(" ipc: ", ipcReader);
return rtn;
}
catch (IOException ioe)
@@ -124,7 +164,7 @@ namespace ZitiTunneler.ServiceClient
send(AddIdentityFunction);
send(newId);
- var resp = read();
+ var resp = read(" ipc: ", ipcReader);
Debug.WriteLine(resp.ToString());
return resp.Payload;
@@ -154,7 +194,7 @@ namespace ZitiTunneler.ServiceClient
Payload = new FingerprintPayload() { Fingerprint = fingerPrint }
};
send(removeFunction);
- var r = read();
+ var r = read(" ipc: ", ipcReader);
}
catch (IOException ioe)
{
@@ -169,7 +209,7 @@ namespace ZitiTunneler.ServiceClient
try
{
send(new BooleanFunction("TunnelState", onOff));
- read();
+ read(" ipc: ", ipcReader);
}
catch (IOException ioe)
{
@@ -206,7 +246,7 @@ namespace ZitiTunneler.ServiceClient
try
{
send(new IdentityToggleFunction(fingerprint, onOff));
- IdentityResponse idr = read();
+ IdentityResponse idr = read(" ipc: ", ipcReader);
return idr.Payload;
}
catch (IOException ioe)
@@ -271,33 +311,33 @@ namespace ZitiTunneler.ServiceClient
}
}
- private T read() where T : SvcResponse
+ private T read(string prefix, StreamReader reader) where T : SvcResponse
{
try
{
int emptyCount = 1;
- Debug.WriteLine("=============== reading message =============== " + emptyCount);
- string respAsString = ipcReader.ReadLine();
+ Debug.WriteLine(prefix + "=============== reading message =============== " + emptyCount);
+ string respAsString = reader.ReadLine();
Debug.WriteLine(respAsString);
- Debug.WriteLine("=============== read message =============== " + emptyCount);
+ Debug.WriteLine(prefix + "=============== read message =============== " + emptyCount);
while (string.IsNullOrEmpty(respAsString?.Trim()))
{
//T resp = (T)serializer.Deserialize(reader, typeof(T));
- if (ipcReader.EndOfStream)
+ if (reader.EndOfStream)
{
throw new Exception("the pipe has closed");
}
Debug.WriteLine("Received empty payload - continuing to read until a payload is received");
//now how'd that happen...
- Debug.WriteLine("=============== reading message =============== " + emptyCount);
- respAsString = ipcReader.ReadLine();
+ Debug.WriteLine(prefix + "=============== reading message =============== " + emptyCount);
+ respAsString = reader.ReadLine();
Debug.WriteLine(respAsString);
- Debug.WriteLine("=============== read message =============== " + emptyCount);
+ Debug.WriteLine(prefix + "=============== read message =============== " + emptyCount);
emptyCount++;
if (emptyCount > 5)
{
- Debug.WriteLine("are we there yet? " + ipcReader.EndOfStream);
+ Debug.WriteLine("are we there yet? " + reader.EndOfStream);
//that's just too many...
setupPipe();
return null;
@@ -320,6 +360,11 @@ namespace ZitiTunneler.ServiceClient
setupPipe();
throw ioe;
}
+ catch (Exception ee)
+ {
+ //almost certainly a problem with the pipe - recreate the pipe...
+ throw ee;
+ }
}
}
}
\ No newline at end of file
diff --git a/ZitiTunneler/ServiceClient/DataStructures.cs b/ZitiTunneler/ServiceClient/DataStructures.cs
index c612a4f4..10efb41d 100644
--- a/ZitiTunneler/ServiceClient/DataStructures.cs
+++ b/ZitiTunneler/ServiceClient/DataStructures.cs
@@ -19,6 +19,18 @@ namespace ZitiTunneler.ServiceClient
}
}
+ class StatusUpdateResponse : SvcResponse
+ {
+ public StatusUpdate Payload { get; set; }
+ }
+
+ class StatusUpdate
+ {
+ public string Operation { get; set; }
+ public TunnelStatus Status { get; set; }
+ public Metrics Metrics { get; set; }
+ }
+
public class NewIdentity
{
public EnrollmentFlags Flags { get; set; }
@@ -96,6 +108,8 @@ namespace ZitiTunneler.ServiceClient
public class Metrics
{
public int TotalBytes { get; set; }
+ public double Upload { get; set; }
+ public double Download { get; set; }
}
public class Identity
@@ -132,6 +146,11 @@ namespace ZitiTunneler.ServiceClient
}
class ZitiTunnelStatus : SvcResponse
+ {
+ public TunnelStatus Status { get; set; }
+ }
+
+ class TunnelStatus
{
public bool Active { get; set; }
diff --git a/wintun-testing/go.mod b/wintun-testing/go.mod
index c5372e9d..70695225 100644
--- a/wintun-testing/go.mod
+++ b/wintun-testing/go.mod
@@ -15,8 +15,8 @@ require (
github.com/netfoundry/ziti-sdk-golang v0.11.16
github.com/sirupsen/logrus v1.5.0
github.com/tebeka/strftime v0.1.4 // indirect
+ github.com/tv42/topic v0.0.0-20130729201830-aa72cbe81b48
golang.org/x/sys v0.0.0-20200406113430-c6e801f48ba2
golang.zx2c4.com/wireguard v0.0.20200320
golang.zx2c4.com/wireguard/windows v0.1.0
- gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
diff --git a/wintun-testing/go.sum b/wintun-testing/go.sum
index 3197386c..26f50c29 100644
--- a/wintun-testing/go.sum
+++ b/wintun-testing/go.sum
@@ -106,6 +106,8 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tebeka/strftime v0.1.4 h1:e0FKSyxthD1Xk4cIixFPoyfD33u2SbjNngOaaC3ePoU=
github.com/tebeka/strftime v0.1.4/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
+github.com/tv42/topic v0.0.0-20130729201830-aa72cbe81b48 h1:4HadKLQh7sw8SobBMRWhMOZXHm+Nyx+c9xfhJlWEI2Y=
+github.com/tv42/topic v0.0.0-20130729201830-aa72cbe81b48/go.mod h1:b4JA15yUof03YRQ6IiKevPk2syaMBMJb92x9PeyU+Xc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -164,8 +166,6 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/wintun-testing/ziti-tunnel/dto/dtos.go b/wintun-testing/ziti-tunnel/dto/dtos.go
index b5b6cbde..2a34b3dd 100644
--- a/wintun-testing/ziti-tunnel/dto/dtos.go
+++ b/wintun-testing/ziti-tunnel/dto/dtos.go
@@ -1,11 +1,9 @@
package dto
import (
- "log"
-
- "github.com/netfoundry/ziti-sdk-golang/ziti/enroll"
-
idcfg "github.com/netfoundry/ziti-sdk-golang/ziti/config"
+ "github.com/netfoundry/ziti-sdk-golang/ziti/enroll"
+ "log"
"wintun-testing/ziti-tunnel/config"
)
@@ -44,11 +42,12 @@ type Response struct {
Error string
Payload interface{} `json:"Payload"`
}
-type ZitiTunnelStatus struct {
- Code int
- Message string
- Error string
- Payload Identity
+
+type TunIpInfo struct {
+ Ip string
+ Subnet string
+ MTU uint16
+ DNS string
}
func (id *Identity) Path() string {
@@ -57,3 +56,16 @@ func (id *Identity) Path() string {
}
return config.Path() + id.FingerPrint + ".json"
}
+
+
+type TunnelStatus struct {
+ Active bool
+ Duration int64 `json:"-"`
+ Identities []*Identity
+ IpInfo *TunIpInfo `json:"IpInfo,omitempty"`
+}
+
+type ZitiTunnelStatus struct {
+ Status *TunnelStatus `json:",omitempty"`
+ Metrics *Metrics `json:",omitempty"`
+}
diff --git a/wintun-testing/ziti-tunnel/main.go b/wintun-testing/ziti-tunnel/main.go
index 06d1fce6..2dd05b87 100644
--- a/wintun-testing/ziti-tunnel/main.go
+++ b/wintun-testing/ziti-tunnel/main.go
@@ -51,6 +51,7 @@ func main() {
cmd := strings.ToLower(os.Args[1])
switch cmd {
case "debug":
+ service.Debug = true
service.RunService(true)
return
case "install":
diff --git a/wintun-testing/ziti-tunnel/service/ipc.go b/wintun-testing/ziti-tunnel/service/ipc.go
index cb19fbe4..df6861b3 100644
--- a/wintun-testing/ziti-tunnel/service/ipc.go
+++ b/wintun-testing/ziti-tunnel/service/ipc.go
@@ -9,7 +9,6 @@ import (
"github.com/netfoundry/ziti-foundation/identity/identity"
"github.com/netfoundry/ziti-sdk-golang/ziti/enroll"
"golang.org/x/sys/windows/svc"
- "golang.org/x/sys/windows/svc/eventlog"
"io"
"io/ioutil"
"net"
@@ -17,62 +16,40 @@ import (
"strings"
"time"
"wintun-testing/cziti"
+ "wintun-testing/ziti-tunnel/globals"
"wintun-testing/cziti/windns"
"wintun-testing/ziti-tunnel/config"
"wintun-testing/ziti-tunnel/dto"
"wintun-testing/ziti-tunnel/idutil"
- "wintun-testing/ziti-tunnel/runtime"
)
+type Pipes struct {
+ ipc net.Listener
+ logs net.Listener
+ events net.Listener
+}
+
+func(p *Pipes) Close() {
+ p.ipc.Close()
+ p.logs.Close()
+ p.events.Close()
+}
func SubMain(ops <- chan string, changes chan<- svc.Status) error {
- log.Debug("")
- log.Debug("")
- log.Debug("===============================================================================")
- // open and assign the event log for this service
- Elog, err := eventlog.Open(SvcName)
- if err != nil {
- return err
- }
- _ = Elog.Info(InformationEvent, SvcName + " starting. log file located at " + config.LogFile())
+ defer close(top.Broadcast)
+ log.Info("============================== service begins ==============================")
+
+ _ = globals.Elog.Info(InformationEvent, SvcName + " starting. log file located at " + config.LogFile())
// create a channel for notifying any connections that they are to be interrupted
interrupt = make(chan struct{})
- // create the ACE string representing the following groups have access to the pipes created
- grps := []string{InteractivelyLoggedInUser, System, BuiltinAdmins, LocalService}
- auth := "D:" + strings.Join(grps, "")
-
- // create the pipes
- pc := winio.PipeConfig{
- SecurityDescriptor: auth,
- MessageMode: false,
- InputBufferSize: 1024,
- OutputBufferSize: 1024,
- }
- logs, err := winio.ListenPipe(logsPipeName, &pc)
+ pipes, err := openPipes()
if err != nil {
return err
}
- // listen for log requests
- go acceptLogs(logs)
- log.Infof("log listener ready. pipe: %s", logsPipeName)
-
- pc2 := winio.PipeConfig{
- SecurityDescriptor: auth,
- MessageMode: false,
- InputBufferSize: 1024,
- OutputBufferSize: 1024,
- }
- ipc, err := winio.ListenPipe(ipcPipeName, &pc2)
- if err != nil {
- return err
- }
-
- // listen for ipc messages
- go acceptIPC(ipc)
- log.Infof("ipc listener ready pipe: %s", ipcPipeName)
+ defer pipes.Close()
// wire in a log file for csdk troubleshooting
logFile, err := os.OpenFile(config.Path() + "cziti.log", os.O_WRONLY | os.O_TRUNC | os.O_APPEND | os.O_CREATE, 0644)
@@ -95,33 +72,80 @@ func SubMain(ops <- chan string, changes chan<- svc.Status) error {
// notify the service is running
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
- _ = Elog.Info(InformationEvent, SvcName + " status set to running")
+ _ = globals.Elog.Info(InformationEvent, SvcName + " status set to running")
log.Info(SvcName + " status set to running. starting cancel loop")
- loop:
- for {
- c := <-ops
- log.Infof("request for control received, %v", c)
- if c == "stop" {
- break loop
- } else {
- log.Debug("unexpected operation: " + c)
- }
- }
+ waitForStopRequest(ops)
- shutdownConnections()
+ pipes.shutdownConnections()
windns.ResetDNS()
- state.Close()
- _ = ipc.Close()
- _ = logs.Close()
- log.Info("shutdown complete. exiting process")
+ rts.Close()
+
+ log.Info("============================== service ends ==============================")
return nil
}
+func waitForStopRequest(ops <- chan string) {
-func shutdownConnections() {
+loop:
+ for {
+ c := <-ops
+ log.Infof("request for control received, %v", c)
+ if c == "stop" {
+ break loop
+ } else {
+ log.Debug("unexpected operation: " + c)
+ }
+ }
+}
+
+func openPipes() (*Pipes, error) {
+ // create the ACE string representing the following groups have access to the pipes created
+ grps := []string{InteractivelyLoggedInUser, System, BuiltinAdmins, LocalService}
+ auth := "D:" + strings.Join(grps, "")
+
+ // create the pipes
+ pc := winio.PipeConfig{
+ SecurityDescriptor: auth,
+ MessageMode: false,
+ InputBufferSize: 1024,
+ OutputBufferSize: 1024,
+ }
+ logs, err := winio.ListenPipe(logsPipeName(), &pc)
+ if err != nil {
+ return nil, err
+ }
+ ipc, err := winio.ListenPipe(ipcPipeName(), &pc)
+ if err != nil {
+ return nil, err
+ }
+ events, err := winio.ListenPipe(eventsPipeName(), &pc)
+ if err != nil {
+ return nil, err
+ }
+
+ // listen for log requests
+ go accept(logs, serveLogs)
+ log.Infof("log listener ready. pipe: %s", logsPipeName())
+
+ // listen for ipc messages
+ go accept(ipc, serveIpc)
+ log.Infof("ipc listener ready pipe: %s", ipcPipeName())
+
+ // listen for events messages
+ go accept(events, serveEvents)
+ log.Infof("events listener ready pipe: %s", eventsPipeName())
+
+ return &Pipes{
+ ipc: ipc,
+ logs: logs,
+ events: events,
+ }, nil
+}
+
+func(p *Pipes) shutdownConnections() {
log.Info("waiting for all connections to close...")
for i := 0; i < connections; i++ {
@@ -132,7 +156,46 @@ func shutdownConnections() {
log.Info("all connections closed")
}
-func acceptIPC(p net.Listener) {
+func initialize() error {
+ rts.LoadConfig()
+
+ err := rts.CreateTun()
+ if err != nil {
+ return err
+ }
+ setTunInfo(rts.state)
+
+ s := rts.state
+ // decide if the tunnel should be active or not and if so - activate it
+ setTunnelState(s.Active)
+
+ // connect any identities that are enabled
+ for _, id := range s.Identities {
+ connectIdentity(id)
+ }
+
+ log.Debugf("initial state loaded from configuration file")
+ return nil
+}
+
+func setTunInfo(s *dto.TunnelStatus) {
+ //set the tun info into the state
+ s.IpInfo = &dto.TunIpInfo{
+ Ip: Ipv4ip,
+ DNS: Ipv4dns,
+ MTU: 1400,
+ Subnet: "255.255.255.0",
+ }
+}
+
+func closeConn(conn net.Conn) {
+ err := conn.Close()
+ if err != nil {
+ log.Warnf("abnormal error while closing connection. %v", err)
+ }
+}
+
+func accept(p net.Listener, serveFunction func(net.Conn)) {
for {
c, err := p.Accept()
if err != nil {
@@ -145,60 +208,7 @@ func acceptIPC(p net.Listener) {
connections ++
log.Debugf("accepting a new client")
- go serveIpc(c)
- }
-}
-
-func initialize() error {
- log.Debugf("reading config file located at: %s", config.File())
- file, err := os.OpenFile(config.File(), os.O_RDONLY, 0644)
- if err != nil {
- // file does not exist or process has no rights to read the file - return leaving configuration empty
- // this is expected when first starting
- return nil
- }
-
- r := bufio.NewReader(file)
- dec := json.NewDecoder(r)
-
- _ = dec.Decode(&state)
-
- err = state.CreateTun()
- if err != nil {
- return err
- }
- setTunInfo()
-
- // decide if the tunnel should be active or not and if so - activate it
- setTunnelState(state.Active)
-
- // connect any identities that are enabled
- for _, id := range state.Identities {
- connectIdentity(id)
- }
-
- err = file.Close()
- if err != nil {
- return fmt.Errorf("could not close configuration file. this is not normal! %v", err)
- }
- log.Debugf("initial state loaded from configuration file")
- return nil
-}
-
-func setTunInfo() {
- //set the tun info into the state
- state.IpInfo = &runtime.TunIpInfo{
- Ip: runtime.Ipv4ip,
- DNS: runtime.Ipv4dns,
- MTU: 1400,
- Subnet: "255.255.255.0",
- }
-}
-
-func closeConn(conn net.Conn) {
- err := conn.Close()
- if err != nil {
- log.Warnf("abnormal error while closing connection. %v", err)
+ go serveFunction(c)
}
}
@@ -284,6 +294,11 @@ func serveIpc(conn net.Conn) {
onOff := cmd.Payload["OnOff"].(bool)
fingerprint := cmd.Payload["Fingerprint"].(string)
toggleIdentity(enc, fingerprint, onOff)
+
+ top.Broadcast <- dto.ZitiTunnelStatus{
+ Status: rts.ToStatus(),
+ Metrics: nil,
+ }
default:
log.Warnf("Unknown operation: %s. Returning error on pipe", cmd.Function)
respondWithError(enc, "Something unexpected has happened", UNKNOWN_ERROR, nil)
@@ -293,19 +308,6 @@ func serveIpc(conn net.Conn) {
log.Info("IPC Loop has exited")
}
-func acceptLogs(p net.Listener) {
- log.Debug("beginning logs receive loop")
- for {
- lcon, err := p.Accept()
- if err != nil {
- log.Errorf("unexpected error during accept. exiting accept loop! %v", err)
- return
- }
-
- go serveLogs(lcon) //serveLogs will close the connection for us
- }
-}
-
func serveLogs(conn net.Conn) {
log.Debug("accepted a connection, writing logs to pipe")
w := bufio.NewWriter(conn)
@@ -344,14 +346,54 @@ func serveLogs(conn net.Conn) {
}
}
+func serveEvents(conn net.Conn) {
+ log.Debug("accepted a connection, writing events to pipe")
+
+ consumer := make(chan interface{}, 1)
+ top.Register(consumer)
+
+ w := bufio.NewWriter(conn)
+ o := json.NewEncoder(w)
+
+ for {
+ msg := <-consumer
+ status, ok := msg.(dto.ZitiTunnelStatus)
+ if !ok {
+ log.Errorf("message received couldn't be converted to status? %v", status)
+ break
+ }
+ respond(o, dto.Response{Payload: status})
+ _, err := w.WriteString("\n")
+ if err != nil {
+ if err == io.EOF {
+ //fine client disconnected
+ log.Debug("exiting from serveEvents - client disconnected")
+ } else {
+ log.Errorf("exiting from serveEvents - unexpected error %v", err)
+ }
+ top.Unregister(consumer)
+ break
+ }
+ _ = w.Flush()
+
+ log.Infof("got %v", msg)
+ }
+ log.Info("exiting serve events")
+}
+
func reportStatus(out *json.Encoder) {
log.Debugf("request for status")
- respond(out, state.Clean())
+
+ respond(out, dto.ZitiTunnelStatus{
+ Status: rts.ToStatus(),
+ Metrics: nil,
+ })
log.Debugf("request for status responded to")
}
func tunnelState(onOff bool, out *json.Encoder) {
log.Debugf("toggle ziti on/off: %t", onOff)
+ state := rts.state
if onOff == state.Active {
log.Debug("nothing to do. the state of the tunnel already matches the requested state: %t", onOff)
respond(out, dto.Response{Message: fmt.Sprintf("noop: tunnel state already set to %t", onOff), Code: SUCCESS, Error: "", Payload: nil})
@@ -359,7 +401,7 @@ func tunnelState(onOff bool, out *json.Encoder) {
}
setTunnelState(onOff)
state.Active = onOff
- runtime.SaveState(&state)
+ SaveState(&rts)
respond(out, dto.Response{Message: "tunnel state updated successfully", Code: SUCCESS, Error: "", Payload: nil})
log.Debugf("toggle ziti on/off: %t responded to", onOff)
@@ -367,8 +409,9 @@ func tunnelState(onOff bool, out *json.Encoder) {
func setTunnelState(onOff bool) {
if onOff {
- runtime.TunStarted = time.Now()
+ TunStarted = time.Now()
+ state := rts.state
for _, id := range state.Identities {
connectIdentity(id)
}
@@ -380,7 +423,7 @@ func setTunnelState(onOff bool) {
func toggleIdentity(out *json.Encoder, fingerprint string, onOff bool) {
log.Debugf("toggle ziti on/off5 for %s: %t", fingerprint, onOff)
- _, id := state.Find(fingerprint)
+ _, id := rts.Find(fingerprint)
if id.Active == onOff {
log.Debugf("nothing to do - the provided identity %s is already set to active=%t", id.Name, id.Active)
//nothing to do...
@@ -401,7 +444,7 @@ func toggleIdentity(out *json.Encoder, fingerprint string, onOff bool) {
respond(out, dto.Response{Message: "identity toggled", Code: SUCCESS, Error: "", Payload: idutil.Clean(*id)})
log.Debugf("toggle ziti on/off for %s: %t responded to", fingerprint, onOff)
- runtime.SaveState(&state)
+ SaveState(&rts)
}
func removeTempFile(file os.File) {
@@ -495,16 +538,13 @@ func newIdentity(newId dto.AddIdentity, out *json.Encoder) {
log.Infof("enrolled successfully. identity file written to: %s", newPath)
connectIdentity(&newId.Id)
- /*
- if newId.Id.Active == true {
- connectIdentity(&newId.Id)
- }
- */
+
+ state := rts.state
//if successful parse the output and add the config to the identity
state.Identities = append(state.Identities, &newId.Id)
//save the state
- runtime.SaveState(&state)
+ SaveState(&rts)
//return successful message
resp := dto.Response{Message: "success", Code: SUCCESS, Error: "", Payload: idutil.Clean(newId.Id)}
@@ -526,7 +566,7 @@ func connectIdentity(id *dto.Identity) {
if !id.Connected {
//tell the c sdk to use the file from the id and connect
log.Debugf("loading identity %s with fingerprint %s", id.Name, id.FingerPrint)
- state.LoadIdentity(id)
+ rts.LoadIdentity(id)
} else {
log.Debugf("id [%s] is already connected - not reconnecting", id.Name)
}
@@ -558,7 +598,7 @@ func disconnectIdentity(id *dto.Identity) error {
func removeIdentity(out *json.Encoder, fingerprint string) {
log.Infof("request to remove identity by fingerprint: %s", fingerprint)
- _, id := state.Find(fingerprint)
+ _, id := rts.Find(fingerprint)
if id == nil {
respondWithError(out, fmt.Sprintf("Could not find identity by fingerprint: %s", fingerprint), IDENTITY_NOT_FOUND, nil)
return
@@ -569,8 +609,8 @@ func removeIdentity(out *json.Encoder, fingerprint string) {
respondWithError(out, "Error when disconnecting identity", ERROR_DISCONNECTING_ID, err)
return
}
- state.RemoveByIdentity(*id)
- runtime.SaveState(&state)
+ rts.RemoveByIdentity(*id)
+ SaveState(&rts)
resp := dto.Response{Message: "success", Code: SUCCESS, Error: "", Payload: nil}
respond(out, resp)
@@ -578,5 +618,7 @@ func removeIdentity(out *json.Encoder, fingerprint string) {
}
func respond(out *json.Encoder, thing interface{}) {
+ //leave for debugging j := json.NewEncoder(os.Stdout)
+ //leave for debugging j.Encode(thing)
_ = out.Encode(thing)
}
diff --git a/wintun-testing/ziti-tunnel/runtime/package-variables.go b/wintun-testing/ziti-tunnel/service/package-variables.go
similarity index 97%
rename from wintun-testing/ziti-tunnel/runtime/package-variables.go
rename to wintun-testing/ziti-tunnel/service/package-variables.go
index 88031833..d2e9f349 100644
--- a/wintun-testing/ziti-tunnel/runtime/package-variables.go
+++ b/wintun-testing/ziti-tunnel/service/package-variables.go
@@ -1,4 +1,4 @@
-package runtime
+package service
import (
"time"
diff --git a/wintun-testing/ziti-tunnel/runtime/permissions.go b/wintun-testing/ziti-tunnel/service/permissions.go
similarity index 98%
rename from wintun-testing/ziti-tunnel/runtime/permissions.go
rename to wintun-testing/ziti-tunnel/service/permissions.go
index ddb4c612..6f01eaca 100644
--- a/wintun-testing/ziti-tunnel/runtime/permissions.go
+++ b/wintun-testing/ziti-tunnel/service/permissions.go
@@ -1,4 +1,4 @@
-package runtime
+package service
import (
"github.com/netfoundry/ziti-foundation/util/stringz"
diff --git a/wintun-testing/ziti-tunnel/service/pkg-vars.go b/wintun-testing/ziti-tunnel/service/pkg-vars.go
index 8b8b113e..6f1cf1ab 100644
--- a/wintun-testing/ziti-tunnel/service/pkg-vars.go
+++ b/wintun-testing/ziti-tunnel/service/pkg-vars.go
@@ -1,21 +1,21 @@
package service
import (
+ "github.com/tv42/topic"
"golang.org/x/sys/windows/svc"
"sync"
- "wintun-testing/ziti-tunnel/globals"
- "wintun-testing/ziti-tunnel/runtime"
)
-var log = globals.Logger()
+var pipeBase = `\\.\pipe\NetFoundry\tunneler\`
+//var tunStatus = RuntimeState{}
-var ipcPipeName = `\\.\pipe\NetFoundry\tunneler\ipc`
-var logsPipeName = `\\.\pipe\NetFoundry\tunneler\logs`
-var state = runtime.TunnelerState{}
+//var state = dto.TunnelStatusa{}
+var rts = RuntimeState{}
var interrupt chan struct{}
var wg sync.WaitGroup
var connections int
+var Debug bool
const (
SUCCESS = 0
@@ -55,4 +55,24 @@ const (
System = "(A;;FA;;;SY)"
BuiltinAdmins = "(A;;FA;;;BA)"
LocalService = "(A;;FA;;;LS)"
-)
\ No newline at end of file
+)
+
+func pipeName(path string) string {
+ if !Debug {
+ return pipeBase + path
+ } else {
+ return pipeBase + `debug\` + path
+ }
+}
+
+var top = topic.New()
+
+func ipcPipeName() string {
+ return pipeName("ipc")
+}
+func logsPipeName() string {
+ return pipeName("logs")
+}
+func eventsPipeName() string {
+ return pipeName("events")
+}
diff --git a/wintun-testing/ziti-tunnel/service/service.go b/wintun-testing/ziti-tunnel/service/service.go
index 10e442f4..266da7eb 100644
--- a/wintun-testing/ziti-tunnel/service/service.go
+++ b/wintun-testing/ziti-tunnel/service/service.go
@@ -15,8 +15,7 @@ type zitiService struct{}
func (m *zitiService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
changes <- svc.Status{State: svc.StartPending}
- log.Errorf("the main loop exited with an unexpected error: %v")
- control := make(chan string)
+ control := make(chan string, 1)
mainLoop := make(chan struct{})
go func() {
err := SubMain(control, changes)
diff --git a/wintun-testing/ziti-tunnel/runtime/state.go b/wintun-testing/ziti-tunnel/service/state.go
similarity index 69%
rename from wintun-testing/ziti-tunnel/runtime/state.go
rename to wintun-testing/ziti-tunnel/service/state.go
index 0b7a38c8..6f3ee794 100644
--- a/wintun-testing/ziti-tunnel/runtime/state.go
+++ b/wintun-testing/ziti-tunnel/service/state.go
@@ -1,4 +1,4 @@
-package runtime
+package service
import (
"bufio"
@@ -11,54 +11,42 @@ import (
"strconv"
"time"
"wintun-testing/cziti"
-
"wintun-testing/ziti-tunnel/config"
"wintun-testing/ziti-tunnel/dto"
"wintun-testing/ziti-tunnel/idutil"
)
-type TunnelerState struct {
- Active bool
- Duration int64
- Identities []*dto.Identity
- IpInfo *TunIpInfo `json:"IpInfo,omitempty"`
-
+type RuntimeState struct {
+ state *dto.TunnelStatus
tun *tun.Device
tunName string
}
-type TunIpInfo struct {
- Ip string
- Subnet string
- MTU uint16
- DNS string
-}
-
-func (t *TunnelerState) RemoveByFingerprint(fingerprint string) {
+func (t *RuntimeState) RemoveByFingerprint(fingerprint string) {
log.Debugf("removing fingerprint: %s", fingerprint)
- if index, _ := t.Find(fingerprint); index < len(t.Identities) {
- t.Identities = append(t.Identities[:index], t.Identities[index+1:]...)
+ if index, _ := t.Find(fingerprint); index < len(t.state.Identities) {
+ t.state.Identities = append(t.state.Identities[:index], t.state.Identities[index+1:]...)
}
}
-func (t *TunnelerState) Find(fingerprint string) (int, *dto.Identity) {
- for i, n := range t.Identities {
+func (t *RuntimeState) Find(fingerprint string) (int, *dto.Identity) {
+ for i, n := range t.state.Identities {
if n.FingerPrint == fingerprint {
return i, n
}
}
- return len(t.Identities), nil
+ return len(t.state.Identities), nil
}
-func (t *TunnelerState) RemoveByIdentity(id dto.Identity) {
+func (t *RuntimeState) RemoveByIdentity(id dto.Identity) {
t.RemoveByFingerprint(id.FingerPrint)
}
-func (t *TunnelerState) FindByIdentity(id dto.Identity) (int, *dto.Identity) {
+func (t *RuntimeState) FindByIdentity(id dto.Identity) (int, *dto.Identity) {
return t.Find(id.FingerPrint)
}
-func SaveState(s *TunnelerState) {
+func SaveState(t *RuntimeState) {
// overwrite file if it exists
_ = os.MkdirAll(config.Path(), 0644)
@@ -69,8 +57,8 @@ func SaveState(s *TunnelerState) {
w := bufio.NewWriter(bufio.NewWriter(cfg))
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
- s.IpInfo = nil
- _ = enc.Encode(s)
+ t.state.IpInfo = nil
+ _ = enc.Encode(t.state)
_ = w.Flush()
err = cfg.Close()
@@ -80,9 +68,9 @@ func SaveState(s *TunnelerState) {
log.Debug("state saved")
}
-func (t *TunnelerState) Clean() TunnelerState {
+func (t *RuntimeState) ToStatus() *dto.TunnelStatus {
var d int64
- if t.Active {
+ if t.state.Active {
now := time.Now()
dd := now.Sub(TunStarted)
d = dd.Milliseconds()
@@ -90,21 +78,21 @@ func (t *TunnelerState) Clean() TunnelerState {
d = 0
}
- rtn := TunnelerState{
- Active: t.Active,
+ clean := dto.TunnelStatus{
+ Active: t.state.Active,
Duration: d,
- Identities: make([]*dto.Identity, len(t.Identities)),
- IpInfo: t.IpInfo,
+ Identities: make([]*dto.Identity, len(t.state.Identities)),
+ IpInfo: t.state.IpInfo,
}
- for i, id := range t.Identities {
- log.Debug("returning clean identity: %s", id.Name)
- rtn.Identities[i] = idutil.Clean(*id)
+ for i, id := range t.state.Identities {
+ log.Debugf("returning clean identity: %s", id.Name)
+ clean.Identities[i] = idutil.Clean(*id)
}
- return rtn
+ return &clean
}
-func (t *TunnelerState) CreateTun() error {
+func (t *RuntimeState) CreateTun() error {
if noZiti() {
log.Warnf("NOZITI set to true. this should be only used for debugging")
return nil
@@ -168,21 +156,7 @@ func (t *TunnelerState) CreateTun() error {
return nil
}
-func (t *TunnelerState) Close() {
- if t.tun != nil {
- log.Warn("TODO: actually close the tun - or disable all the identities etc.")
- /*
- cziti.Stop()
- */
- tu := *t.tun
- err := tu.Close()
- if err != nil {
- log.Fatalf("problem closing tunnel!")
- }
- }
-}
-
-func (t *TunnelerState) LoadIdentity(id *dto.Identity) {
+func (t *RuntimeState) LoadIdentity(id *dto.Identity) {
if !noZiti() {
if id.Connected {
log.Warnf("id [%s] already connected", id.FingerPrint)
@@ -221,3 +195,67 @@ func noZiti() bool {
v, _ := strconv.ParseBool(os.Getenv("NOZITI"))
return v
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+func (t *RuntimeState) Close() {
+ if t.tun != nil {
+ log.Warn("TODO: actually close the tun - or disable all the identities etc.")
+ /*
+ cziti.Stop()
+ */
+ tu := *t.tun
+ err := tu.Close()
+ if err != nil {
+ log.Fatalf("problem closing tunnel!")
+ }
+ }
+}
+
+func (t *RuntimeState) LoadConfig() {
+
+ log.Debugf("reading config file located at: %s", config.File())
+ file, err := os.OpenFile(config.File(), os.O_RDONLY, 0644)
+ if err != nil {
+ t.state = &dto.TunnelStatus{}
+ return
+ }
+
+ r := bufio.NewReader(file)
+ dec := json.NewDecoder(r)
+
+ err = dec.Decode(&rts.state)
+ if err != nil {
+ log.Warnf("unexpected error reading config file. %v", err)
+ t.state = &dto.TunnelStatus{}
+ return
+ }
+
+
+ err = file.Close()
+ if err != nil {
+ log.Errorf("could not close configuration file. this is not normal! %v", err)
+ }
+}
\ No newline at end of file