@ -24,9 +24,17 @@
# include <arpa/inet.h>
# include <ifaddrs.h>
# include <net/if.h>
# include <linux/netlink.h>
# include <linux/rtnetlink.h>
# ifndef IFA_F_TEMPORARY
# define IFA_F_TEMPORARY 0x01
# endif
# ifndef IFA_F_MANAGETEMPADDR
# define IFA_F_MANAGETEMPADDR 0x100
# endif
# ifndef IFA_F_STABLE_PRIVACY
# define IFA_F_STABLE_PRIVACY 0x800
# endif
# endif
/*
@ -106,6 +114,87 @@ int get_interface_ipv6_by_index(uint32_t netif_index, int temporary, uint8_t* ad
return found ? 0 : - 1 ;
}
/* get_interface_ipv6_addr_nl — netlink-based IPv6 address lookup with proper IFA_F_* flags
*
* getifaddrs ( ) ifa_flags contains interface flags ( IFF_UP etc . ) , NOT address flags
* ( IFA_F_TEMPORARY ) . To properly distinguish temporary vs permanent IPv6 addresses ,
* we must use netlink RTM_GETADDR which exposes IFA_FLAGS attribute with real flags :
* - Temporary : IFA_F_TEMPORARY = 1 , IFA_F_MANAGETEMPADDR = 0
* - Stable / mngtmp : IFA_F_TEMPORARY = 1 , IFA_F_MANAGETEMPADDR = 1
* - Legacy static : IFA_F_TEMPORARY = 0 , IFA_F_MANAGETEMPADDR = 0
*
* prefer_stable = 1 : prefer permanent / stable ( IFA_F_MANAGETEMPADDR or ! IFA_F_TEMPORARY )
* prefer_stable = 0 : prefer temporary ( IFA_F_TEMPORARY & & ! IFA_F_MANAGETEMPADDR )
* Fallback : first non - link - local address */
int get_interface_ipv6_addr_nl ( uint32_t netif_index , int prefer_stable , uint8_t * addr_out ) {
if ( ! addr_out | | ! netif_index ) return - 1 ;
memset ( addr_out , 0 , 16 ) ;
int nl_sock = socket ( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
if ( nl_sock < 0 ) return - 1 ;
struct {
struct nlmsghdr nlh ;
struct ifaddrmsg ifa ;
char attrbuf [ 64 ] ;
} req ;
memset ( & req , 0 , sizeof ( req ) ) ;
req . nlh . nlmsg_len = NLMSG_LENGTH ( sizeof ( struct ifaddrmsg ) ) ;
req . nlh . nlmsg_type = RTM_GETADDR ;
req . nlh . nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP ;
req . nlh . nlmsg_seq = 1 ;
req . ifa . ifa_family = AF_INET6 ;
req . ifa . ifa_index = netif_index ;
if ( send ( nl_sock , & req , req . nlh . nlmsg_len , 0 ) < 0 ) { close ( nl_sock ) ; return - 1 ; }
uint8_t fallback [ 16 ] , stable_addr [ 16 ] , temp_addr [ 16 ] ;
int has_fallback = 0 , has_stable = 0 , has_temp = 0 ;
char buf [ 8192 ] ;
int done = 0 ;
while ( ! done ) {
ssize_t len = recv ( nl_sock , buf , sizeof ( buf ) , 0 ) ;
if ( len < 0 ) break ;
struct nlmsghdr * nlh = ( struct nlmsghdr * ) buf ;
for ( ; NLMSG_OK ( nlh , ( size_t ) len ) ; nlh = NLMSG_NEXT ( nlh , len ) ) {
if ( nlh - > nlmsg_type = = NLMSG_DONE ) { done = 1 ; break ; }
if ( nlh - > nlmsg_type ! = RTM_NEWADDR ) continue ;
struct ifaddrmsg * ifa = ( struct ifaddrmsg * ) NLMSG_DATA ( nlh ) ;
if ( ifa - > ifa_family ! = AF_INET6 ) continue ;
if ( ifa - > ifa_index ! = netif_index ) continue ;
uint8_t * addr = NULL ;
uint32_t ifa_flags = 0 ;
struct rtattr * rta = IFA_RTA ( ifa ) ;
int rta_len = IFA_PAYLOAD ( nlh ) ;
for ( ; RTA_OK ( rta , rta_len ) ; rta = RTA_NEXT ( rta , rta_len ) ) {
if ( rta - > rta_type = = IFA_ADDRESS ) addr = RTA_DATA ( rta ) ;
if ( rta - > rta_type = = IFA_FLAGS ) ifa_flags = * ( uint32_t * ) RTA_DATA ( rta ) ;
}
if ( ! addr ) continue ;
if ( ( addr [ 0 ] & 0xfe ) = = 0xfe & & addr [ 1 ] = = 0x80 ) continue ; // skip link-local
int is_temp = ( ifa_flags & IFA_F_TEMPORARY ) ! = 0 ;
int is_mngtmp = ( ifa_flags & IFA_F_MANAGETEMPADDR ) ! = 0 ;
if ( ! has_fallback ) { memcpy ( fallback , addr , 16 ) ; has_fallback = 1 ; }
if ( ! has_stable & & ( ! is_temp | | is_mngtmp ) ) { memcpy ( stable_addr , addr , 16 ) ; has_stable = 1 ; }
if ( ! has_temp & & is_temp & & ! is_mngtmp ) { memcpy ( temp_addr , addr , 16 ) ; has_temp = 1 ; }
}
}
close ( nl_sock ) ;
if ( prefer_stable & & has_stable ) { memcpy ( addr_out , stable_addr , 16 ) ; return 0 ; }
if ( ! prefer_stable & & has_temp ) { memcpy ( addr_out , temp_addr , 16 ) ; return 0 ; }
if ( has_stable ) { memcpy ( addr_out , stable_addr , 16 ) ; return 0 ; }
if ( has_temp ) { memcpy ( addr_out , temp_addr , 16 ) ; return 0 ; }
if ( has_fallback ) { memcpy ( addr_out , fallback , 16 ) ; return 0 ; }
return - 1 ;
}
uint32_t get_default_route_netif_index ( int family ) {
if ( family ! = AF_INET & & family ! = AF_INET6 ) return 0 ;
@ -191,6 +280,12 @@ int get_interface_ipv6_by_index(uint32_t netif_index, int temporary, uint8_t* ad
return - 1 ;
}
int get_interface_ipv6_addr_nl ( uint32_t netif_index , int prefer_stable , uint8_t * addr_out ) {
( void ) netif_index ; ( void ) prefer_stable ;
if ( addr_out ) memset ( addr_out , 0 , 16 ) ;
return - 1 ;
}
uint32_t get_default_route_netif_index ( int family ) {
( void ) family ;
return 0 ;