Getting Latest Handshake Information
Learn how to retrieve handshake information and monitor WireGuard peer connections using the getLatestHandshake function.
Overview
The getLatestHandshake function provides detailed information about all peers connected to a WireGuard interface. This includes handshake timestamps, transfer statistics, endpoints, and connection status - essential for monitoring VPN health and debugging connectivity issues.
What is a Handshake?
A WireGuard handshake is a cryptographic key exchange process that establishes a secure connection between peers. The handshake:
- Establishes encryption keys for secure communication
- Verifies peer identity using public/private key pairs
- Sets up the secure tunnel between peers
- Must be completed before data can be transmitted
Basic Usage
import { getLatestHandshake } from "@kriper0nind/wg-utils"
// Get handshake information for interface wg0
const handshakes = await getLatestHandshake("wg0")
console.log(`Found ${handshakes.length} peers`)
// Display information for each peer
handshakes.forEach((peer, index) => {
console.log(`\nPeer ${index + 1}:`)
console.log(` Public Key: ${peer.publicKey}`)
console.log(` Latest Handshake: ${peer.latestHandshake}`)
console.log(` Endpoint: ${peer.endpoint}`)
console.log(` Transfer: ${peer.transfer}`)
})Understanding the Response
The function returns an array of HandshakeInfo objects, each containing:
interface HandshakeInfo {
publicKey: string // Peer's public key (always present)
handshake?: string // Current handshake timestamp
endpoint?: string // Peer's IP address and port
allowedIps?: string // Allowed IP ranges for this peer
latestHandshake?: string // Most recent successful handshake
transfer?: string // Data transfer statistics (received/sent)
}Field Explanations
- publicKey: The peer's public key (always present)
- latestHandshake: Timestamp of the most recent successful handshake
- endpoint: The peer's IP address and port (e.g., "192.168.1.100:51820")
- allowedIps: IP ranges this peer is allowed to use
- transfer: Data transfer statistics in human-readable format
Common Use Cases
Monitoring Connection Health
import { getLatestHandshake } from "@kriper0nind/wg-utils"
async function checkConnectionHealth(iface: string) {
const handshakes = await getLatestHandshake(iface)
const now = new Date()
const fiveMinutesAgo = new Date(now.getTime() - 5 * 60 * 1000)
for (const peer of handshakes) {
if (peer.latestHandshake) {
const handshakeTime = new Date(peer.latestHandshake)
if (handshakeTime < fiveMinutesAgo) {
console.warn(`⚠️ Peer ${peer.publicKey} hasn't handshaken recently`)
console.warn(` Last handshake: ${peer.latestHandshake}`)
} else {
console.log(`✅ Peer ${peer.publicKey} is active`)
console.log(` Last handshake: ${peer.latestHandshake}`)
}
} else {
console.warn(`❌ Peer ${peer.publicKey} has never handshaken`)
}
}
}
await checkConnectionHealth("wg0")Finding Inactive Peers
import { getLatestHandshake } from "@kriper0nind/wg-utils"
async function findInactivePeers(iface: string, maxAgeMinutes: number = 30) {
const handshakes = await getLatestHandshake(iface)
const cutoff = new Date(Date.now() - maxAgeMinutes * 60 * 1000)
const inactivePeers = handshakes.filter(peer => {
if (!peer.latestHandshake) return true
const lastHandshake = new Date(peer.latestHandshake)
return lastHandshake < cutoff
})
console.log(`Found ${inactivePeers.length} inactive peers (older than ${maxAgeMinutes} minutes)`)
inactivePeers.forEach(peer => {
console.log(`- ${peer.publicKey}: ${peer.latestHandshake || 'Never'}`)
})
return inactivePeers
}
const inactivePeers = await findInactivePeers("wg0", 60) // 1 hourMonitoring Data Transfer
import { getLatestHandshake } from "@kriper0nind/wg-utils"
async function monitorTransfer(iface: string) {
const handshakes = await getLatestHandshake(iface)
console.log("Transfer Statistics:")
handshakes.forEach(peer => {
if (peer.transfer) {
console.log(`Peer ${peer.publicKey.substring(0, 8)}...:`)
console.log(` ${peer.transfer}`)
console.log(` Endpoint: ${peer.endpoint}`)
}
})
}
await monitorTransfer("wg0")Peer Status Dashboard
import { getLatestHandshake } from "@kriper0nind/wg-utils"
async function peerDashboard(iface: string) {
const handshakes = await getLatestHandshake(iface)
console.log(`\n📊 WireGuard Interface: ${iface}`)
console.log(`👥 Total Peers: ${handshakes.length}`)
let activePeers = 0
let inactivePeers = 0
handshakes.forEach((peer, index) => {
const isActive = peer.latestHandshake &&
(Date.now() - new Date(peer.latestHandshake).getTime()) < 5 * 60 * 1000
if (isActive) activePeers++
else inactivePeers++
const status = isActive ? "🟢 Active" : "🔴 Inactive"
console.log(`\n${index + 1}. ${status}`)
console.log(` Key: ${peer.publicKey.substring(0, 16)}...`)
console.log(` Endpoint: ${peer.endpoint || 'Unknown'}`)
console.log(` Last Handshake: ${peer.latestHandshake || 'Never'}`)
if (peer.transfer) {
console.log(` Transfer: ${peer.transfer}`)
}
})
console.log(`\n📈 Summary:`)
console.log(` Active: ${activePeers}`)
console.log(` Inactive: ${inactivePeers}`)
}
await peerDashboard("wg0")Error Handling
import { getLatestHandshake } from "@kriper0nind/wg-utils"
async function safeGetHandshakes(iface: string) {
try {
const handshakes = await getLatestHandshake(iface)
return handshakes
} catch (error) {
if (error.message.includes("No such device")) {
console.error(`Interface ${iface} does not exist or is not running`)
} else if (error.message.includes("Operation not permitted")) {
console.error("Insufficient privileges - run with sudo")
} else {
console.error("Failed to get handshake information:", error.message)
}
return []
}
}
const handshakes = await safeGetHandshakes("wg0")Best Practices
- Regular Monitoring: Check handshakes periodically to ensure connections are healthy
- Age Thresholds: Define acceptable handshake age limits (e.g., 5-30 minutes)
- Logging: Keep logs of handshake patterns for debugging
- Alerting: Set up alerts for peers that haven't handshaken recently
- Cleanup: Remove peers that have been inactive for extended periods
Troubleshooting
Common Issues
"No such device" error:- Interface doesn't exist or isn't running
- Check with
wg showcommand
- No peers are configured
- Peers haven't connected yet
- Interface might be down
- Network connectivity issues
- Firewall blocking connections
- Peer configuration problems
Debugging Commands
# Check if interface exists and is running
wg show
# Check specific interface
wg show wg0
# Check interface status with more detail
wg show wg0 dumpRelated Functions
up- Start a WireGuard interfacedown- Stop a WireGuard interfacesyncConf- Synchronize interface configurationaddPeer- Add a peer to configurationdeletePeer- Remove a peer from configuration