LCOV - code coverage report
Current view: top level - app/shared - fd_net_util.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 57 110 51.8 %
Date: 2025-03-20 12:08:36 Functions: 2 4 50.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fd_net_util.h"
       3             : 
       4             : #include <fcntl.h>
       5             : #include <errno.h>
       6             : #include <sched.h>
       7             : #include <unistd.h>
       8             : #include <net/if.h>
       9             : #include <sys/ioctl.h>
      10             : #include <sys/socket.h>
      11             : #include <linux/netlink.h>
      12             : #include <linux/rtnetlink.h>
      13             : #include <netinet/in.h>
      14             : 
      15             : int
      16             : fd_net_util_netns_enter( const char * name,
      17           0 :                          int *        original_netns ) {
      18           0 :   char path[ PATH_MAX ];
      19           0 :   if( FD_UNLIKELY( !fd_cstr_printf_check( path, PATH_MAX, NULL, "/var/run/netns/%s", name ) ) ) {
      20           0 :     errno = ENAMETOOLONG;
      21           0 :     return -1;
      22           0 :   }
      23             : 
      24           0 :   int _original_netns = -1;
      25           0 :   if( FD_LIKELY( original_netns ) ) {
      26           0 :     *original_netns = -1;
      27           0 :     _original_netns = open( "/proc/self/ns/net", O_RDONLY | O_CLOEXEC );
      28           0 :     if( FD_UNLIKELY( -1==_original_netns ) ) return -1;
      29           0 :   }
      30             : 
      31           0 :   int fd = open( path, O_RDONLY | O_CLOEXEC );
      32           0 :   if( FD_UNLIKELY( -1==fd ) ) {
      33           0 :     int err = errno;
      34           0 :     if( FD_LIKELY( original_netns ) ) close( _original_netns );
      35           0 :     errno = err;
      36           0 :     return -1;
      37           0 :   }
      38           0 :   if( FD_UNLIKELY( setns( fd, CLONE_NEWNET ) ) ) {
      39           0 :     int err = errno;
      40           0 :     if( FD_LIKELY( original_netns ) ) close( _original_netns );
      41           0 :     errno = err;
      42           0 :     return -1;
      43           0 :   }
      44             : 
      45           0 :   if( FD_LIKELY( original_netns ) ) *original_netns = _original_netns;
      46           0 :   if( FD_UNLIKELY( -1==close( fd ) ) ) return -1;
      47             : 
      48             :   /* `ip link set dev lo up`
      49             :      Done via the ioctl API for simplicity.  Requires a dummy socket. */
      50           0 :   int ifreq_fd = socket( AF_INET, SOCK_DGRAM, 0 );
      51           0 :   if( FD_UNLIKELY( -1==ifreq_fd ) ) return -1;
      52           0 :   struct ifreq ifr = { .ifr_name = "lo" };
      53           0 :   if( FD_UNLIKELY( -1==ioctl( ifreq_fd, SIOCGIFFLAGS, &ifr ) ) ) return -1;
      54           0 :   ifr.ifr_flags |= (IFF_UP|IFF_RUNNING);
      55           0 :   if( FD_UNLIKELY( -1==ioctl( ifreq_fd, SIOCSIFFLAGS, &ifr ) ) ) return -1;
      56           0 :   if( FD_UNLIKELY( -1==close( ifreq_fd ) ) ) return -1;
      57             : 
      58           0 :   return 0;
      59           0 : }
      60             : 
      61             : int
      62           0 : fd_net_util_netns_restore( int original_fd ) {
      63           0 :   if( FD_UNLIKELY( -1==setns( original_fd, CLONE_NEWNET ) ) ) return -1;
      64           0 :   if( FD_UNLIKELY( -1==close( original_fd ) ) ) return -1;
      65           0 :   return 0;
      66           0 : }
      67             : 
      68             : int
      69           3 : fd_net_util_internet_ifindex( uint * ifindex ) {
      70           3 :   int sock = socket( AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
      71           3 :   if( FD_UNLIKELY( -1==sock ) ) return -1;
      72             : 
      73           3 :   struct {
      74           3 :     struct nlmsghdr nlh;
      75           3 :     struct rtmsg rt;
      76           3 :     char buf[ 8192UL ];
      77           3 :   } request;
      78             : 
      79           3 :   memset(&request, 0, sizeof(request));
      80           3 :   request.nlh.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
      81           3 :   request.nlh.nlmsg_flags = NLM_F_REQUEST;
      82           3 :   request.nlh.nlmsg_type  = RTM_GETROUTE;
      83           3 :   request.rt.rtm_family   = AF_INET;
      84           3 :   request.rt.rtm_dst_len  = 32;
      85             : 
      86           3 :   struct rtattr *rta = (struct rtattr *)( ( (char *)&request ) + NLMSG_ALIGN( request.nlh.nlmsg_len ) );
      87           3 :   rta->rta_len          = RTA_LENGTH(4);
      88           3 :   rta->rta_type         = RTA_DST;
      89           3 :   request.nlh.nlmsg_len = NLMSG_ALIGN( request.nlh.nlmsg_len ) + (uint)RTA_LENGTH( 4 );
      90             : 
      91           3 :   uint ip = (8 << 24) | (8 << 16) | (8 << 8) | 8;
      92           3 :   fd_memcpy( RTA_DATA( rta ), &ip, 4 );
      93             : 
      94           3 :   long sent = send( sock, &request, request.nlh.nlmsg_len, 0 );
      95           3 :   if( FD_UNLIKELY( -1==sent ) ) {
      96           0 :     close( sock );
      97           0 :     return -1;
      98           0 :   }
      99           3 :   FD_TEST( sent==request.nlh.nlmsg_len );
     100             : 
     101           3 :   char response[ 8192UL ];
     102           3 :   long len = recv( sock, response, sizeof(response), 0 );
     103           3 :   if( FD_UNLIKELY( -1==len ) ) {
     104           0 :     close( sock );
     105           0 :     return -1;
     106           3 :   } else if( FD_UNLIKELY( len==sizeof(response) ) ) {
     107           0 :     errno = ENOBUFS;
     108           0 :     close( sock );
     109           0 :     return -1;
     110           0 :   }
     111             : 
     112           3 :   struct nlmsghdr *nlh;
     113           3 :   int result = -1;
     114           3 :   for( nlh = (struct nlmsghdr *)response; NLMSG_OK( nlh, len ); nlh = NLMSG_NEXT( nlh, len ) ) {
     115           3 :       struct rtmsg *rt = NLMSG_DATA( nlh );
     116             : 
     117           3 :       struct rtattr *rta = RTM_RTA( rt );
     118           3 :       uint rtl = (uint)RTM_PAYLOAD( nlh );
     119             : 
     120          21 :       for (; RTA_OK( rta, rtl ); rta = RTA_NEXT( rta, rtl ) ) {
     121          21 :           if (rta->rta_type == RTA_OIF) {
     122           3 :             result = *(int *)RTA_DATA(rta);
     123           3 :           }
     124          21 :       }
     125           3 :   }
     126             : 
     127           3 :   if( FD_UNLIKELY( -1==close( sock ) ) ) return -1;
     128             : 
     129           3 :   if( FD_LIKELY( result>=0 ) ) {
     130           3 :     *ifindex = (uint)result;
     131           3 :     return 0;
     132           3 :   } else {
     133           0 :     errno = ENODEV;
     134           0 :     return -1;
     135           0 :   }
     136           3 : }
     137             : 
     138             : int
     139             : fd_net_util_if_addr( const char * interface,
     140           3 :                      uint *       addr ) {
     141           3 :   int fd = socket( AF_INET, SOCK_DGRAM, 0 );
     142           3 :   if( FD_UNLIKELY( -1==fd ) ) return -1;
     143             : 
     144           3 :   struct ifreq ifr = {0};
     145           3 :   ifr.ifr_addr.sa_family = AF_INET;
     146           3 :   strncpy( ifr.ifr_name, interface, IFNAMSIZ );
     147           3 :   ifr.ifr_name[ IFNAMSIZ-1 ] = '\0';
     148             : 
     149           3 :   if( FD_UNLIKELY( -1==ioctl( fd, SIOCGIFADDR, &ifr ) ) ) return -1;
     150           3 :   if( FD_UNLIKELY( -1==close( fd ) ) ) return -1;
     151             : 
     152           3 :   *addr = ((struct sockaddr_in *)fd_type_pun( &ifr.ifr_addr ))->sin_addr.s_addr;
     153           3 :   return 0;
     154           3 : }

Generated by: LCOV version 1.14