add debug logging for VPN packet flow diagnosis

Add comprehensive console logging at key data path points:
- [TUN-RX]: per-packet TUN read (size, proto, src/dst IP, slow write detection)
- [TUN-TX]: per-packet TUN write (size, success/error)
- [WS-RX]: per-packet WebSocket read from client (size, proto, src/dst IP)
- [WS-TX]: per-packet WebSocket write to client (size, lockWaitMs, writeMs)
- [ROUTE]: routing decisions (TUN->client, client->tun, client->relay, anti-spoof)
- [CONN]: connection lifecycle (init, ready, stats every 10s, disconnect with final stats)
- [STATS]: global traffic stats every 10s (clients, rx/tx bytes and rates)
- [PING]: WebSocket ping failures
- [WS]: WebSocket upgrade with client IP and auth method
- [TUN]: MTU set confirmation, VPN start/stop environment info
This commit is contained in:
2026-07-08 19:14:48 +08:00
parent 3306fc7ee4
commit 616d30bc08
6 changed files with 167 additions and 22 deletions
+37 -2
View File
@@ -1,6 +1,7 @@
package vpn
import (
"log"
"net"
"sync"
@@ -106,6 +107,16 @@ func parseIPAddrs(packet []byte) (src, dest net.IP, ok bool) {
return nil, nil, false
}
func protoName(packet []byte) string {
if waterutil.IsIPv4(packet) {
return "IPv4"
}
if waterutil.IsIPv6(packet) {
return "IPv6"
}
return "unknown"
}
func (s *PacketSwitch) allowC2C() bool {
s.mu.RLock()
v := s.allowClientToClient
@@ -116,43 +127,67 @@ func (s *PacketSwitch) allowC2C() bool {
func (s *PacketSwitch) RouteFromClient(src SwitchConn, packet []byte) []SwitchConn {
srcIP, dest, ok := parseIPAddrs(packet)
if !ok {
log.Printf("[ROUTE] client->? parse failed size=%d", len(packet))
return nil
}
proto := protoName(packet)
// anti-spoof: enforce assigned source IP by version
if srcIP != nil {
if srcIP.To4() != nil {
if !srcIP.Equal(src.AssignedIP()) {
log.Printf("[ROUTE] anti-spoof drop src=%s expected=%s dst=%s proto=%s size=%d",
srcIP, src.AssignedIP(), dest, proto, len(packet))
return nil
}
} else {
assigned6 := src.AssignedIP6()
if assigned6 == nil || !srcIP.Equal(assigned6) {
log.Printf("[ROUTE] anti-spoof drop src=%s expected=%s dst=%s proto=%s size=%d",
srcIP, assigned6, dest, proto, len(packet))
return nil
}
}
}
if dest.IsGlobalUnicast() {
if c := s.findByIP(dest); c != nil && s.allowC2C() {
log.Printf("[ROUTE] client->relay src=%s dst=%s proto=%s size=%d",
src.AssignedIP(), dest, proto, len(packet))
return []SwitchConn{c}
}
log.Printf("[ROUTE] client->tun src=%s dst=%s proto=%s size=%d",
src.AssignedIP(), dest, proto, len(packet))
return nil
}
if s.allowC2C() {
return s.allExcept(src)
targets := s.allExcept(src)
log.Printf("[ROUTE] client->broadcast src=%s dst=%s proto=%s size=%d targets=%d",
src.AssignedIP(), dest, proto, len(packet), len(targets))
return targets
}
log.Printf("[ROUTE] client->drop(broadcast,c2c off) src=%s dst=%s proto=%s size=%d",
src.AssignedIP(), dest, proto, len(packet))
return nil
}
func (s *PacketSwitch) RouteFromTUN(packet []byte) []SwitchConn {
_, dest, ok := parseIPAddrs(packet)
if !ok {
log.Printf("[ROUTE] TUN->? parse failed size=%d", len(packet))
return nil
}
proto := protoName(packet)
if dest.IsGlobalUnicast() {
if c := s.findByIP(dest); c != nil {
log.Printf("[ROUTE] TUN->client dst=%s proto=%s size=%d found=true",
dest, proto, len(packet))
return []SwitchConn{c}
}
log.Printf("[ROUTE] TUN->client dst=%s proto=%s size=%d found=false",
dest, proto, len(packet))
return nil
}
return s.allExcept(nil)
targets := s.allExcept(nil)
log.Printf("[ROUTE] TUN->broadcast dst=%s proto=%s size=%d targets=%d",
dest, proto, len(packet), len(targets))
return targets
}