mirror of
https://github.com/fosrl/newt.git
synced 2026-02-07 21:46:39 +00:00
Shift things around - remove native
This commit is contained in:
@@ -4,17 +4,18 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fosrl/newt/clients"
|
||||||
|
wgnetstack "github.com/fosrl/newt/clients"
|
||||||
"github.com/fosrl/newt/logger"
|
"github.com/fosrl/newt/logger"
|
||||||
"github.com/fosrl/newt/netstack2"
|
"github.com/fosrl/newt/netstack2"
|
||||||
"github.com/fosrl/newt/proxy"
|
"github.com/fosrl/newt/proxy"
|
||||||
"github.com/fosrl/newt/websocket"
|
"github.com/fosrl/newt/websocket"
|
||||||
"golang.zx2c4.com/wireguard/tun/netstack"
|
"golang.zx2c4.com/wireguard/tun/netstack"
|
||||||
|
|
||||||
"github.com/fosrl/newt/wgnetstack"
|
|
||||||
"github.com/fosrl/newt/wgtester"
|
"github.com/fosrl/newt/wgtester"
|
||||||
)
|
)
|
||||||
|
|
||||||
var wgService *wgnetstack.WireGuardService
|
var wgService *clients.WireGuardService
|
||||||
var wgTesterServer *wgtester.Server
|
var wgTesterServer *wgtester.Server
|
||||||
var ready bool
|
var ready bool
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package wgnetstack
|
package clients
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -29,18 +29,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type WgConfig struct {
|
type WgConfig struct {
|
||||||
IpAddress string `json:"ipAddress"`
|
IpAddress string `json:"ipAddress"`
|
||||||
Peers []Peer `json:"peers"`
|
Peers []Peer `json:"peers"`
|
||||||
Targets TargetsByType `json:"targets"`
|
Targets []Target `json:"targets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TargetsByType struct {
|
type Target struct {
|
||||||
UDP []string `json:"udp"`
|
CIDR string `json:"cidr"`
|
||||||
TCP []string `json:"tcp"`
|
PortRange []PortRange `json:"portRange,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TargetData struct {
|
type PortRange struct {
|
||||||
Targets []string `json:"targets"`
|
Min uint16 `json:"min"`
|
||||||
|
Max uint16 `json:"max"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
@@ -178,6 +179,8 @@ func NewWireGuardService(interfaceName string, mtu int, generateAndSaveKeyTo str
|
|||||||
wsClient.RegisterHandler("newt/wg/peer/add", service.handleAddPeer)
|
wsClient.RegisterHandler("newt/wg/peer/add", service.handleAddPeer)
|
||||||
wsClient.RegisterHandler("newt/wg/peer/remove", service.handleRemovePeer)
|
wsClient.RegisterHandler("newt/wg/peer/remove", service.handleRemovePeer)
|
||||||
wsClient.RegisterHandler("newt/wg/peer/update", service.handleUpdatePeer)
|
wsClient.RegisterHandler("newt/wg/peer/update", service.handleUpdatePeer)
|
||||||
|
wsClient.RegisterHandler("newt/wg/target/add", service.handleAddTarget)
|
||||||
|
wsClient.RegisterHandler("newt/wg/target/remove", service.handleRemoveTarget)
|
||||||
|
|
||||||
return service, nil
|
return service, nil
|
||||||
}
|
}
|
||||||
@@ -327,6 +330,10 @@ func (s *WireGuardService) handleConfig(msg websocket.WSMessage) {
|
|||||||
if err := s.ensureWireguardPeers(config.Peers); err != nil {
|
if err := s.ensureWireguardPeers(config.Peers); err != nil {
|
||||||
logger.Error("Failed to ensure WireGuard peers: %v", err)
|
logger.Error("Failed to ensure WireGuard peers: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.ensureTargets(config.Targets); err != nil {
|
||||||
|
logger.Error("Failed to ensure WireGuard targets: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
||||||
@@ -376,7 +383,7 @@ func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
|||||||
// logger.Info("Private key is %s", fixKey(s.key.String()))
|
// logger.Info("Private key is %s", fixKey(s.key.String()))
|
||||||
|
|
||||||
// Configure WireGuard with private key
|
// Configure WireGuard with private key
|
||||||
config := fmt.Sprintf("private_key=%s", fixKey(s.key.String()))
|
config := fmt.Sprintf("private_key=%s", util.FixKey(s.key.String()))
|
||||||
|
|
||||||
err = s.device.IpcSet(config)
|
err = s.device.IpcSet(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -409,20 +416,6 @@ func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fixKey(key string) string {
|
|
||||||
// Remove any whitespace
|
|
||||||
key = strings.TrimSpace(key)
|
|
||||||
|
|
||||||
// Decode from base64
|
|
||||||
decoded, err := base64.StdEncoding.DecodeString(key)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal("Error decoding base64: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to hex
|
|
||||||
return hex.EncodeToString(decoded)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WireGuardService) ensureWireguardPeers(peers []Peer) error {
|
func (s *WireGuardService) ensureWireguardPeers(peers []Peer) error {
|
||||||
// For netstack, we need to manage peers differently
|
// For netstack, we need to manage peers differently
|
||||||
// We'll configure peers directly on the device using IPC
|
// We'll configure peers directly on the device using IPC
|
||||||
@@ -461,6 +454,38 @@ func (s *WireGuardService) ensureWireguardPeers(peers []Peer) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *WireGuardService) ensureTargets(targets []Target) error {
|
||||||
|
if s.tnet == nil {
|
||||||
|
return fmt.Errorf("netstack not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
// handler.AddSubnetRule(subnet2, []PortRange{
|
||||||
|
// {Min: 12000, Max: 12001},
|
||||||
|
// {Min: 8000, Max: 8000},
|
||||||
|
// })
|
||||||
|
|
||||||
|
for _, target := range targets {
|
||||||
|
prefix, err := netip.ParsePrefix(target.CIDR)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid CIDR %s: %v", target.CIDR, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var portRanges []netstack2.PortRange
|
||||||
|
for _, pr := range target.PortRange {
|
||||||
|
portRanges = append(portRanges, netstack2.PortRange{
|
||||||
|
Min: pr.Min,
|
||||||
|
Max: pr.Max,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tnet.AddProxySubnetRule(prefix, portRanges)
|
||||||
|
|
||||||
|
logger.Info("Added target subnet %s with port ranges: %v", target.CIDR, target.PortRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *WireGuardService) addPeerToDevice(peer Peer) error {
|
func (s *WireGuardService) addPeerToDevice(peer Peer) error {
|
||||||
// parse the key first
|
// parse the key first
|
||||||
pubKey, err := wgtypes.ParseKey(peer.PublicKey)
|
pubKey, err := wgtypes.ParseKey(peer.PublicKey)
|
||||||
@@ -469,7 +494,7 @@ func (s *WireGuardService) addPeerToDevice(peer Peer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build IPC configuration string for the peer
|
// Build IPC configuration string for the peer
|
||||||
config := fmt.Sprintf("public_key=%s", fixKey(pubKey.String()))
|
config := fmt.Sprintf("public_key=%s", util.FixKey(pubKey.String()))
|
||||||
|
|
||||||
// Add allowed IPs
|
// Add allowed IPs
|
||||||
for _, allowedIP := range peer.AllowedIPs {
|
for _, allowedIP := range peer.AllowedIPs {
|
||||||
@@ -559,7 +584,7 @@ func (s *WireGuardService) removePeer(publicKey string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build IPC configuration string to remove the peer
|
// Build IPC configuration string to remove the peer
|
||||||
config := fmt.Sprintf("public_key=%s\nremove=true", fixKey(pubKey.String()))
|
config := fmt.Sprintf("public_key=%s\nremove=true", util.FixKey(pubKey.String()))
|
||||||
|
|
||||||
if err := s.device.IpcSet(config); err != nil {
|
if err := s.device.IpcSet(config); err != nil {
|
||||||
return fmt.Errorf("failed to remove peer: %v", err)
|
return fmt.Errorf("failed to remove peer: %v", err)
|
||||||
@@ -603,7 +628,7 @@ func (s *WireGuardService) handleUpdatePeer(msg websocket.WSMessage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build IPC configuration string to update the peer
|
// Build IPC configuration string to update the peer
|
||||||
config := fmt.Sprintf("public_key=%s\nupdate_only=true", fixKey(pubKey.String()))
|
config := fmt.Sprintf("public_key=%s\nupdate_only=true", util.FixKey(pubKey.String()))
|
||||||
|
|
||||||
// Handle AllowedIPs update
|
// Handle AllowedIPs update
|
||||||
if len(request.AllowedIPs) > 0 {
|
if len(request.AllowedIPs) > 0 {
|
||||||
@@ -801,6 +826,81 @@ func (s *WireGuardService) reportPeerBandwidth() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
||||||
|
func (s *WireGuardService) handleAddTarget(msg websocket.WSMessage) {
|
||||||
|
logger.Debug("Received message: %v", msg.Data)
|
||||||
|
var target Target
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Error marshaling data: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(jsonData, &target); err != nil {
|
||||||
|
logger.Info("Error unmarshaling target data: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.tnet == nil {
|
||||||
|
logger.Info("Netstack not initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix, err := netip.ParsePrefix(target.CIDR)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Invalid CIDR %s: %v", target.CIDR, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var portRanges []netstack2.PortRange
|
||||||
|
for _, pr := range target.PortRange {
|
||||||
|
portRanges = append(portRanges, netstack2.PortRange{
|
||||||
|
Min: pr.Min,
|
||||||
|
Max: pr.Max,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tnet.AddProxySubnetRule(prefix, portRanges)
|
||||||
|
|
||||||
|
logger.Info("Added target subnet %s with port ranges: %v", target.CIDR, target.PortRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WireGuardService) handleRemoveTarget(msg websocket.WSMessage) {
|
||||||
|
logger.Debug("Received message: %v", msg.Data)
|
||||||
|
|
||||||
|
type RemoveTargetRequest struct {
|
||||||
|
CIDR string `json:"cidr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Error marshaling data: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var request RemoveTargetRequest
|
||||||
|
if err := json.Unmarshal(jsonData, &request); err != nil {
|
||||||
|
logger.Info("Error unmarshaling data: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.tnet == nil {
|
||||||
|
logger.Info("Netstack not initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix, err := netip.ParsePrefix(request.CIDR)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Invalid CIDR %s: %v", request.CIDR, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tnet.RemoveProxySubnetRule(prefix)
|
||||||
|
|
||||||
|
logger.Info("Removed target subnet %s", request.CIDR)
|
||||||
|
}
|
||||||
|
|
||||||
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
// filterReadOnlyFields removes read-only fields from WireGuard IPC configuration
|
||||||
func (s *WireGuardService) filterReadOnlyFields(config string) string {
|
func (s *WireGuardService) filterReadOnlyFields(config string) string {
|
||||||
lines := strings.Split(config, "\n")
|
lines := strings.Split(config, "\n")
|
||||||
16
common.go
16
common.go
@@ -3,8 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@@ -27,20 +25,6 @@ import (
|
|||||||
|
|
||||||
const msgHealthFileWriteFailed = "Failed to write health file: %v"
|
const msgHealthFileWriteFailed = "Failed to write health file: %v"
|
||||||
|
|
||||||
func fixKey(key string) string {
|
|
||||||
// Remove any whitespace
|
|
||||||
key = strings.TrimSpace(key)
|
|
||||||
|
|
||||||
// Decode from base64
|
|
||||||
decoded, err := base64.StdEncoding.DecodeString(key)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal("Error decoding base64: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to hex
|
|
||||||
return hex.EncodeToString(decoded)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ping(tnet *netstack.Net, dst string, timeout time.Duration) (time.Duration, error) {
|
func ping(tnet *netstack.Net, dst string, timeout time.Duration) (time.Duration, error) {
|
||||||
logger.Debug("Pinging %s", dst)
|
logger.Debug("Pinging %s", dst)
|
||||||
socket, err := tnet.Dial("ping4", dst)
|
socket, err := tnet.Dial("ping4", dst)
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -678,7 +678,7 @@ func main() {
|
|||||||
public_key=%s
|
public_key=%s
|
||||||
allowed_ip=%s/32
|
allowed_ip=%s/32
|
||||||
endpoint=%s
|
endpoint=%s
|
||||||
persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.PublicKey), wgData.ServerIP, endpoint)
|
persistent_keepalive_interval=5`, util.FixKey(privateKey.String()), util.FixKey(wgData.PublicKey), wgData.ServerIP, endpoint)
|
||||||
|
|
||||||
err = dev.IpcSet(config)
|
err = dev.IpcSet(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -150,18 +150,18 @@ func NewProxyHandler(options ProxyHandlerOptions) (*ProxyHandler, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example 1: Add a subnet with no port restrictions (all ports allowed)
|
// // Example 1: Add a subnet with no port restrictions (all ports allowed)
|
||||||
// This accepts all traffic to 10.20.20.0/24
|
// // This accepts all traffic to 10.20.20.0/24
|
||||||
subnet1 := netip.MustParsePrefix("10.20.20.0/24")
|
// subnet1 := netip.MustParsePrefix("10.20.20.0/24")
|
||||||
handler.AddSubnetRule(subnet1, nil)
|
// handler.AddSubnetRule(subnet1, nil)
|
||||||
|
|
||||||
// Example 2: Add a subnet with specific port ranges
|
// // Example 2: Add a subnet with specific port ranges
|
||||||
// This accepts traffic to 192.168.1.0/24 only on ports 80, 443, and 8000-9000
|
// // This accepts traffic to 192.168.1.0/24 only on ports 80, 443, and 8000-9000
|
||||||
subnet2 := netip.MustParsePrefix("10.20.21.21/32")
|
// subnet2 := netip.MustParsePrefix("10.20.21.21/32")
|
||||||
handler.AddSubnetRule(subnet2, []PortRange{
|
// handler.AddSubnetRule(subnet2, []PortRange{
|
||||||
{Min: 12000, Max: 12001},
|
// {Min: 12000, Max: 12001},
|
||||||
{Min: 8000, Max: 8000},
|
// {Min: 8000, Max: 8000},
|
||||||
})
|
// })
|
||||||
|
|
||||||
return handler, nil
|
return handler, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ type netTun struct {
|
|||||||
mtu int
|
mtu int
|
||||||
dnsServers []netip.Addr
|
dnsServers []netip.Addr
|
||||||
hasV4, hasV6 bool
|
hasV4, hasV6 bool
|
||||||
proxyHandler *ProxyHandler // Handles promiscuous mode packet processing
|
// TODO: LETS NOT KEEP THIS ON THE TUN AND MOVE IT BUT WE CAN KEEP IT FOR NOW
|
||||||
|
proxyHandler *ProxyHandler // Handles promiscuous mode packet processing
|
||||||
}
|
}
|
||||||
|
|
||||||
type Net netTun
|
type Net netTun
|
||||||
@@ -347,6 +348,30 @@ func (net *Net) ListenUDP(laddr *net.UDPAddr) (*gonet.UDPConn, error) {
|
|||||||
return net.DialUDP(laddr, nil)
|
return net.DialUDP(laddr, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddProxySubnetRule adds a subnet rule to the proxy handler
|
||||||
|
// If portRanges is nil or empty, all ports are allowed for this subnet
|
||||||
|
func (net *Net) AddProxySubnetRule(prefix netip.Prefix, portRanges []PortRange) {
|
||||||
|
tun := (*netTun)(net)
|
||||||
|
if tun.proxyHandler != nil {
|
||||||
|
tun.proxyHandler.AddSubnetRule(prefix, portRanges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveProxySubnetRule removes a subnet rule from the proxy handler
|
||||||
|
func (net *Net) RemoveProxySubnetRule(prefix netip.Prefix) {
|
||||||
|
tun := (*netTun)(net)
|
||||||
|
if tun.proxyHandler != nil {
|
||||||
|
tun.proxyHandler.RemoveSubnetRule(prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProxyHandler returns the proxy handler (for advanced use cases)
|
||||||
|
// Returns nil if proxy is not enabled
|
||||||
|
func (net *Net) GetProxyHandler() *ProxyHandler {
|
||||||
|
tun := (*netTun)(net)
|
||||||
|
return tun.proxyHandler
|
||||||
|
}
|
||||||
|
|
||||||
type PingConn struct {
|
type PingConn struct {
|
||||||
laddr PingAddr
|
laddr PingAddr
|
||||||
raddr PingAddr
|
raddr PingAddr
|
||||||
|
|||||||
16
util/util.go
16
util/util.go
@@ -1,6 +1,8 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -120,3 +122,17 @@ func FindAvailableUDPPort(minPort, maxPort uint16) (uint16, error) {
|
|||||||
|
|
||||||
return 0, fmt.Errorf("no available consecutive UDP ports found in range %d-%d", minPort, maxPort)
|
return 0, fmt.Errorf("no available consecutive UDP ports found in range %d-%d", minPort, maxPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FixKey(key string) string {
|
||||||
|
// Remove any whitespace
|
||||||
|
key = strings.TrimSpace(key)
|
||||||
|
|
||||||
|
// Decode from base64
|
||||||
|
decoded, err := base64.StdEncoding.DecodeString(key)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal("Error decoding base64: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to hex
|
||||||
|
return hex.EncodeToString(decoded)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user