ant_quic/candidate_discovery/
linux.rs

1//! Linux-specific network interface discovery using netlink sockets
2//!
3//! This module provides production-ready network interface enumeration and monitoring
4//! for Linux platforms using netlink sockets for real-time network change detection.
5
6use std::{
7    collections::HashMap,
8    ffi::{CStr, CString},
9    io,
10    mem,
11    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
12    os::unix::io::{AsRawFd, RawFd},
13    ptr,
14    slice,
15    time::Instant,
16};
17
18use nix::libc;
19use tracing::{debug, error, info, warn};
20
21use crate::candidate_discovery::{NetworkInterface, NetworkInterfaceDiscovery};
22
23/// Linux-specific network interface discovery using netlink
24pub struct LinuxInterfaceDiscovery {
25    /// Cached interface data to detect changes
26    cached_interfaces: HashMap<u32, LinuxInterface>,
27    /// Last scan timestamp for cache validation
28    last_scan_time: Option<Instant>,
29    /// Cache TTL for interface data
30    cache_ttl: std::time::Duration,
31    /// Current scan state
32    scan_state: ScanState,
33    /// Netlink socket for interface monitoring
34    netlink_socket: Option<NetlinkSocket>,
35    /// Interface enumeration configuration
36    interface_config: InterfaceConfig,
37}
38
39/// Internal representation of a Linux network interface
40#[derive(Debug, Clone)]
41struct LinuxInterface {
42    /// Interface index
43    index: u32,
44    /// Interface name
45    name: String,
46    /// Interface type
47    interface_type: InterfaceType,
48    /// Interface flags
49    flags: InterfaceFlags,
50    /// MTU size
51    mtu: u32,
52    /// IPv4 addresses with prefix length
53    ipv4_addresses: Vec<(Ipv4Addr, u8)>,
54    /// IPv6 addresses with prefix length
55    ipv6_addresses: Vec<(Ipv6Addr, u8)>,
56    /// Hardware address (MAC)
57    hardware_address: Option<[u8; 6]>,
58    /// Interface state
59    state: InterfaceState,
60    /// Last update timestamp
61    last_updated: Instant,
62}
63
64/// Linux interface types derived from netlink messages
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66enum InterfaceType {
67    /// Ethernet interface
68    Ethernet,
69    /// Wireless interface
70    Wireless,
71    /// Loopback interface
72    Loopback,
73    /// Tunnel interface
74    Tunnel,
75    /// Point-to-point interface
76    PointToPoint,
77    /// Bridge interface
78    Bridge,
79    /// VLAN interface
80    Vlan,
81    /// Bond interface
82    Bond,
83    /// Virtual interface
84    Virtual,
85    /// Unknown interface type
86    Unknown(u16),
87}
88
89/// Interface flags from netlink
90#[derive(Debug, Clone, Copy, Default)]
91struct InterfaceFlags {
92    /// Interface is up
93    is_up: bool,
94    /// Interface is running
95    is_running: bool,
96    /// Interface is loopback
97    is_loopback: bool,
98    /// Interface is point-to-point
99    is_point_to_point: bool,
100    /// Interface supports multicast
101    supports_multicast: bool,
102    /// Interface supports broadcast
103    supports_broadcast: bool,
104    /// Interface is wireless
105    is_wireless: bool,
106}
107
108/// Interface operational state
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110enum InterfaceState {
111    /// Unknown state
112    Unknown,
113    /// Interface is not present
114    NotPresent,
115    /// Interface is down
116    Down,
117    /// Interface is in lower layer down
118    LowerLayerDown,
119    /// Interface is testing
120    Testing,
121    /// Interface is dormant
122    Dormant,
123    /// Interface is up
124    Up,
125}
126
127/// Current state of the scanning process
128#[derive(Debug, Clone, PartialEq)]
129enum ScanState {
130    /// No scan in progress
131    Idle,
132    /// Scan initiated, waiting for completion
133    InProgress { started_at: Instant },
134    /// Scan completed, results available
135    Completed { scan_results: Vec<NetworkInterface> },
136    /// Scan failed with error
137    Failed { error: String },
138}
139
140/// Netlink socket for interface monitoring
141struct NetlinkSocket {
142    /// Socket file descriptor
143    socket_fd: i32,
144    /// Sequence number for netlink messages
145    sequence_number: u32,
146    /// Process ID for netlink messages
147    process_id: u32,
148    /// Buffer for receiving netlink messages
149    receive_buffer: Vec<u8>,
150    /// Last message timestamp
151    last_message_time: Option<Instant>,
152}
153
154/// Configuration for interface enumeration
155#[derive(Debug, Clone)]
156struct InterfaceConfig {
157    /// Include loopback interfaces
158    include_loopback: bool,
159    /// Include down interfaces
160    include_down: bool,
161    /// Include IPv6 addresses
162    include_ipv6: bool,
163    /// Minimum MTU size to consider
164    min_mtu: u32,
165    /// Maximum interfaces to enumerate
166    max_interfaces: u32,
167    /// Enable real-time monitoring
168    enable_monitoring: bool,
169    /// Filter by interface types
170    allowed_interface_types: Vec<InterfaceType>,
171}
172
173/// Linux netlink error types
174#[derive(Debug, Clone)]
175enum LinuxNetworkError {
176    /// Netlink socket creation failed
177    SocketCreationFailed { error: String },
178    /// Failed to bind netlink socket
179    SocketBindFailed { error: String },
180    /// Failed to send netlink message
181    MessageSendFailed { error: String },
182    /// Failed to receive netlink message
183    MessageReceiveFailed { error: String },
184    /// Invalid netlink message format
185    InvalidMessage { message: String },
186    /// Interface not found
187    InterfaceNotFound { interface_name: String },
188    /// Permission denied for netlink operations
189    PermissionDenied { operation: String },
190    /// System limit exceeded
191    SystemLimitExceeded { limit_type: String },
192    /// Network namespace error
193    NetworkNamespaceError { error: String },
194    /// Interface enumeration timeout
195    EnumerationTimeout { timeout: std::time::Duration },
196}
197
198/// Netlink message types
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200enum NetlinkMessageType {
201    /// Get link information
202    GetLink,
203    /// Get address information
204    GetAddress,
205    /// Link state change
206    LinkStateChange,
207    /// Address change
208    AddressChange,
209    /// Route change
210    RouteChange,
211}
212
213/// Netlink message parsing result
214#[derive(Debug, Clone)]
215struct NetlinkMessage {
216    /// Message type
217    message_type: NetlinkMessageType,
218    /// Message flags
219    flags: u16,
220    /// Message sequence number
221    sequence: u32,
222    /// Message payload
223    payload: Vec<u8>,
224}
225
226impl LinuxInterfaceDiscovery {
227    /// Create a new Linux interface discovery instance
228    pub fn new() -> Self {
229        Self {
230            cached_interfaces: HashMap::new(),
231            last_scan_time: None,
232            cache_ttl: std::time::Duration::from_secs(30),
233            scan_state: ScanState::Idle,
234            netlink_socket: None,
235            interface_config: InterfaceConfig {
236                include_loopback: false,
237                include_down: false,
238                include_ipv6: true,
239                min_mtu: 1280, // IPv6 minimum MTU
240                max_interfaces: 64,
241                enable_monitoring: true,
242                allowed_interface_types: vec![
243                    InterfaceType::Ethernet,
244                    InterfaceType::Wireless,
245                    InterfaceType::Tunnel,
246                    InterfaceType::Bridge,
247                ],
248            },
249        }
250    }
251
252    /// Set interface configuration
253    pub fn set_interface_config(&mut self, config: InterfaceConfig) {
254        self.interface_config = config;
255    }
256
257    /// Initialize netlink socket for interface monitoring
258    pub fn initialize_netlink_socket(&mut self) -> Result<(), LinuxNetworkError> {
259        if self.netlink_socket.is_some() {
260            return Ok(());
261        }
262
263        // Create netlink socket
264        let socket_fd = unsafe {
265            libc::socket(
266                libc::AF_NETLINK,
267                libc::SOCK_RAW | libc::SOCK_CLOEXEC,
268                libc::NETLINK_ROUTE,
269            )
270        };
271
272        if socket_fd < 0 {
273            return Err(LinuxNetworkError::SocketCreationFailed {
274                error: format!("Failed to create netlink socket: {}", 
275                    std::io::Error::last_os_error()),
276            });
277        }
278
279        // Set up socket address
280        let mut addr: libc::sockaddr_nl = unsafe { std::mem::zeroed() };
281        addr.nl_family = libc::AF_NETLINK as u16;
282        addr.nl_pid = 0; // Kernel will assign PID
283        addr.nl_groups = (1 << (libc::RTNLGRP_LINK - 1)) | (1 << (libc::RTNLGRP_IPV4_IFADDR - 1)) | (1 << (libc::RTNLGRP_IPV6_IFADDR - 1));
284
285        // Bind socket
286        let bind_result = unsafe {
287            libc::bind(
288                socket_fd,
289                &addr as *const libc::sockaddr_nl as *const libc::sockaddr,
290                std::mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t,
291            )
292        };
293
294        if bind_result < 0 {
295            unsafe { libc::close(socket_fd); }
296            return Err(LinuxNetworkError::SocketBindFailed {
297                error: format!("Failed to bind netlink socket: {}", 
298                    std::io::Error::last_os_error()),
299            });
300        }
301
302        // Get assigned PID
303        let mut addr_len = std::mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;
304        let getsockname_result = unsafe {
305            libc::getsockname(
306                socket_fd,
307                &mut addr as *mut libc::sockaddr_nl as *mut libc::sockaddr,
308                &mut addr_len,
309            )
310        };
311
312        if getsockname_result < 0 {
313            unsafe { libc::close(socket_fd); }
314            return Err(LinuxNetworkError::SocketBindFailed {
315                error: format!("Failed to get socket name: {}", 
316                    std::io::Error::last_os_error()),
317            });
318        }
319
320        // Set socket to non-blocking mode
321        let flags = unsafe { libc::fcntl(socket_fd, libc::F_GETFL) };
322        if flags >= 0 {
323            unsafe {
324                libc::fcntl(socket_fd, libc::F_SETFL, flags | libc::O_NONBLOCK);
325            }
326        }
327
328        self.netlink_socket = Some(NetlinkSocket {
329            socket_fd,
330            sequence_number: 1,
331            process_id: addr.nl_pid,
332            receive_buffer: vec![0; 8192],
333            last_message_time: None,
334        });
335
336        debug!("Netlink socket initialized with PID {}", addr.nl_pid);
337        Ok(())
338    }
339
340    /// Check for netlink messages indicating network changes
341    pub fn check_network_changes(&mut self) -> Result<bool, LinuxNetworkError> {
342        let socket = match self.netlink_socket.as_mut() {
343            Some(socket) => socket,
344            None => return Ok(false),
345        };
346
347        let mut changes_detected = false;
348
349        // Read available messages
350        loop {
351            let bytes_read = unsafe {
352                libc::recv(
353                    socket.socket_fd,
354                    socket.receive_buffer.as_mut_ptr() as *mut libc::c_void,
355                    socket.receive_buffer.len(),
356                    0,
357                )
358            };
359
360            if bytes_read < 0 {
361                let error = std::io::Error::last_os_error();
362                match error.kind() {
363                    std::io::ErrorKind::WouldBlock => break, // No more messages
364                    _ => {
365                        return Err(LinuxNetworkError::MessageReceiveFailed {
366                            error: format!("Failed to receive netlink message: {}", error),
367                        });
368                    }
369                }
370            }
371
372            if bytes_read == 0 {
373                break; // No more data
374            }
375
376            // Parse netlink messages
377            let messages = Self::parse_netlink_messages(&socket.receive_buffer[..bytes_read as usize])?;
378            
379            for message in messages {
380                match message.message_type {
381                    NetlinkMessageType::LinkStateChange |
382                    NetlinkMessageType::AddressChange => {
383                        changes_detected = true;
384                        debug!("Network change detected: {:?}", message.message_type);
385                    }
386                    _ => {}
387                }
388            }
389
390            socket.last_message_time = Some(Instant::now());
391        }
392
393        Ok(changes_detected)
394    }
395
396    /// Parse netlink messages from buffer
397    fn parse_netlink_messages(buffer: &[u8]) -> Result<Vec<NetlinkMessage>, LinuxNetworkError> {
398        let mut messages = Vec::new();
399        let mut offset = 0;
400
401        while offset + 16 <= buffer.len() {
402            // Parse netlink header
403            let length = u32::from_ne_bytes([
404                buffer[offset],
405                buffer[offset + 1],
406                buffer[offset + 2],
407                buffer[offset + 3],
408            ]) as usize;
409
410            if length < 16 || offset + length > buffer.len() {
411                break; // Invalid or incomplete message
412            }
413
414            let msg_type = u16::from_ne_bytes([
415                buffer[offset + 4],
416                buffer[offset + 5],
417            ]);
418
419            let flags = u16::from_ne_bytes([
420                buffer[offset + 6],
421                buffer[offset + 7],
422            ]);
423
424            let sequence = u32::from_ne_bytes([
425                buffer[offset + 8],
426                buffer[offset + 9],
427                buffer[offset + 10],
428                buffer[offset + 11],
429            ]);
430
431            let message_type = match msg_type {
432                libc::RTM_NEWLINK | libc::RTM_DELLINK => NetlinkMessageType::LinkStateChange,
433                libc::RTM_NEWADDR | libc::RTM_DELADDR => NetlinkMessageType::AddressChange,
434                libc::RTM_NEWROUTE | libc::RTM_DELROUTE => NetlinkMessageType::RouteChange,
435                _ => {
436                    offset += length;
437                    continue;
438                }
439            };
440
441            let payload = if length > 16 {
442                buffer[offset + 16..offset + length].to_vec()
443            } else {
444                Vec::new()
445            };
446
447            messages.push(NetlinkMessage {
448                message_type,
449                flags,
450                sequence,
451                payload,
452            });
453
454            offset += length;
455        }
456
457        Ok(messages)
458    }
459
460    /// Enumerate network interfaces using netlink
461    fn enumerate_interfaces(&mut self) -> Result<Vec<LinuxInterface>, LinuxNetworkError> {
462        let mut interfaces = Vec::new();
463
464        // Read /proc/net/dev for basic interface information
465        let proc_net_dev = match std::fs::read_to_string("/proc/net/dev") {
466            Ok(content) => content,
467            Err(e) => {
468                return Err(LinuxNetworkError::InterfaceNotFound {
469                    interface_name: format!("Failed to read /proc/net/dev: {}", e),
470                });
471            }
472        };
473
474        // Parse /proc/net/dev
475        for line in proc_net_dev.lines().skip(2) {
476            let parts: Vec<&str> = line.split_whitespace().collect();
477            if parts.len() < 2 {
478                continue;
479            }
480
481            let interface_name = parts[0].trim_end_matches(':');
482            if interface_name.is_empty() {
483                continue;
484            }
485
486            match self.get_interface_details(interface_name) {
487                Ok(interface) => {
488                    if self.should_include_interface(&interface) {
489                        interfaces.push(interface);
490                    }
491                }
492                Err(e) => {
493                    warn!("Failed to get interface details for {}: {:?}", interface_name, e);
494                }
495            }
496
497            if interfaces.len() >= self.interface_config.max_interfaces as usize {
498                break;
499            }
500        }
501
502        debug!("Enumerated {} network interfaces", interfaces.len());
503        Ok(interfaces)
504    }
505
506    /// Get detailed information about a specific interface
507    fn get_interface_details(&self, interface_name: &str) -> Result<LinuxInterface, LinuxNetworkError> {
508        // Get interface index
509        let interface_index = self.get_interface_index(interface_name)?;
510        
511        // Get interface flags and state
512        let (flags, state, mtu) = self.get_interface_flags_and_state(interface_name)?;
513        
514        // Determine interface type
515        let interface_type = self.determine_interface_type(interface_name, &flags)?;
516        
517        // Get hardware address
518        let hardware_address = self.get_hardware_address(interface_name).ok();
519        
520        // Get IP addresses
521        let ipv4_addresses = self.get_ipv4_addresses(interface_name)?;
522        let ipv6_addresses = if self.interface_config.include_ipv6 {
523            self.get_ipv6_addresses(interface_name)?
524        } else {
525            Vec::new()
526        };
527
528        Ok(LinuxInterface {
529            index: interface_index,
530            name: interface_name.to_string(),
531            interface_type,
532            flags,
533            mtu,
534            ipv4_addresses,
535            ipv6_addresses,
536            hardware_address,
537            state,
538            last_updated: Instant::now(),
539        })
540    }
541
542    /// Get interface index from name
543    fn get_interface_index(&self, interface_name: &str) -> Result<u32, LinuxNetworkError> {
544        let c_name = std::ffi::CString::new(interface_name).map_err(|_| {
545            LinuxNetworkError::InterfaceNotFound {
546                interface_name: format!("Invalid interface name: {}", interface_name),
547            }
548        })?;
549
550        let index = unsafe { libc::if_nametoindex(c_name.as_ptr()) };
551        if index == 0 {
552            return Err(LinuxNetworkError::InterfaceNotFound {
553                interface_name: interface_name.to_string(),
554            });
555        }
556
557        Ok(index)
558    }
559
560    /// Get interface flags and state
561    fn get_interface_flags_and_state(&self, interface_name: &str) -> Result<(InterfaceFlags, InterfaceState, u32), LinuxNetworkError> {
562        let socket_fd = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
563        if socket_fd < 0 {
564            return Err(LinuxNetworkError::SocketCreationFailed {
565                error: "Failed to create socket for interface query".to_string(),
566            });
567        }
568
569        let mut ifreq: libc::ifreq = unsafe { std::mem::zeroed() };
570        let name_bytes = interface_name.as_bytes();
571        let copy_len = std::cmp::min(name_bytes.len(), libc::IFNAMSIZ - 1);
572        
573        unsafe {
574            std::ptr::copy_nonoverlapping(
575                name_bytes.as_ptr(),
576                ifreq.ifr_name.as_mut_ptr() as *mut u8,
577                copy_len,
578            );
579        }
580
581        // Get interface flags
582        let flags_result = unsafe { libc::ioctl(socket_fd, libc::SIOCGIFFLAGS, &mut ifreq) };
583        if flags_result < 0 {
584            unsafe { libc::close(socket_fd); }
585            return Err(LinuxNetworkError::InterfaceNotFound {
586                interface_name: format!("Failed to get flags for interface {}", interface_name),
587            });
588        }
589
590        let raw_flags = unsafe { ifreq.ifr_ifru.ifru_flags };
591        let flags = InterfaceFlags {
592            is_up: (raw_flags & libc::IFF_UP as i16) != 0,
593            is_running: (raw_flags & libc::IFF_RUNNING as i16) != 0,
594            is_loopback: (raw_flags & libc::IFF_LOOPBACK as i16) != 0,
595            is_point_to_point: (raw_flags & libc::IFF_POINTOPOINT as i16) != 0,
596            supports_multicast: (raw_flags & libc::IFF_MULTICAST as i16) != 0,
597            supports_broadcast: (raw_flags & libc::IFF_BROADCAST as i16) != 0,
598            is_wireless: self.is_wireless_interface(interface_name),
599        };
600
601        // Get MTU
602        let mtu_result = unsafe { libc::ioctl(socket_fd, libc::SIOCGIFMTU, &mut ifreq) };
603        let mtu = if mtu_result >= 0 {
604            unsafe { ifreq.ifr_ifru.ifru_mtu as u32 }
605        } else {
606            1500 // Default MTU
607        };
608
609        unsafe { libc::close(socket_fd); }
610
611        // Determine interface state
612        let state = if flags.is_up && flags.is_running {
613            InterfaceState::Up
614        } else if flags.is_up {
615            InterfaceState::Down
616        } else {
617            InterfaceState::Down
618        };
619
620        Ok((flags, state, mtu))
621    }
622
623    /// Determine interface type from name and characteristics
624    fn determine_interface_type(&self, interface_name: &str, flags: &InterfaceFlags) -> Result<InterfaceType, LinuxNetworkError> {
625        if flags.is_loopback {
626            return Ok(InterfaceType::Loopback);
627        }
628
629        if flags.is_point_to_point {
630            return Ok(InterfaceType::PointToPoint);
631        }
632
633        if flags.is_wireless {
634            return Ok(InterfaceType::Wireless);
635        }
636
637        // Check interface name patterns
638        if interface_name.starts_with("eth") || interface_name.starts_with("en") {
639            return Ok(InterfaceType::Ethernet);
640        }
641
642        if interface_name.starts_with("wlan") || interface_name.starts_with("wl") {
643            return Ok(InterfaceType::Wireless);
644        }
645
646        if interface_name.starts_with("tun") || interface_name.starts_with("tap") {
647            return Ok(InterfaceType::Tunnel);
648        }
649
650        if interface_name.starts_with("br") {
651            return Ok(InterfaceType::Bridge);
652        }
653
654        if interface_name.contains('.') {
655            return Ok(InterfaceType::Vlan);
656        }
657
658        if interface_name.starts_with("bond") {
659            return Ok(InterfaceType::Bond);
660        }
661
662        if interface_name.starts_with("veth") || interface_name.starts_with("docker") {
663            return Ok(InterfaceType::Virtual);
664        }
665
666        Ok(InterfaceType::Unknown(0))
667    }
668
669    /// Check if interface is wireless
670    fn is_wireless_interface(&self, interface_name: &str) -> bool {
671        // Check for wireless interface indicators
672        if interface_name.starts_with("wlan") || interface_name.starts_with("wl") {
673            return true;
674        }
675
676        // Check if wireless extensions are available
677        let wireless_path = format!("/sys/class/net/{}/wireless", interface_name);
678        std::path::Path::new(&wireless_path).exists()
679    }
680
681    /// Get hardware address for interface
682    fn get_hardware_address(&self, interface_name: &str) -> Result<[u8; 6], LinuxNetworkError> {
683        let socket_fd = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
684        if socket_fd < 0 {
685            return Err(LinuxNetworkError::SocketCreationFailed {
686                error: "Failed to create socket for hardware address query".to_string(),
687            });
688        }
689
690        let mut ifreq: libc::ifreq = unsafe { std::mem::zeroed() };
691        let name_bytes = interface_name.as_bytes();
692        let copy_len = std::cmp::min(name_bytes.len(), libc::IFNAMSIZ - 1);
693        
694        unsafe {
695            std::ptr::copy_nonoverlapping(
696                name_bytes.as_ptr(),
697                ifreq.ifr_name.as_mut_ptr() as *mut u8,
698                copy_len,
699            );
700        }
701
702        let result = unsafe { libc::ioctl(socket_fd, libc::SIOCGIFHWADDR, &mut ifreq) };
703        unsafe { libc::close(socket_fd); }
704
705        if result < 0 {
706            return Err(LinuxNetworkError::InterfaceNotFound {
707                interface_name: format!("Failed to get hardware address for {}", interface_name),
708            });
709        }
710
711        let mut hw_addr = [0u8; 6];
712        unsafe {
713            std::ptr::copy_nonoverlapping(
714                ifreq.ifr_ifru.ifru_hwaddr.sa_data.as_ptr() as *const u8,
715                hw_addr.as_mut_ptr(),
716                6,
717            );
718        }
719
720        Ok(hw_addr)
721    }
722
723    /// Get IPv4 addresses for interface
724    fn get_ipv4_addresses(&self, interface_name: &str) -> Result<Vec<(Ipv4Addr, u8)>, LinuxNetworkError> {
725        let mut addresses = Vec::new();
726        
727        // Read /proc/net/fib_trie for IPv4 addresses
728        // This is a simplified implementation - production code would use netlink
729        let socket_fd = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
730        if socket_fd < 0 {
731            return Ok(addresses);
732        }
733
734        let mut ifreq: libc::ifreq = unsafe { std::mem::zeroed() };
735        let name_bytes = interface_name.as_bytes();
736        let copy_len = std::cmp::min(name_bytes.len(), libc::IFNAMSIZ - 1);
737        
738        unsafe {
739            std::ptr::copy_nonoverlapping(
740                name_bytes.as_ptr(),
741                ifreq.ifr_name.as_mut_ptr() as *mut u8,
742                copy_len,
743            );
744        }
745
746        let result = unsafe { libc::ioctl(socket_fd, libc::SIOCGIFADDR, &mut ifreq) };
747        if result >= 0 {
748            let sockaddr_in = unsafe { 
749                &*(&ifreq.ifr_ifru.ifru_addr as *const libc::sockaddr as *const libc::sockaddr_in)
750            };
751            
752            if sockaddr_in.sin_family == libc::AF_INET as u16 {
753                let ip_bytes = sockaddr_in.sin_addr.s_addr.to_ne_bytes();
754                let ipv4_addr = Ipv4Addr::from(ip_bytes);
755                
756                // Get netmask
757                let netmask_result = unsafe { libc::ioctl(socket_fd, libc::SIOCGIFNETMASK, &mut ifreq) };
758                let prefix_len = if netmask_result >= 0 {
759                    let netmask_sockaddr_in = unsafe { 
760                        &*(&ifreq.ifr_ifru.ifru_netmask as *const libc::sockaddr as *const libc::sockaddr_in)
761                    };
762                    let netmask_bytes = netmask_sockaddr_in.sin_addr.s_addr.to_ne_bytes();
763                    let netmask = u32::from_ne_bytes(netmask_bytes);
764                    netmask.count_ones() as u8
765                } else {
766                    24 // Default /24
767                };
768                
769                addresses.push((ipv4_addr, prefix_len));
770            }
771        }
772
773        unsafe { libc::close(socket_fd); }
774        Ok(addresses)
775    }
776
777    /// Get IPv6 addresses for interface
778    fn get_ipv6_addresses(&self, interface_name: &str) -> Result<Vec<(Ipv6Addr, u8)>, LinuxNetworkError> {
779        let mut addresses = Vec::new();
780        
781        // Read /proc/net/if_inet6 for IPv6 addresses
782        let if_inet6_content = match std::fs::read_to_string("/proc/net/if_inet6") {
783            Ok(content) => content,
784            Err(_) => return Ok(addresses), // IPv6 not available
785        };
786
787        for line in if_inet6_content.lines() {
788            let parts: Vec<&str> = line.split_whitespace().collect();
789            if parts.len() >= 6 {
790                let addr_str = parts[0];
791                let prefix_len_str = parts[1];
792                let if_name = parts[5];
793                
794                if if_name == interface_name {
795                    if let Ok(prefix_len) = u8::from_str_radix(prefix_len_str, 16) {
796                        // Parse IPv6 address from hex string
797                        if addr_str.len() == 32 {
798                            // Convert hex string to bytes
799                            let mut ipv6_bytes = [0u8; 16];
800                            let mut valid = true;
801                            for i in 0..16 {
802                                if let Ok(byte) = u8::from_str_radix(&addr_str[i*2..i*2+2], 16) {
803                                    ipv6_bytes[i] = byte;
804                                } else {
805                                    valid = false;
806                                    break;
807                                }
808                            }
809                            if valid {
810                                let ipv6_addr = Ipv6Addr::from(ipv6_bytes);
811                                addresses.push((ipv6_addr, prefix_len));
812                            }
813                        }
814                    }
815                }
816            }
817        }
818
819        Ok(addresses)
820    }
821
822    /// Check if an interface should be included based on configuration
823    fn should_include_interface(&self, interface: &LinuxInterface) -> bool {
824        // Check loopback filter
825        if interface.flags.is_loopback && !self.interface_config.include_loopback {
826            return false;
827        }
828
829        // Check operational state filter
830        if interface.state != InterfaceState::Up && !self.interface_config.include_down {
831            return false;
832        }
833
834        // Check MTU filter
835        if interface.mtu < self.interface_config.min_mtu {
836            return false;
837        }
838
839        // Check interface type filter
840        if !self.interface_config.allowed_interface_types.is_empty() && 
841           !self.interface_config.allowed_interface_types.contains(&interface.interface_type) {
842            return false;
843        }
844
845        // Check if interface has any usable addresses
846        if interface.ipv4_addresses.is_empty() && interface.ipv6_addresses.is_empty() {
847            return false;
848        }
849
850        true
851    }
852
853    /// Convert Linux interface to generic NetworkInterface
854    fn convert_to_network_interface(&self, linux_interface: &LinuxInterface) -> NetworkInterface {
855        let mut addresses = Vec::new();
856
857        // Add IPv4 addresses
858        for (ipv4, _prefix) in &linux_interface.ipv4_addresses {
859            addresses.push(SocketAddr::new(IpAddr::V4(*ipv4), 0));
860        }
861
862        // Add IPv6 addresses
863        for (ipv6, _prefix) in &linux_interface.ipv6_addresses {
864            addresses.push(SocketAddr::new(IpAddr::V6(*ipv6), 0));
865        }
866
867        NetworkInterface {
868            name: linux_interface.name.clone(),
869            addresses,
870            is_up: linux_interface.state == InterfaceState::Up,
871            is_wireless: linux_interface.flags.is_wireless,
872            mtu: Some(linux_interface.mtu as u16),
873        }
874    }
875
876    /// Update cached interfaces with new scan results
877    fn update_cache(&mut self, interfaces: Vec<LinuxInterface>) {
878        self.cached_interfaces.clear();
879        for interface in interfaces {
880            self.cached_interfaces.insert(interface.index, interface);
881        }
882        self.last_scan_time = Some(Instant::now());
883    }
884
885    /// Check if cache is valid
886    fn is_cache_valid(&self) -> bool {
887        if let Some(last_scan) = self.last_scan_time {
888            last_scan.elapsed() < self.cache_ttl
889        } else {
890            false
891        }
892    }
893}
894
895impl NetworkInterfaceDiscovery for LinuxInterfaceDiscovery {
896    fn start_scan(&mut self) -> Result<(), String> {
897        debug!("Starting Linux network interface scan");
898        
899        // Initialize netlink socket if monitoring is enabled
900        if self.interface_config.enable_monitoring {
901            if let Err(e) = self.initialize_netlink_socket() {
902                warn!("Failed to initialize netlink socket: {:?}", e);
903            }
904        }
905
906        // Check if we need to scan or can use cache
907        if self.is_cache_valid() {
908            if let Ok(changes) = self.check_network_changes() {
909                if !changes {
910                    debug!("Using cached interface data");
911                    let interfaces: Vec<NetworkInterface> = self.cached_interfaces
912                        .values()
913                        .map(|li| self.convert_to_network_interface(li))
914                        .collect();
915                    
916                    self.scan_state = ScanState::Completed {
917                        scan_results: interfaces,
918                    };
919                    return Ok(());
920                }
921            }
922        }
923
924        // Perform fresh scan
925        self.scan_state = ScanState::InProgress {
926            started_at: Instant::now(),
927        };
928
929        match self.enumerate_interfaces() {
930            Ok(interfaces) => {
931                debug!("Successfully enumerated {} interfaces", interfaces.len());
932                
933                // Convert to generic NetworkInterface format
934                let network_interfaces: Vec<NetworkInterface> = interfaces
935                    .iter()
936                    .map(|li| self.convert_to_network_interface(li))
937                    .collect();
938
939                // Update cache
940                self.update_cache(interfaces);
941                
942                self.scan_state = ScanState::Completed {
943                    scan_results: network_interfaces,
944                };
945                
946                info!("Network interface scan completed successfully");
947                Ok(())
948            }
949            Err(e) => {
950                let error_msg = format!("Linux interface enumeration failed: {:?}", e);
951                error!("{}", error_msg);
952                self.scan_state = ScanState::Failed {
953                    error: error_msg.clone(),
954                };
955                Err(error_msg)
956            }
957        }
958    }
959
960    fn check_scan_complete(&mut self) -> Option<Vec<NetworkInterface>> {
961        match &self.scan_state {
962            ScanState::Completed { scan_results } => {
963                let results = scan_results.clone();
964                self.scan_state = ScanState::Idle;
965                Some(results)
966            }
967            ScanState::Failed { error } => {
968                warn!("Scan failed: {}", error);
969                self.scan_state = ScanState::Idle;
970                None
971            }
972            _ => None,
973        }
974    }
975}
976
977impl Drop for LinuxInterfaceDiscovery {
978    fn drop(&mut self) {
979        // Clean up netlink socket
980        if let Some(socket) = self.netlink_socket.take() {
981            unsafe {
982                libc::close(socket.socket_fd);
983            }
984        }
985    }
986}
987
988impl std::fmt::Display for LinuxNetworkError {
989    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
990        match self {
991            Self::SocketCreationFailed { error } => {
992                write!(f, "Socket creation failed: {}", error)
993            }
994            Self::SocketBindFailed { error } => {
995                write!(f, "Socket bind failed: {}", error)
996            }
997            Self::MessageSendFailed { error } => {
998                write!(f, "Message send failed: {}", error)
999            }
1000            Self::MessageReceiveFailed { error } => {
1001                write!(f, "Message receive failed: {}", error)
1002            }
1003            Self::InvalidMessage { message } => {
1004                write!(f, "Invalid message: {}", message)
1005            }
1006            Self::InterfaceNotFound { interface_name } => {
1007                write!(f, "Interface not found: {}", interface_name)
1008            }
1009            Self::PermissionDenied { operation } => {
1010                write!(f, "Permission denied for operation: {}", operation)
1011            }
1012            Self::SystemLimitExceeded { limit_type } => {
1013                write!(f, "System limit exceeded: {}", limit_type)
1014            }
1015            Self::NetworkNamespaceError { error } => {
1016                write!(f, "Network namespace error: {}", error)
1017            }
1018            Self::EnumerationTimeout { timeout } => {
1019                write!(f, "Enumeration timeout: {:?}", timeout)
1020            }
1021        }
1022    }
1023}
1024
1025impl std::error::Error for LinuxNetworkError {}
1026
1027#[cfg(test)]
1028mod tests {
1029    use super::*;
1030
1031    #[test]
1032    fn test_linux_interface_discovery_creation() {
1033        let discovery = LinuxInterfaceDiscovery::new();
1034        assert!(discovery.cached_interfaces.is_empty());
1035        assert!(discovery.last_scan_time.is_none());
1036    }
1037
1038    #[test]
1039    fn test_interface_config() {
1040        let mut discovery = LinuxInterfaceDiscovery::new();
1041        let config = InterfaceConfig {
1042            include_loopback: true,
1043            include_down: true,
1044            include_ipv6: false,
1045            min_mtu: 1000,
1046            max_interfaces: 32,
1047            enable_monitoring: false,
1048            allowed_interface_types: vec![InterfaceType::Ethernet],
1049        };
1050        
1051        discovery.set_interface_config(config.clone());
1052        assert_eq!(discovery.interface_config.include_loopback, true);
1053        assert_eq!(discovery.interface_config.min_mtu, 1000);
1054    }
1055
1056    #[test]
1057    fn test_wireless_interface_detection() {
1058        let discovery = LinuxInterfaceDiscovery::new();
1059        
1060        assert!(discovery.is_wireless_interface("wlan0"));
1061        assert!(discovery.is_wireless_interface("wl0"));
1062        assert!(!discovery.is_wireless_interface("eth0"));
1063    }
1064
1065    #[test]
1066    fn test_interface_type_determination() {
1067        let discovery = LinuxInterfaceDiscovery::new();
1068        let flags = InterfaceFlags::default();
1069        
1070        assert_eq!(
1071            discovery.determine_interface_type("eth0", &flags).unwrap(),
1072            InterfaceType::Ethernet
1073        );
1074        assert_eq!(
1075            discovery.determine_interface_type("wlan0", &flags).unwrap(),
1076            InterfaceType::Wireless
1077        );
1078        assert_eq!(
1079            discovery.determine_interface_type("tun0", &flags).unwrap(),
1080            InterfaceType::Tunnel
1081        );
1082    }
1083
1084    #[test]
1085    fn test_cache_validation() {
1086        let mut discovery = LinuxInterfaceDiscovery::new();
1087        
1088        // No cache initially
1089        assert!(!discovery.is_cache_valid());
1090        
1091        // Set cache time
1092        discovery.last_scan_time = Some(Instant::now());
1093        assert!(discovery.is_cache_valid());
1094        
1095        // Expired cache
1096        discovery.last_scan_time = Some(Instant::now() - std::time::Duration::from_secs(60));
1097        assert!(!discovery.is_cache_valid());
1098    }
1099}