From 8c3441d52716f10220faee13cddc3f7ca95edb5b Mon Sep 17 00:00:00 2001 From: eugene Date: Thu, 11 Apr 2024 14:49:30 -0400 Subject: [PATCH] implement VPN frontend --- cmd/zrok/accessPrivate.go | 25 ++++++++ endpoints/vpn/frontend.go | 131 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 endpoints/vpn/frontend.go diff --git a/cmd/zrok/accessPrivate.go b/cmd/zrok/accessPrivate.go index 8bb1402f..3d1d5c39 100644 --- a/cmd/zrok/accessPrivate.go +++ b/cmd/zrok/accessPrivate.go @@ -8,6 +8,7 @@ import ( "github.com/openziti/zrok/endpoints/proxy" "github.com/openziti/zrok/endpoints/tcpTunnel" "github.com/openziti/zrok/endpoints/udpTunnel" + "github.com/openziti/zrok/endpoints/vpn" "github.com/openziti/zrok/environment" "github.com/openziti/zrok/rest_client_zrok" "github.com/openziti/zrok/rest_client_zrok/share" @@ -165,6 +166,30 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { } }() + case "vpn": + endpointUrl = &url.URL{ + Scheme: "VPN", + } + fe, err := vpn.NewFrontend(&vpn.FrontendConfig{ + IdentityName: env.EnvironmentIdentityName(), + ShrToken: args[0], + RequestsChan: requests, + }) + if err != nil { + if !panicInstead { + tui.Error("unable to create private access", err) + } + panic(err) + } + go func() { + if err := fe.Run(); err != nil { + if !panicInstead { + tui.Error("error starting access", err) + } + panic(err) + } + }() + default: cfg := proxy.DefaultFrontendConfig(env.EnvironmentIdentityName()) cfg.ShrToken = shrToken diff --git a/endpoints/vpn/frontend.go b/endpoints/vpn/frontend.go new file mode 100644 index 00000000..62e7bf7f --- /dev/null +++ b/endpoints/vpn/frontend.go @@ -0,0 +1,131 @@ +package vpn + +import ( + "encoding/json" + "github.com/net-byte/vtun/common/config" + "github.com/net-byte/vtun/tun" + "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/zrok/endpoints" + "github.com/openziti/zrok/environment" + "github.com/openziti/zrok/sdk/golang/sdk" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "net" + "time" +) + +type FrontendConfig struct { + IdentityName string + ShrToken string + RequestsChan chan *endpoints.Request +} + +type Frontend struct { + cfg *FrontendConfig + ztx ziti.Context + conn net.Conn +} + +func NewFrontend(cfg *FrontendConfig) (*Frontend, error) { + env, err := environment.LoadRoot() + if err != nil { + return nil, errors.Wrap(err, "error loading environment root") + } + zCfgPath, err := env.ZitiIdentityNamed(cfg.IdentityName) + if err != nil { + return nil, errors.Wrapf(err, "error getting ziti identity '%v' from environment", cfg.IdentityName) + } + zCfg, err := ziti.NewConfigFromFile(zCfgPath) + if err != nil { + return nil, errors.Wrap(err, "error loading config") + } + zCfg.ConfigTypes = []string{sdk.ZrokProxyConfig} + zCtx, err := ziti.NewContext(zCfg) + if err != nil { + return nil, errors.Wrap(err, "error loading ziti context") + } + + zConn, err := zCtx.Dial(cfg.ShrToken) + if err != nil { + zCtx.Close() + return nil, errors.Wrap(err, "error connecting to ziti") + } + return &Frontend{ + cfg: cfg, + ztx: zCtx, + conn: zConn, + }, nil +} + +func (f *Frontend) Run() error { + var cltCfg ClientConfig + d := json.NewDecoder(f.conn) + if err := d.Decode(&cltCfg); err != nil { + return errors.Wrap(err, "error decoding vpn config") + } + f.cfg.RequestsChan <- &endpoints.Request{ + Stamp: time.Now(), + RemoteAddr: cltCfg.ServerIP, + Method: "CONNECTED", + Path: cltCfg.Greeting, + } + logrus.Info("connected:", cltCfg.Greeting) + + defer func() { + f.cfg.RequestsChan <- &endpoints.Request{ + Stamp: time.Now(), + RemoteAddr: cltCfg.ServerIP, + Method: "Disconnected", + } + }() + + cfg := config.Config{ + ServerIP: cltCfg.ServerIP, + CIDR: cltCfg.CIDR, + ServerIPv6: "fced::ffff:c0a8:7f01", + CIDRv6: "fced::ffff:c0a8:7f16/64", + MTU: cltCfg.MTU, + Verbose: false, + } + iface := tun.CreateTun(cfg) + + logrus.Infof("created tun device: %s", iface.Name()) + + go func() { + defer func() { + _ = f.conn.Close() + _ = iface.Close() + }() + + b := make([]byte, cltCfg.MTU) + for { + n, err := f.conn.Read(b) + if err != nil { + logrus.WithError(err).Error("error reading from ziti") + return + } + p := packet(b[:n]) + logrus.WithField("packet", p).Trace("received packet from peer") + _, err = iface.Write(p) + if err != nil { + logrus.WithError(err).Error("error writing to device") + return + } + } + }() + + buf := make([]byte, cltCfg.MTU) + for { + n, err := iface.Read(buf) + if err != nil { + return errors.Wrap(err, "error reading packet") + } + pkt := packet(buf[:n]) + logrus.WithField("packet", pkt).Trace("read packet from tun device") + _, err = f.conn.Write(pkt) + + if err != nil { + return errors.Wrap(err, "error sending packet to ziti") + } + } +}