mirror of
https://github.com/openziti/zrok.git
synced 2024-12-23 07:09:12 +01:00
implement VPN backend
This commit is contained in:
parent
67851c64af
commit
b7f046abf5
@ -2,15 +2,19 @@ package vpn
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"github.com/net-byte/vtun/common/config"
|
||||||
|
"github.com/net-byte/vtun/tun"
|
||||||
_ "github.com/net-byte/vtun/tun"
|
_ "github.com/net-byte/vtun/tun"
|
||||||
|
"github.com/net-byte/water"
|
||||||
"github.com/openziti/sdk-golang/ziti"
|
"github.com/openziti/sdk-golang/ziti"
|
||||||
"github.com/openziti/sdk-golang/ziti/edge"
|
"github.com/openziti/sdk-golang/ziti/edge"
|
||||||
"github.com/openziti/zrok/endpoints"
|
"github.com/openziti/zrok/endpoints"
|
||||||
|
cmap "github.com/orcaman/concurrent-map/v2"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/songgao/water/waterutil"
|
"github.com/songgao/water/waterutil"
|
||||||
"net"
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,11 +25,20 @@ type BackendConfig struct {
|
|||||||
RequestsChan chan *endpoints.Request
|
RequestsChan chan *endpoints.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
type Backend struct {
|
type Backend struct {
|
||||||
cfg *BackendConfig
|
cfg *BackendConfig
|
||||||
listener edge.Listener
|
listener edge.Listener
|
||||||
|
|
||||||
cidr net.IPAddr
|
cidr net.IPAddr
|
||||||
|
tun *water.Interface
|
||||||
|
mtu int
|
||||||
|
|
||||||
|
counter atomic.Uint32
|
||||||
|
clients cmap.ConcurrentMap[dest, *client]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBackend(cfg *BackendConfig) (*Backend, error) {
|
func NewBackend(cfg *BackendConfig) (*Backend, error) {
|
||||||
@ -49,14 +62,66 @@ func NewBackend(cfg *BackendConfig) (*Backend, error) {
|
|||||||
b := &Backend{
|
b := &Backend{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
listener: listener,
|
listener: listener,
|
||||||
|
mtu: ZROK_VPN_MTU,
|
||||||
|
clients: cmap.NewWithCustomShardingFunction[dest, *client](func(key dest) uint32 {
|
||||||
|
return key.toInt32()
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
b.counter.Store(1)
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Backend) readTun() {
|
||||||
|
buf := make([]byte, ZROK_VPN_MTU)
|
||||||
|
for {
|
||||||
|
n, err := b.tun.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("failed to read tun device")
|
||||||
|
// handle? error
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pkt := packet(buf[:n])
|
||||||
|
if !waterutil.IsIPv4(pkt) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("packet", pkt).Trace("read from tun device")
|
||||||
|
dest := pkt.destination()
|
||||||
|
|
||||||
|
if clt, ok := b.clients.Get(dest); ok {
|
||||||
|
_, err := clt.conn.Write(pkt)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Errorf("failed to write packet to clt[%v]", dest)
|
||||||
|
_ = clt.conn.Close()
|
||||||
|
b.clients.Remove(dest)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logrus.Errorf("no client with address[%v]", dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Backend) Run() error {
|
func (b *Backend) Run() error {
|
||||||
logrus.Info("started")
|
logrus.Info("started")
|
||||||
defer logrus.Info("exited")
|
defer logrus.Info("exited")
|
||||||
|
|
||||||
|
tunCfg := config.Config{
|
||||||
|
ServerIP: "192.168.127.1",
|
||||||
|
ServerIPv6: "fced::ffff:c0a8:7f01",
|
||||||
|
CIDR: "192.168.127.1/24",
|
||||||
|
CIDRv6: "fced::ffff:c0a8:7f01/64",
|
||||||
|
MTU: ZROK_VPN_MTU,
|
||||||
|
Verbose: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
b.tun = tun.CreateTun(tunCfg)
|
||||||
|
defer func() {
|
||||||
|
_ = b.tun.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go b.readTun()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if conn, err := b.listener.Accept(); err == nil {
|
if conn, err := b.listener.Accept(); err == nil {
|
||||||
go b.handle(conn)
|
go b.handle(conn)
|
||||||
@ -66,47 +131,54 @@ func (b *Backend) Run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ipProto waterutil.IPProtocol
|
|
||||||
|
|
||||||
func (p ipProto) String() string {
|
|
||||||
switch p {
|
|
||||||
case waterutil.TCP:
|
|
||||||
return "tcp"
|
|
||||||
case waterutil.UDP:
|
|
||||||
return "udp"
|
|
||||||
case waterutil.ICMP:
|
|
||||||
return "icmp"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("proto[%d]", p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) handle(conn net.Conn) {
|
func (b *Backend) handle(conn net.Conn) {
|
||||||
defer func(conn net.Conn) {
|
defer func(conn net.Conn) {
|
||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
}(conn)
|
}(conn)
|
||||||
|
|
||||||
|
num := uint32(0)
|
||||||
|
for num == 0 || num == 1 {
|
||||||
|
num = b.counter.Add(1)
|
||||||
|
num = num % 256
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv4 := net.IPv4(192, 168, 127, byte(num))
|
||||||
|
ip := ipToDest(ipv4)
|
||||||
|
|
||||||
cfg := &ClientConfig{
|
cfg := &ClientConfig{
|
||||||
Greeting: "Welcome to zrok VPN",
|
Greeting: "Welcome to zrok VPN",
|
||||||
|
IP: ipv4.String(),
|
||||||
|
ServerIP: "192.168.127.1",
|
||||||
|
CIDR: ipv4.String() + "/24",
|
||||||
|
MTU: b.mtu,
|
||||||
}
|
}
|
||||||
|
|
||||||
j, err := json.Marshal(&cfg)
|
j, err := json.Marshal(&cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("failed to write client VPN config")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = conn.Write(j)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("failed to write client VPN config")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn.Write(j)
|
|
||||||
|
|
||||||
buf := make([]byte, 16*1024)
|
clt := &client{conn: conn}
|
||||||
|
b.clients.Set(ip, clt)
|
||||||
|
|
||||||
|
buf := make([]byte, b.mtu)
|
||||||
for {
|
for {
|
||||||
read, err := conn.Read(buf)
|
read, err := conn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error("read error", err)
|
logrus.Error("read error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pkt := buf[:read]
|
pkt := packet(buf[:read])
|
||||||
logrus.Infof("read packet %d bytes %v %v:%v -> %v:%v", read,
|
logrus.WithField("packet", pkt).Info("read from ziti")
|
||||||
ipProto(waterutil.IPv4Protocol(pkt)),
|
_, err = b.tun.Write(pkt)
|
||||||
waterutil.IPv4Source(pkt), waterutil.IPv4SourcePort(pkt),
|
if err != nil {
|
||||||
waterutil.IPv4Destination(pkt), waterutil.IPv4DestinationPort(pkt))
|
logrus.WithError(err).Error("failed to write packet to tun")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,63 @@
|
|||||||
package vpn
|
package vpn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/songgao/water/waterutil"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ZROK_VPN_MTU = 16 * 1024
|
||||||
|
|
||||||
type ClientConfig struct {
|
type ClientConfig struct {
|
||||||
Greeting string
|
Greeting string
|
||||||
IP string
|
IP string
|
||||||
CIDR string
|
CIDR string
|
||||||
ServerIP string
|
ServerIP string
|
||||||
Routes []string
|
Routes []string
|
||||||
|
MTU int
|
||||||
|
}
|
||||||
|
|
||||||
|
type dest struct {
|
||||||
|
addr [4]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dest) String() string {
|
||||||
|
return net.IP(d.addr[:]).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dest) toInt32() uint32 {
|
||||||
|
return uint32(d.addr[0])<<24 + uint32(d.addr[1])<<16 + uint32(d.addr[2])<<8 + uint32(d.addr[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipToDest(addr net.IP) dest {
|
||||||
|
return dest{
|
||||||
|
addr: [4]byte{addr[0], addr[1], addr[2], addr[3]},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type packet []byte
|
||||||
|
|
||||||
|
func (p packet) destination() dest {
|
||||||
|
return ipToDest(waterutil.IPv4Destination(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p packet) String() string {
|
||||||
|
return fmt.Sprintf("%s %s:%d -> %s:%d %d bytes", p.proto(),
|
||||||
|
waterutil.IPv4Source(p), waterutil.IPv4SourcePort(p),
|
||||||
|
waterutil.IPv4Destination(p), waterutil.IPv4DestinationPort(p), len(waterutil.IPv4Payload(p)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p packet) proto() string {
|
||||||
|
proto := waterutil.IPv4Protocol(p)
|
||||||
|
switch proto {
|
||||||
|
case waterutil.TCP:
|
||||||
|
return "tcp"
|
||||||
|
case waterutil.UDP:
|
||||||
|
return "udp"
|
||||||
|
case waterutil.ICMP:
|
||||||
|
return "icmp"
|
||||||
|
default:
|
||||||
|
return strconv.Itoa(int(proto))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
4
go.mod
4
go.mod
@ -31,6 +31,7 @@ require (
|
|||||||
github.com/michaelquigley/pfxlog v0.6.10
|
github.com/michaelquigley/pfxlog v0.6.10
|
||||||
github.com/muesli/reflow v0.3.0
|
github.com/muesli/reflow v0.3.0
|
||||||
github.com/net-byte/vtun v1.7.0
|
github.com/net-byte/vtun v1.7.0
|
||||||
|
github.com/net-byte/water v0.0.7
|
||||||
github.com/nxadm/tail v1.4.8
|
github.com/nxadm/tail v1.4.8
|
||||||
github.com/openziti/channel/v2 v2.0.121
|
github.com/openziti/channel/v2 v2.0.121
|
||||||
github.com/openziti/edge-api v0.26.12
|
github.com/openziti/edge-api v0.26.12
|
||||||
@ -38,6 +39,7 @@ require (
|
|||||||
github.com/openziti/identity v1.0.72
|
github.com/openziti/identity v1.0.72
|
||||||
github.com/openziti/sdk-golang v0.23.10
|
github.com/openziti/sdk-golang v0.23.10
|
||||||
github.com/openziti/transport/v2 v2.0.124
|
github.com/openziti/transport/v2 v2.0.124
|
||||||
|
github.com/orcaman/concurrent-map/v2 v2.0.1
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rabbitmq/amqp091-go v1.8.1
|
github.com/rabbitmq/amqp091-go v1.8.1
|
||||||
github.com/rubenv/sql-migrate v1.6.0
|
github.com/rubenv/sql-migrate v1.6.0
|
||||||
@ -166,7 +168,6 @@ require (
|
|||||||
github.com/muesli/termenv v0.13.0 // indirect
|
github.com/muesli/termenv v0.13.0 // indirect
|
||||||
github.com/muhlemmer/gu v0.3.1 // indirect
|
github.com/muhlemmer/gu v0.3.1 // indirect
|
||||||
github.com/net-byte/go-gateway v0.0.2 // indirect
|
github.com/net-byte/go-gateway v0.0.2 // indirect
|
||||||
github.com/net-byte/water v0.0.7 // indirect
|
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
@ -174,7 +175,6 @@ require (
|
|||||||
github.com/openziti/metrics v1.2.47 // indirect
|
github.com/openziti/metrics v1.2.47 // indirect
|
||||||
github.com/openziti/secretstream v0.1.17 // indirect
|
github.com/openziti/secretstream v0.1.17 // indirect
|
||||||
github.com/openziti/storage v0.2.6 // indirect
|
github.com/openziti/storage v0.2.6 // indirect
|
||||||
github.com/orcaman/concurrent-map/v2 v2.0.1 // indirect
|
|
||||||
github.com/parallaxsecond/parsec-client-go v0.0.0-20221025095442-f0a77d263cf9 // indirect
|
github.com/parallaxsecond/parsec-client-go v0.0.0-20221025095442-f0a77d263cf9 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||||
|
Loading…
Reference in New Issue
Block a user