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"
|
||||
"strings"
|
||||
|
||||
"github.com/fosrl/newt/clients"
|
||||
wgnetstack "github.com/fosrl/newt/clients"
|
||||
"github.com/fosrl/newt/logger"
|
||||
"github.com/fosrl/newt/netstack2"
|
||||
"github.com/fosrl/newt/proxy"
|
||||
"github.com/fosrl/newt/websocket"
|
||||
"golang.zx2c4.com/wireguard/tun/netstack"
|
||||
|
||||
"github.com/fosrl/newt/wgnetstack"
|
||||
"github.com/fosrl/newt/wgtester"
|
||||
)
|
||||
|
||||
var wgService *wgnetstack.WireGuardService
|
||||
var wgService *clients.WireGuardService
|
||||
var wgTesterServer *wgtester.Server
|
||||
var ready bool
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package wgnetstack
|
||||
package clients
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -31,16 +31,17 @@ import (
|
||||
type WgConfig struct {
|
||||
IpAddress string `json:"ipAddress"`
|
||||
Peers []Peer `json:"peers"`
|
||||
Targets TargetsByType `json:"targets"`
|
||||
Targets []Target `json:"targets"`
|
||||
}
|
||||
|
||||
type TargetsByType struct {
|
||||
UDP []string `json:"udp"`
|
||||
TCP []string `json:"tcp"`
|
||||
type Target struct {
|
||||
CIDR string `json:"cidr"`
|
||||
PortRange []PortRange `json:"portRange,omitempty"`
|
||||
}
|
||||
|
||||
type TargetData struct {
|
||||
Targets []string `json:"targets"`
|
||||
type PortRange struct {
|
||||
Min uint16 `json:"min"`
|
||||
Max uint16 `json:"max"`
|
||||
}
|
||||
|
||||
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/remove", service.handleRemovePeer)
|
||||
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
|
||||
}
|
||||
@@ -327,6 +330,10 @@ func (s *WireGuardService) handleConfig(msg websocket.WSMessage) {
|
||||
if err := s.ensureWireguardPeers(config.Peers); err != nil {
|
||||
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 {
|
||||
@@ -376,7 +383,7 @@ func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
||||
// logger.Info("Private key is %s", fixKey(s.key.String()))
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
@@ -409,20 +416,6 @@ func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
||||
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 {
|
||||
// For netstack, we need to manage peers differently
|
||||
// We'll configure peers directly on the device using IPC
|
||||
@@ -461,6 +454,38 @@ func (s *WireGuardService) ensureWireguardPeers(peers []Peer) error {
|
||||
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 {
|
||||
// parse the key first
|
||||
pubKey, err := wgtypes.ParseKey(peer.PublicKey)
|
||||
@@ -469,7 +494,7 @@ func (s *WireGuardService) addPeerToDevice(peer Peer) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
for _, allowedIP := range peer.AllowedIPs {
|
||||
@@ -559,7 +584,7 @@ func (s *WireGuardService) removePeer(publicKey string) error {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
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
|
||||
if len(request.AllowedIPs) > 0 {
|
||||
@@ -801,6 +826,81 @@ func (s *WireGuardService) reportPeerBandwidth() error {
|
||||
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
|
||||
func (s *WireGuardService) filterReadOnlyFields(config string) string {
|
||||
lines := strings.Split(config, "\n")
|
||||
16
common.go
16
common.go
@@ -3,8 +3,6 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -27,20 +25,6 @@ import (
|
||||
|
||||
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) {
|
||||
logger.Debug("Pinging %s", dst)
|
||||
socket, err := tnet.Dial("ping4", dst)
|
||||
|
||||
2
main.go
2
main.go
@@ -678,7 +678,7 @@ func main() {
|
||||
public_key=%s
|
||||
allowed_ip=%s/32
|
||||
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)
|
||||
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)
|
||||
// This accepts all traffic to 10.20.20.0/24
|
||||
subnet1 := netip.MustParsePrefix("10.20.20.0/24")
|
||||
handler.AddSubnetRule(subnet1, nil)
|
||||
// // Example 1: Add a subnet with no port restrictions (all ports allowed)
|
||||
// // This accepts all traffic to 10.20.20.0/24
|
||||
// subnet1 := netip.MustParsePrefix("10.20.20.0/24")
|
||||
// handler.AddSubnetRule(subnet1, nil)
|
||||
|
||||
// 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
|
||||
subnet2 := netip.MustParsePrefix("10.20.21.21/32")
|
||||
handler.AddSubnetRule(subnet2, []PortRange{
|
||||
{Min: 12000, Max: 12001},
|
||||
{Min: 8000, Max: 8000},
|
||||
})
|
||||
// // 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
|
||||
// subnet2 := netip.MustParsePrefix("10.20.21.21/32")
|
||||
// handler.AddSubnetRule(subnet2, []PortRange{
|
||||
// {Min: 12000, Max: 12001},
|
||||
// {Min: 8000, Max: 8000},
|
||||
// })
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ type netTun struct {
|
||||
mtu int
|
||||
dnsServers []netip.Addr
|
||||
hasV4, hasV6 bool
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -347,6 +348,30 @@ func (net *Net) ListenUDP(laddr *net.UDPAddr) (*gonet.UDPConn, error) {
|
||||
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 {
|
||||
laddr PingAddr
|
||||
raddr PingAddr
|
||||
|
||||
16
util/util.go
16
util/util.go
@@ -1,6 +1,8 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"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)
|
||||
}
|
||||
|
||||
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