mirror of
https://github.com/openziti/desktop-edge-win.git
synced 2026-10-14 08:39:55 +00:00
staging updates just so jeremy can pick them up
This commit is contained in:
@@ -147,5 +147,6 @@
|
||||
</StackPanel>
|
||||
<local:MainMenu x:Name="MainMenu" Visibility="Collapsed"></local:MainMenu>
|
||||
<local:IdentityDetails x:Name="IdentityMenu" Visibility="Collapsed"></local:IdentityDetails>
|
||||
<Button Content="Button" HorizontalAlignment="Left" Margin="47,244,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -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<ZitiIdentity>());
|
||||
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)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ using System.Security.Principal;
|
||||
using System.Security.AccessControl;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
/// <summary>
|
||||
/// The implementation will abstract away the setup of the communication to
|
||||
@@ -19,13 +20,35 @@ using Newtonsoft.Json;
|
||||
/// </summary>
|
||||
namespace ZitiTunneler.ServiceClient
|
||||
{
|
||||
|
||||
internal class Client
|
||||
{
|
||||
public event EventHandler<TunnelStatus> OnTunnelStatusUpdate;
|
||||
public event EventHandler<Metrics> OnMetricsUpdate;
|
||||
|
||||
protected virtual void ZitiTunnelStatusUpdate(TunnelStatus e)
|
||||
{
|
||||
EventHandler<TunnelStatus> handler = OnTunnelStatusUpdate;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(this, e);
|
||||
}
|
||||
}
|
||||
protected virtual void MetricsUpdate(Metrics e)
|
||||
{
|
||||
EventHandler<Metrics> 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<StatusUpdateResponse>("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<ZitiTunnelStatus>();
|
||||
var rtn = read<ZitiTunnelStatus>(" ipc: ", ipcReader);
|
||||
return rtn;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
@@ -124,7 +164,7 @@ namespace ZitiTunneler.ServiceClient
|
||||
|
||||
send(AddIdentityFunction);
|
||||
send(newId);
|
||||
var resp = read<IdentityResponse>();
|
||||
var resp = read<IdentityResponse>(" 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<SvcResponse>();
|
||||
var r = read<SvcResponse>(" ipc: ", ipcReader);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
@@ -169,7 +209,7 @@ namespace ZitiTunneler.ServiceClient
|
||||
try
|
||||
{
|
||||
send(new BooleanFunction("TunnelState", onOff));
|
||||
read<SvcResponse>();
|
||||
read<SvcResponse>(" ipc: ", ipcReader);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
@@ -206,7 +246,7 @@ namespace ZitiTunneler.ServiceClient
|
||||
try
|
||||
{
|
||||
send(new IdentityToggleFunction(fingerprint, onOff));
|
||||
IdentityResponse idr = read<IdentityResponse>();
|
||||
IdentityResponse idr = read<IdentityResponse>(" ipc: ", ipcReader);
|
||||
return idr.Payload;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
@@ -271,33 +311,33 @@ namespace ZitiTunneler.ServiceClient
|
||||
}
|
||||
}
|
||||
|
||||
private T read<T>() where T : SvcResponse
|
||||
private T read<T>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package runtime
|
||||
package service
|
||||
|
||||
import (
|
||||
"time"
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package runtime
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/util/stringz"
|
||||
@@ -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)"
|
||||
)
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
+90
-52
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user