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 : }