Monitoring UDP Socket Connections: How to List Active UDP Communications with Server Daemons


4 views

While UDP is indeed connectionless, server daemons maintaining ongoing communications with multiple clients create what we can conceptually call "connections" through socket bindings and ongoing packet exchanges. For monitoring purposes, we need to identify these active communication channels.

The most straightforward approach is using system monitoring tools:


# Show all UDP sockets and their states
ss -uap

# Alternative with netstat (legacy systems)
netstat -uanp

# Filter for specific daemon
ss -uap | grep [process_name]

For more advanced monitoring, we can create a Python script to track UDP communications:


import socket
import psutil

def get_udp_connections():
    udp_stats = {}
    for conn in psutil.net_connections(kind='udp'):
        if conn.status == 'NONE' and conn.raddr:  # UDP with remote address
            key = f"{conn.laddr.ip}:{conn.laddr.port}-{conn.raddr.ip}:{conn.raddr.port}"
            udp_stats[key] = {
                'pid': conn.pid,
                'process': psutil.Process(conn.pid).name() if conn.pid else None,
                'last_activity': conn.last_activity
            }
    return udp_stats

print(get_udp_connections())

For high-performance servers, eBPF provides efficient monitoring:


#include 
#include 

struct udp_event {
    __u32 saddr;
    __u32 daddr;
    __u16 sport;
    __u16 dport;
};

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 10240);
    __type(key, struct udp_event);
    __type(value, __u64);
} active_udp_connections SEC(".maps");

SEC("tracepoint/syscalls/sys_enter_sendto")
int trace_udp_send(struct trace_event_raw_sys_enter *ctx) {
    // Implementation would extract UDP connection info
    // and update the active_udp_connections map
    return 0;
}

When implementing UDP monitoring:

  • Account for NAT when tracking client IPs
  • Handle ephemeral ports in your tracking logic
  • Consider implementing timeouts (e.g., 5 minutes of inactivity)
  • For very high traffic, sample rather than track every packet

For more accurate tracking, instrument your server daemon to log connections:


// Example in C server code
void handle_udp_packet(int sockfd) {
    struct sockaddr_in client_addr;
    socklen_t addr_len = sizeof(client_addr);
    char buffer[1024];
    
    recvfrom(sockfd, buffer, sizeof(buffer), 0,
             (struct sockaddr *)&client_addr, &addr_len);
             
    // Log the client connection
    log_connection(&client_addr);
    
    // Process packet...
}

When working with UDP-based server daemons that communicate with numerous clients, one common challenge is tracking active interactions. Unlike TCP, UDP doesn't maintain connection state, making it difficult to determine which clients are actively communicating with your servers.

The most reliable way to monitor UDP activity is through system utilities:


# Linux systems
ss -uap | grep your_daemon_name

# Alternative with netstat (older systems)
netstat -uanp | grep your_daemon_name

These commands will show all UDP sockets your daemon has open, along with the remote addresses currently communicating with them.

For more detailed analysis, packet capture tools can be useful:


# Basic tcpdump command to monitor UDP traffic
sudo tcpdump -i any udp port your_port -nn -q

# More advanced tshark version
tshark -i any -f "udp port your_port" -T fields -e ip.src -e udp.srcport

For long-term monitoring, you might want to implement tracking within your application:


from collections import defaultdict
import socket
import time

class UDPMonitor:
    def __init__(self):
        self.client_activity = defaultdict(lambda: {'last_seen': 0, 'count': 0})
        self.timeout = 300  # 5 minutes
    
    def record_activity(self, client_address):
        self.client_activity[client_address]['last_seen'] = time.time()
        self.client_activity[client_address]['count'] += 1
    
    def get_active_clients(self):
        now = time.time()
        return [addr for addr, data in self.client_activity.items() 
                if now - data['last_seen'] <= self.timeout]

# Usage example in your UDP handler
monitor = UDPMonitor()

def handle_request(data, client_address):
    monitor.record_activity(client_address)
    # ... rest of your handler logic

For low-level tracking, you can examine kernel structures:


# Show UDP socket information from /proc
cat /proc/net/udp

# More detailed socket info
ls -l /proc/your_pid/fd/ | grep socket

For modern Linux systems, eBPF provides powerful monitoring capabilities:


#!/usr/bin/bpftrace

BEGIN {
    printf("Tracing UDP packets...\n");
}

kprobe:udp_recvmsg {
    $sk = (struct sock *)arg0;
    $lport = $sk->__sk_common.skc_num;
    $daddr = ntop($sk->__sk_common.skc_daddr);
    $saddr = ntop($sk->__sk_common.skc_rcv_saddr);
    
    printf("%-15s:%-5d <- %-15s:%-5d\n", 
           $daddr, $lport, $saddr, $sk->__sk_common.skc_dport);
}

When implementing monitoring in production:

  • Be mindful of performance overhead
  • Consider sampling rather than tracking every packet
  • Implement rate limiting to prevent abuse
  • Log to external systems rather than local files