zrok/endpoints/vpn/frontend.go
2024-10-18 11:36:13 -04:00

132 lines
3.0 KiB
Go

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.DialWithOptions(cfg.ShrToken, &ziti.DialOptions{ConnectTimeout: 30 * time.Second})
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: cltCfg.ServerIPv6,
CIDRv6: cltCfg.CIDR6,
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")
}
}
}