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:
+60
-8
@@ -41,22 +41,42 @@ type tunnelConn struct {
|
||||
ready atomic.Bool
|
||||
rxBytes atomic.Int64
|
||||
txBytes atomic.Int64
|
||||
rxPkts atomic.Int64
|
||||
txPkts atomic.Int64
|
||||
}
|
||||
|
||||
func (c *tunnelConn) AssignedIP() net.IP { return c.assignedIP }
|
||||
func (c *tunnelConn) AssignedIP6() net.IP { return c.assignedIP6 }
|
||||
|
||||
func (c *tunnelConn) label() string {
|
||||
s := "user=" + c.user.Username + " ip=" + c.assignedIP.String()
|
||||
if c.assignedIP6 != nil {
|
||||
s += " ip6=" + c.assignedIP6.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (c *tunnelConn) WritePacket(data []byte) error {
|
||||
if !c.ready.Load() || len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
lockStart := time.Now()
|
||||
c.writeMu.Lock()
|
||||
lockWait := time.Since(lockStart)
|
||||
defer c.writeMu.Unlock()
|
||||
c.conn.SetWriteDeadline(time.Now().Add(writeTimeout))
|
||||
if err := c.conn.WriteMessage(websocket.BinaryMessage, data); err != nil {
|
||||
writeStart := time.Now()
|
||||
err := c.conn.WriteMessage(websocket.BinaryMessage, data)
|
||||
writeDur := time.Since(writeStart)
|
||||
if err != nil {
|
||||
log.Printf("[WS-TX] %s size=%d lockWaitMs=%d writeMs=%d ok=false err=%v",
|
||||
c.label(), len(data), lockWait.Milliseconds(), writeDur.Milliseconds(), err)
|
||||
return err
|
||||
}
|
||||
c.txBytes.Add(int64(len(data)))
|
||||
c.txPkts.Add(1)
|
||||
log.Printf("[WS-TX] %s size=%d lockWaitMs=%d writeMs=%d ok=true",
|
||||
c.label(), len(data), lockWait.Milliseconds(), writeDur.Milliseconds())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -150,13 +170,13 @@ func runTunnel(conn *websocket.Conn, user *model.User) {
|
||||
initMsg.ServerIP6 = VPN.ServerIP6().String()
|
||||
}
|
||||
if err := tc.writeControl(initMsg); err != nil {
|
||||
log.Printf("用户 %s 发送 init 失败: %v", user.Username, err)
|
||||
log.Printf("[CONN] init failed %s err=%v", tc.label(), err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("用户 %s 已连接,分配 IP %s", user.Username, ip4.String())
|
||||
log.Printf("[CONN] init sent %s mtu=%d prefix=%d server=%s", tc.label(), settings.MTU, VPN.Prefix(), VPN.ServerIP().String())
|
||||
if ip6 != nil {
|
||||
log.Printf(" IPv6: %s", ip6.String())
|
||||
log.Printf("[CONN] init6 sent %s ip6=%s prefix6=%d server6=%s", tc.label(), ip6.String(), VPN.Prefix6(), VPN.ServerIP6().String())
|
||||
}
|
||||
|
||||
conn.SetReadLimit(maxMessageSize)
|
||||
@@ -170,12 +190,32 @@ func runTunnel(conn *websocket.Conn, user *model.User) {
|
||||
tc.writeMu.Lock()
|
||||
if err := conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(writeTimeout)); err != nil {
|
||||
tc.writeMu.Unlock()
|
||||
log.Printf("[PING] failed %s err=%v", tc.label(), err)
|
||||
return
|
||||
}
|
||||
tc.writeMu.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(10 * time.Second)
|
||||
defer ticker.Stop()
|
||||
var lastRx, lastTx int64
|
||||
for range ticker.C {
|
||||
if !tc.ready.Load() {
|
||||
return
|
||||
}
|
||||
rx := tc.rxBytes.Load()
|
||||
tx := tc.txBytes.Load()
|
||||
rxRate := rx - lastRx
|
||||
txRate := tx - lastTx
|
||||
log.Printf("[CONN] stats %s rxBytes=%d txBytes=%d rxRate=%dB/s txRate=%dB/s rxPkts=%d txPkts=%d",
|
||||
tc.label(), rx, tx, rxRate/10, txRate/10, tc.rxPkts.Load(), tc.txPkts.Load())
|
||||
lastRx = rx
|
||||
lastTx = tx
|
||||
}
|
||||
}()
|
||||
|
||||
conn.SetPongHandler(func(string) error {
|
||||
conn.SetReadDeadline(time.Now().Add(readTimeout))
|
||||
return nil
|
||||
@@ -184,7 +224,10 @@ func runTunnel(conn *websocket.Conn, user *model.User) {
|
||||
for {
|
||||
messageType, data, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
log.Printf("用户 %s 断开连接: %v", user.Username, err)
|
||||
duration := time.Since(tc.connectedAt)
|
||||
log.Printf("[CONN] disconnected %s duration=%s rxBytes=%d txBytes=%d rxPkts=%d txPkts=%d err=%v",
|
||||
tc.label(), duration.Round(time.Second), tc.rxBytes.Load(), tc.txBytes.Load(),
|
||||
tc.rxPkts.Load(), tc.txPkts.Load(), err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -196,7 +239,7 @@ func runTunnel(conn *websocket.Conn, user *model.User) {
|
||||
if msg.Type == "ready" && !tc.ready.Load() {
|
||||
tc.ready.Store(true)
|
||||
conn.SetReadDeadline(time.Now().Add(readTimeout))
|
||||
log.Printf("用户 %s 就绪 (IP %s)", user.Username, ip4.String())
|
||||
log.Printf("[CONN] ready %s", tc.label())
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -207,7 +250,7 @@ func runTunnel(conn *websocket.Conn, user *model.User) {
|
||||
|
||||
if !tc.ready.Load() {
|
||||
if time.Now().After(readyDeadline) {
|
||||
log.Printf("用户 %s 等待 ready 超时", user.Username)
|
||||
log.Printf("[CONN] ready timeout %s", tc.label())
|
||||
return
|
||||
}
|
||||
conn.SetReadDeadline(readyDeadline)
|
||||
@@ -215,11 +258,20 @@ func runTunnel(conn *websocket.Conn, user *model.User) {
|
||||
}
|
||||
|
||||
tc.rxBytes.Add(int64(len(data)))
|
||||
tc.rxPkts.Add(1)
|
||||
|
||||
srcIP, destIP, ok := parseIPAddrs(data)
|
||||
if ok {
|
||||
log.Printf("[WS-RX] %s size=%d proto=%s src=%s dst=%s",
|
||||
tc.label(), len(data), protoName(data), srcIP, destIP)
|
||||
} else {
|
||||
log.Printf("[WS-RX] %s size=%d parse=fail", tc.label(), len(data))
|
||||
}
|
||||
|
||||
targets := VPN.RouteFromClient(tc, data)
|
||||
if len(targets) == 0 {
|
||||
if err := VPN.WriteToTUN(data); err != nil {
|
||||
log.Printf("用户 %s 写入 TUN 失败: %v", user.Username, err)
|
||||
log.Printf("[WS-RX] %s action=tun err=%v size=%d", tc.label(), err, len(data))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user