(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
check_native.c
       1  /* Determine whether interfaces use native transport.  Linux version.
       2     Copyright (C) 2007-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <assert.h>
      20  #include <errno.h>
      21  #include <ifaddrs.h>
      22  #include <stddef.h>
      23  #include <stdint.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <time.h>
      27  #include <unistd.h>
      28  #include <net/if.h>
      29  #include <net/if_arp.h>
      30  #include <sys/ioctl.h>
      31  
      32  #include <asm/types.h>
      33  #include <linux/netlink.h>
      34  #include <linux/rtnetlink.h>
      35  
      36  #include <not-cancel.h>
      37  
      38  #include "netlinkaccess.h"
      39  
      40  void
      41  __check_native (uint32_t a1_index, int *a1_native,
      42  		uint32_t a2_index, int *a2_native)
      43  {
      44    int fd = __socket (PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
      45  
      46    struct sockaddr_nl nladdr;
      47    memset (&nladdr, '\0', sizeof (nladdr));
      48    nladdr.nl_family = AF_NETLINK;
      49  
      50    socklen_t addr_len = sizeof (nladdr);
      51  
      52    if (fd < 0)
      53      return;
      54  
      55    /* Netlink requires that user buffer needs to be either 8kb or page size
      56       (whichever is bigger), however this has been changed over time and now
      57       8Kb is sufficient (check NLMSG_DEFAULT_SIZE on Linux
      58       linux/include/linux/netlink.h).  */
      59    const size_t buf_size = 8192;
      60    char *buf = malloc (buf_size);
      61  
      62    if (buf == NULL)
      63      goto out;
      64  
      65    if (__bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) != 0
      66        || __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) != 0)
      67      goto out;
      68  
      69    pid_t pid = nladdr.nl_pid;
      70    struct req
      71    {
      72      struct nlmsghdr nlh;
      73      struct rtgenmsg g;
      74      /* struct rtgenmsg consists of a single byte.  This means there
      75         are three bytes of padding included in the REQ definition.
      76         We make them explicit here.  */
      77      char pad[3];
      78    } req;
      79  
      80    req.nlh.nlmsg_len = sizeof (req);
      81    req.nlh.nlmsg_type = RTM_GETLINK;
      82    req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
      83    req.nlh.nlmsg_pid = 0;
      84    req.nlh.nlmsg_seq = time_now ();
      85    req.g.rtgen_family = AF_UNSPEC;
      86  
      87    assert (sizeof (req) - offsetof (struct req, pad) == 3);
      88    memset (req.pad, '\0', sizeof (req.pad));
      89  
      90    memset (&nladdr, '\0', sizeof (nladdr));
      91    nladdr.nl_family = AF_NETLINK;
      92  
      93    struct iovec iov = { buf, buf_size };
      94  
      95    if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
      96  				    (struct sockaddr *) &nladdr,
      97  				    sizeof (nladdr))) < 0)
      98      goto out;
      99  
     100    bool done = false;
     101    do
     102      {
     103        struct msghdr msg =
     104  	{
     105  	  .msg_name = (void *) &nladdr,
     106  	  .msg_namelen =  sizeof (nladdr),
     107  	  .msg_iov = &iov,
     108  	  .msg_iovlen = 1,
     109  	  .msg_control = NULL,
     110  	  .msg_controllen = 0,
     111  	  .msg_flags = 0
     112  	};
     113  
     114        ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
     115        __netlink_assert_response (fd, read_len);
     116        if (read_len < 0)
     117  	goto out;
     118  
     119        if (msg.msg_flags & MSG_TRUNC)
     120  	goto out;
     121  
     122        struct nlmsghdr *nlmh;
     123        for (nlmh = (struct nlmsghdr *) buf;
     124  	   NLMSG_OK (nlmh, (size_t) read_len);
     125  	   nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len))
     126  	{
     127  	  if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != pid
     128  	      || nlmh->nlmsg_seq != req.nlh.nlmsg_seq)
     129  	    continue;
     130  
     131  	  if (nlmh->nlmsg_type == RTM_NEWLINK)
     132  	    {
     133  	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlmh);
     134  	      int native = (ifim->ifi_type != ARPHRD_TUNNEL6
     135  			    && ifim->ifi_type != ARPHRD_TUNNEL
     136  			    && ifim->ifi_type != ARPHRD_SIT);
     137  
     138  	      if (a1_index == ifim->ifi_index)
     139  		{
     140  		  *a1_native = native;
     141  		  a1_index = 0xffffffffu;
     142  		}
     143  	      if (a2_index == ifim->ifi_index)
     144  		{
     145  		  *a2_native = native;
     146  		  a2_index = 0xffffffffu;
     147  		}
     148  
     149  	      if (a1_index == 0xffffffffu
     150  		  && a2_index == 0xffffffffu)
     151  		goto out;
     152  	    }
     153  	  else if (nlmh->nlmsg_type == NLMSG_DONE)
     154  	    /* We found the end, leave the loop.  */
     155  	    done = true;
     156  	}
     157      }
     158    while (! done);
     159  
     160  out:
     161    __close_nocancel_nostatus (fd);
     162    free (buf);
     163  }