mirror of
https://github.com/fosrl/newt.git
synced 2026-02-08 05:56:40 +00:00
Basic holepunch working
This commit is contained in:
1
go.mod
1
go.mod
@@ -16,6 +16,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
|
github.com/google/gopacket v1.1.19 // indirect
|
||||||
github.com/josharian/native v1.1.0 // indirect
|
github.com/josharian/native v1.1.0 // indirect
|
||||||
github.com/mdlayher/genetlink v1.3.2 // indirect
|
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||||
|
|||||||
14
go.sum
14
go.sum
@@ -2,6 +2,8 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
|||||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||||
|
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||||
@@ -18,22 +20,34 @@ github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQ
|
|||||||
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
||||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
|
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
|
||||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
||||||
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
|
||||||
|
|||||||
202
network/network.go
Normal file
202
network/network.go
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
udpProtocol = 17
|
||||||
|
// EmptyUDPSize is the size of an empty UDP packet
|
||||||
|
EmptyUDPSize = 28
|
||||||
|
timeout = time.Second * 10
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server stores data relating to the server
|
||||||
|
type Server struct {
|
||||||
|
Hostname string
|
||||||
|
Addr *net.IPAddr
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerNet stores data about a peer's endpoint
|
||||||
|
type PeerNet struct {
|
||||||
|
Resolved bool
|
||||||
|
IP net.IP
|
||||||
|
Port uint16
|
||||||
|
NewtID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClientIP gets source ip address that will be used when sending data to dstIP
|
||||||
|
func GetClientIP(dstIP net.IP) net.IP {
|
||||||
|
routes, err := netlink.RouteGet(dstIP)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error getting route:", err)
|
||||||
|
}
|
||||||
|
return routes[0].Src
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostToAddr resolves a hostname, whether DNS or IP to a valid net.IPAddr
|
||||||
|
func HostToAddr(hostStr string) *net.IPAddr {
|
||||||
|
remoteAddrs, err := net.LookupHost(hostStr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error parsing remote address:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addrStr := range remoteAddrs {
|
||||||
|
if remoteAddr, err := net.ResolveIPAddr("ip4", addrStr); err == nil {
|
||||||
|
return remoteAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupRawConn creates an ipv4 and udp only RawConn and applies packet filtering
|
||||||
|
func SetupRawConn(server *Server, client *PeerNet) *ipv4.RawConn {
|
||||||
|
packetConn, err := net.ListenPacket("ip4:udp", client.IP.String())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error creating packetConn:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawConn, err := ipv4.NewRawConn(packetConn)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error creating rawConn:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplyBPF(rawConn, server, client)
|
||||||
|
|
||||||
|
return rawConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyBPF constructs a BPF program and applies it to the RawConn
|
||||||
|
func ApplyBPF(rawConn *ipv4.RawConn, server *Server, client *PeerNet) {
|
||||||
|
const ipv4HeaderLen = 20
|
||||||
|
const srcIPOffset = 12
|
||||||
|
const srcPortOffset = ipv4HeaderLen + 0
|
||||||
|
const dstPortOffset = ipv4HeaderLen + 2
|
||||||
|
|
||||||
|
ipArr := []byte(server.Addr.IP.To4())
|
||||||
|
ipInt := uint32(ipArr[0])<<(3*8) + uint32(ipArr[1])<<(2*8) + uint32(ipArr[2])<<8 + uint32(ipArr[3])
|
||||||
|
|
||||||
|
bpfRaw, err := bpf.Assemble([]bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{Off: srcIPOffset, Size: 4},
|
||||||
|
bpf.JumpIf{Cond: bpf.JumpEqual, Val: ipInt, SkipFalse: 5, SkipTrue: 0},
|
||||||
|
|
||||||
|
bpf.LoadAbsolute{Off: srcPortOffset, Size: 2},
|
||||||
|
bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(server.Port), SkipFalse: 3, SkipTrue: 0},
|
||||||
|
|
||||||
|
bpf.LoadAbsolute{Off: dstPortOffset, Size: 2},
|
||||||
|
bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(client.Port), SkipFalse: 1, SkipTrue: 0},
|
||||||
|
|
||||||
|
bpf.RetConstant{Val: 1<<(8*4) - 1},
|
||||||
|
bpf.RetConstant{Val: 0},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error assembling BPF:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rawConn.SetBPF(bpfRaw)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error setting BPF:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakePacket constructs a request packet to send to the server
|
||||||
|
func MakePacket(payload []byte, server *Server, client *PeerNet) []byte {
|
||||||
|
buf := gopacket.NewSerializeBuffer()
|
||||||
|
|
||||||
|
opts := gopacket.SerializeOptions{
|
||||||
|
FixLengths: true,
|
||||||
|
ComputeChecksums: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ipHeader := layers.IPv4{
|
||||||
|
SrcIP: client.IP,
|
||||||
|
DstIP: server.Addr.IP,
|
||||||
|
Version: 4,
|
||||||
|
TTL: 64,
|
||||||
|
Protocol: layers.IPProtocolUDP,
|
||||||
|
}
|
||||||
|
|
||||||
|
udpHeader := layers.UDP{
|
||||||
|
SrcPort: layers.UDPPort(client.Port),
|
||||||
|
DstPort: layers.UDPPort(server.Port),
|
||||||
|
}
|
||||||
|
|
||||||
|
payloadLayer := gopacket.Payload(payload)
|
||||||
|
|
||||||
|
udpHeader.SetNetworkLayerForChecksum(&ipHeader)
|
||||||
|
|
||||||
|
gopacket.SerializeLayers(buf, opts, &ipHeader, &udpHeader, &payloadLayer)
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendPacket sends packet to the Server
|
||||||
|
func SendPacket(packet []byte, conn *ipv4.RawConn, server *Server, client *PeerNet) error {
|
||||||
|
fullPacket := MakePacket(packet, server, client)
|
||||||
|
_, err := conn.WriteToIP(fullPacket, server.Addr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendDataPacket sends a JSON payload to the Server
|
||||||
|
func SendDataPacket(data interface{}, conn *ipv4.RawConn, server *Server, client *PeerNet) error {
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal payload: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return SendPacket(jsonData, conn, server, client)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecvPacket receives a UDP packet from server
|
||||||
|
func RecvPacket(conn *ipv4.RawConn, server *Server, client *PeerNet) ([]byte, int, error) {
|
||||||
|
err := conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := make([]byte, 4096)
|
||||||
|
n, err := conn.Read(response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, n, err
|
||||||
|
}
|
||||||
|
return response, n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecvDataPacket receives and unmarshals a JSON packet from server
|
||||||
|
func RecvDataPacket(conn *ipv4.RawConn, server *Server, client *PeerNet) ([]byte, error) {
|
||||||
|
response, n, err := RecvPacket(conn, server, client)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract payload from UDP packet
|
||||||
|
payload := response[EmptyUDPSize:n]
|
||||||
|
return payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseResponse takes a response packet and parses it into an IP and port
|
||||||
|
func ParseResponse(response []byte) (net.IP, uint16) {
|
||||||
|
ip := net.IP(response[:4])
|
||||||
|
port := binary.BigEndian.Uint16(response[4:6])
|
||||||
|
return ip, port
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseForBPF(response []byte) (srcIP net.IP, srcPort uint16, dstPort uint16) {
|
||||||
|
srcIP = net.IP(response[12:16])
|
||||||
|
srcPort = binary.BigEndian.Uint16(response[20:22])
|
||||||
|
dstPort = binary.BigEndian.Uint16(response[22:24])
|
||||||
|
return
|
||||||
|
}
|
||||||
25
nohup.out
Normal file
25
nohup.out
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
INFO: 2025/02/22 23:25:47 Requesting WireGuard configuration from remote server
|
||||||
|
INFO: 2025/02/22 23:25:47 Sent registration message
|
||||||
|
INFO: 2025/02/22 23:25:47 Received message: {newt/wg/receive-config map[ipAddress:100.90.128.1/24 listenPort:51822 peers:[]]}
|
||||||
|
INFO: 2025/02/22 23:25:47 Created WireGuard interface wg1
|
||||||
|
INFO: 2025/02/22 23:25:47 Assigning IP address 100.90.128.1/24 to interface wg1
|
||||||
|
INFO: 2025/02/22 23:25:47 WireGuard interface wg1 created and configured
|
||||||
|
INFO: 2025/02/22 23:25:47 Received registration message
|
||||||
|
INFO: 2025/02/22 23:25:47 Received: {Type:newt/wg/connect Data:map[endpoint:pangolin.fosrl.io:51820 publicKey:tng9Z/BN32flFjqwwT1yAxN/twFkmgbZA+D9N+YqdjM= serverIP:100.89.128.1 targets:map[tcp:[] udp:[]] tunnelIP:100.89.128.4]}
|
||||||
|
INFO: 2025/02/22 23:25:47 WireGuard device created. Lets ping the server now...
|
||||||
|
INFO: 2025/02/22 23:25:47 Ping attempt 1 of 5
|
||||||
|
INFO: 2025/02/22 23:25:47 Pinging 100.89.128.1
|
||||||
|
INFO: 2025/02/22 23:25:47 Ping latency: 9.00105ms
|
||||||
|
INFO: 2025/02/22 23:25:47 Starting ping check
|
||||||
|
INFO: 2025/02/22 23:26:48 Peer P9pacnRfUSfvDibaQTdTk59q27eRpgtbMMmMpkNwKl0= removed successfully
|
||||||
|
INFO: 2025/02/22 23:26:48 Peer NMrcorGgTTi4tAUZ1lLru0qISNrt9D9JdsFGyDYlcSQ= added successfully
|
||||||
|
INFO: 2025/02/22 23:28:58 Peer NMrcorGgTTi4tAUZ1lLru0qISNrt9D9JdsFGyDYlcSQ= removed successfully
|
||||||
|
INFO: 2025/02/22 23:28:58 Peer n8ZKTG8vsROL/OiqHYJELU/Rg9XDifz0YjE/lQsL0m0= added successfully
|
||||||
|
INFO: 2025/02/22 23:33:59 Peer n8ZKTG8vsROL/OiqHYJELU/Rg9XDifz0YjE/lQsL0m0= removed successfully
|
||||||
|
INFO: 2025/02/22 23:33:59 Peer /i8YTgrLkZh08HKXLXqNFQJsyg1E8I2ELXqF0zuP9D8= added successfully
|
||||||
|
INFO: 2025/02/22 23:34:06 Peer /i8YTgrLkZh08HKXLXqNFQJsyg1E8I2ELXqF0zuP9D8= removed successfully
|
||||||
|
INFO: 2025/02/22 23:34:06 Peer 50+RB00sDoSG+KAKzl/baaqPkKGOe7upX7uqRCKqsRo= added successfully
|
||||||
|
INFO: 2025/02/22 23:35:07 Peer 50+RB00sDoSG+KAKzl/baaqPkKGOe7upX7uqRCKqsRo= removed successfully
|
||||||
|
INFO: 2025/02/22 23:35:07 Peer Aa2Y2NEmc+SITlT89+fsOeqDkXJVu9RBY14+77TXa3w= added successfully
|
||||||
|
INFO: 2025/02/23 00:55:55 Peer Aa2Y2NEmc+SITlT89+fsOeqDkXJVu9RBY14+77TXa3w= removed successfully
|
||||||
|
INFO: 2025/02/23 00:55:55 Peer 2AXNjMQzT7GGvdbIG6MJVFpO3FIzQ+qCqZkdSnBA3DE= added successfully
|
||||||
159
wg/wg.go
159
wg/wg.go
@@ -5,10 +5,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fosrl/newt/logger"
|
"github.com/fosrl/newt/logger"
|
||||||
|
"github.com/fosrl/newt/network"
|
||||||
"github.com/fosrl/newt/websocket"
|
"github.com/fosrl/newt/websocket"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"golang.org/x/exp/rand"
|
"golang.org/x/exp/rand"
|
||||||
@@ -214,7 +217,7 @@ func (s *WireGuardService) handleConfig(msg websocket.WSMessage) {
|
|||||||
s.config = config
|
s.config = config
|
||||||
|
|
||||||
// stop the holepunch
|
// stop the holepunch
|
||||||
close(s.stopHolepunch)
|
// close(s.stopHolepunch)
|
||||||
|
|
||||||
// Ensure the WireGuard interface and peers are configured
|
// Ensure the WireGuard interface and peers are configured
|
||||||
if err := s.ensureWireguardInterface(config); err != nil {
|
if err := s.ensureWireguardInterface(config); err != nil {
|
||||||
@@ -373,94 +376,6 @@ func (s *WireGuardService) ensureWireguardPeers(peers []Peer) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (s *WireGuardService) ensureMSSClamping() error {
|
|
||||||
// // Calculate MSS value (MTU - 40 for IPv4 header (20) and TCP header (20))
|
|
||||||
// mssValue := mtuInt - 40
|
|
||||||
|
|
||||||
// // Rules to be managed - just the chains, we'll construct the full command separately
|
|
||||||
// chains := []string{"INPUT", "OUTPUT", "FORWARD"}
|
|
||||||
|
|
||||||
// // First, try to delete any existing rules
|
|
||||||
// for _, chain := range chains {
|
|
||||||
// deleteCmd := exec.Command("/usr/sbin/iptables",
|
|
||||||
// "-t", "mangle",
|
|
||||||
// "-D", chain,
|
|
||||||
// "-p", "tcp",
|
|
||||||
// "--tcp-flags", "SYN,RST", "SYN",
|
|
||||||
// "-j", "TCPMSS",
|
|
||||||
// "--set-mss", fmt.Sprintf("%d", mssValue))
|
|
||||||
|
|
||||||
// logger.Info("Attempting to delete existing MSS clamping rule for chain %s", chain)
|
|
||||||
|
|
||||||
// // Try deletion multiple times to handle multiple existing rules
|
|
||||||
// for i := 0; i < 3; i++ {
|
|
||||||
// out, err := deleteCmd.CombinedOutput()
|
|
||||||
// if err != nil {
|
|
||||||
// // Convert exit status 1 to string for better logging
|
|
||||||
// if exitErr, ok := err.(*exec.ExitError); ok {
|
|
||||||
// logger.Debug("Deletion stopped for chain %s: %v (output: %s)",
|
|
||||||
// chain, exitErr.String(), string(out))
|
|
||||||
// }
|
|
||||||
// break // No more rules to delete
|
|
||||||
// }
|
|
||||||
// logger.Info("Deleted MSS clamping rule for chain %s (attempt %d)", chain, i+1)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Then add the new rules
|
|
||||||
// var errors []error
|
|
||||||
// for _, chain := range chains {
|
|
||||||
// addCmd := exec.Command("/usr/sbin/iptables",
|
|
||||||
// "-t", "mangle",
|
|
||||||
// "-A", chain,
|
|
||||||
// "-p", "tcp",
|
|
||||||
// "--tcp-flags", "SYN,RST", "SYN",
|
|
||||||
// "-j", "TCPMSS",
|
|
||||||
// "--set-mss", fmt.Sprintf("%d", mssValue))
|
|
||||||
|
|
||||||
// logger.Info("Adding MSS clamping rule for chain %s", chain)
|
|
||||||
|
|
||||||
// if out, err := addCmd.CombinedOutput(); err != nil {
|
|
||||||
// errMsg := fmt.Sprintf("Failed to add MSS clamping rule for chain %s: %v (output: %s)",
|
|
||||||
// chain, err, string(out))
|
|
||||||
// logger.Error(errMsg)
|
|
||||||
// errors = append(errors, fmt.Errorf(errMsg))
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Verify the rule was added
|
|
||||||
// checkCmd := exec.Command("/usr/sbin/iptables",
|
|
||||||
// "-t", "mangle",
|
|
||||||
// "-C", chain,
|
|
||||||
// "-p", "tcp",
|
|
||||||
// "--tcp-flags", "SYN,RST", "SYN",
|
|
||||||
// "-j", "TCPMSS",
|
|
||||||
// "--set-mss", fmt.Sprintf("%d", mssValue))
|
|
||||||
|
|
||||||
// if out, err := checkCmd.CombinedOutput(); err != nil {
|
|
||||||
// errMsg := fmt.Sprintf("Rule verification failed for chain %s: %v (output: %s)",
|
|
||||||
// chain, err, string(out))
|
|
||||||
// logger.Error(errMsg)
|
|
||||||
// errors = append(errors, fmt.Errorf(errMsg))
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// logger.Info("Successfully added and verified MSS clamping rule for chain %s", chain)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // If we encountered any errors, return them combined
|
|
||||||
// if len(errors) > 0 {
|
|
||||||
// var errMsgs []string
|
|
||||||
// for _, err := range errors {
|
|
||||||
// errMsgs = append(errMsgs, err.Error())
|
|
||||||
// }
|
|
||||||
// return fmt.Errorf("MSS clamping setup encountered errors:\n%s",
|
|
||||||
// strings.Join(errMsgs, "\n"))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (s *WireGuardService) handleAddPeer(msg websocket.WSMessage) {
|
func (s *WireGuardService) handleAddPeer(msg websocket.WSMessage) {
|
||||||
var peer Peer
|
var peer Peer
|
||||||
|
|
||||||
@@ -681,40 +596,72 @@ func (s *WireGuardService) reportPeerBandwidth() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *WireGuardService) sendUDPHolePunch(serverAddr string) error {
|
func (s *WireGuardService) sendUDPHolePunch(serverAddr string) error {
|
||||||
// Bind to specific local port
|
// Parse server address
|
||||||
localAddr := &net.UDPAddr{
|
serverSplit := strings.Split(serverAddr, ":")
|
||||||
Port: int(s.port),
|
if len(serverSplit) < 2 {
|
||||||
IP: net.IPv4zero,
|
return fmt.Errorf("invalid server address format, expected hostname:port")
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteAddr, err := net.ResolveUDPAddr("udp", serverAddr)
|
serverHostname := serverSplit[0]
|
||||||
|
serverPort, err := strconv.ParseUint(serverSplit[1], 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to resolve UDP address: %v", err)
|
return fmt.Errorf("failed to parse server port: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", localAddr)
|
// Resolve server hostname to IP
|
||||||
if err != nil {
|
serverIPAddr := network.HostToAddr(serverHostname)
|
||||||
return fmt.Errorf("failed to bind UDP socket: %v", err)
|
if serverIPAddr == nil {
|
||||||
|
return fmt.Errorf("failed to resolve server hostname")
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
|
// Get client IP based on route to server
|
||||||
|
clientIP := network.GetClientIP(serverIPAddr.IP)
|
||||||
|
|
||||||
|
// Create server and client configs
|
||||||
|
server := &network.Server{
|
||||||
|
Hostname: serverHostname,
|
||||||
|
Addr: serverIPAddr,
|
||||||
|
Port: uint16(serverPort),
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &network.PeerNet{
|
||||||
|
IP: clientIP,
|
||||||
|
Port: s.port,
|
||||||
|
NewtID: s.newtId,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup raw connection with BPF filtering
|
||||||
|
rawConn := network.SetupRawConn(server, client)
|
||||||
|
defer rawConn.Close()
|
||||||
|
|
||||||
|
// Create JSON payload
|
||||||
payload := struct {
|
payload := struct {
|
||||||
NewtID string `json:"newtId"`
|
NewtID string `json:"newtId"`
|
||||||
}{
|
}{
|
||||||
NewtID: s.newtId,
|
NewtID: s.newtId,
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(payload)
|
// Send the packet using the raw connection
|
||||||
if err != nil {
|
err = network.SendDataPacket(payload, rawConn, server, client)
|
||||||
return fmt.Errorf("failed to marshal payload: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.WriteToUDP(data, remoteAddr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to send UDP packet: %v", err)
|
return fmt.Errorf("failed to send UDP packet: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("Sent UDP hole punch to %s", serverAddr)
|
// logger.Info("Sent UDP hole punch to %s", serverAddr)
|
||||||
|
|
||||||
|
// // Wait for response if needed
|
||||||
|
// response, err := network.RecvDataPacket(rawConn, server, client)
|
||||||
|
// if err != nil {
|
||||||
|
// if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||||
|
// return fmt.Errorf("connection to %s timed out", serverAddr)
|
||||||
|
// }
|
||||||
|
// return fmt.Errorf("error receiving response: %v", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Process response if needed
|
||||||
|
// if len(response) > 0 {
|
||||||
|
// logger.Info("Received response from server")
|
||||||
|
// }
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user