"Fossies" - the Fresh Open Source Software Archive

Member "dnsmasq-2.85/src/netlink.c" (7 Apr 2021, 11189 Bytes) of package /linux/misc/dns/dnsmasq-2.85.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "netlink.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.84_vs_2.85.

    1 /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
    2 
    3    This program is free software; you can redistribute it and/or modify
    4    it under the terms of the GNU General Public License as published by
    5    the Free Software Foundation; version 2 dated June, 1991, or
    6    (at your option) version 3 dated 29 June, 2007.
    7  
    8    This program is distributed in the hope that it will be useful,
    9    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11    GNU General Public License for more details.
   12      
   13    You should have received a copy of the GNU General Public License
   14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15 */
   16 
   17 #include "dnsmasq.h"
   18 
   19 #ifdef HAVE_LINUX_NETWORK
   20 
   21 #include <linux/types.h>
   22 #include <linux/netlink.h>
   23 #include <linux/rtnetlink.h>
   24 
   25 /* Blergh. Radv does this, so that's our excuse. */
   26 #ifndef SOL_NETLINK
   27 #define SOL_NETLINK 270
   28 #endif
   29 
   30 #ifndef NETLINK_NO_ENOBUFS
   31 #define NETLINK_NO_ENOBUFS 5
   32 #endif
   33 
   34 /* linux 2.6.19 buggers up the headers, patch it up here. */ 
   35 #ifndef IFA_RTA
   36 #  define IFA_RTA(r)  \
   37        ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
   38 
   39 #  include <linux/if_addr.h>
   40 #endif
   41 
   42 #ifndef NDA_RTA
   43 #  define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) 
   44 #endif
   45 
   46 /* Used to request refresh of addresses or routes just once,
   47  * when multiple changes might be announced. */
   48 enum async_states {
   49   STATE_NEWADDR = (1 << 0),
   50   STATE_NEWROUTE = (1 << 1),
   51 };
   52 
   53 
   54 static struct iovec iov;
   55 static u32 netlink_pid;
   56 
   57 static unsigned nl_async(struct nlmsghdr *h, unsigned state);
   58 static void nl_multicast_state(unsigned state);
   59 
   60 char *netlink_init(void)
   61 {
   62   struct sockaddr_nl addr;
   63   socklen_t slen = sizeof(addr);
   64 
   65   addr.nl_family = AF_NETLINK;
   66   addr.nl_pad = 0;
   67   addr.nl_pid = 0; /* autobind */
   68   addr.nl_groups = RTMGRP_IPV4_ROUTE;
   69   if (option_bool(OPT_CLEVERBIND))
   70     addr.nl_groups |= RTMGRP_IPV4_IFADDR;  
   71   addr.nl_groups |= RTMGRP_IPV6_ROUTE;
   72   if (option_bool(OPT_CLEVERBIND))
   73     addr.nl_groups |= RTMGRP_IPV6_IFADDR;
   74 
   75 #ifdef HAVE_DHCP6
   76   if (daemon->doing_ra || daemon->doing_dhcp6)
   77     addr.nl_groups |= RTMGRP_IPV6_IFADDR;
   78 #endif
   79   
   80   /* May not be able to have permission to set multicast groups don't die in that case */
   81   if ((daemon->netlinkfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1)
   82     {
   83       if (bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
   84     {
   85       addr.nl_groups = 0;
   86       if (errno != EPERM || bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
   87         daemon->netlinkfd = -1;
   88     }
   89     }
   90   
   91   if (daemon->netlinkfd == -1 || 
   92       getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1)
   93     die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
   94   
   95   
   96   /* save pid assigned by bind() and retrieved by getsockname() */ 
   97   netlink_pid = addr.nl_pid;
   98   
   99   iov.iov_len = 100;
  100   iov.iov_base = safe_malloc(iov.iov_len);
  101   
  102   return NULL;
  103 }
  104 
  105 static ssize_t netlink_recv(int flags)
  106 {
  107   struct msghdr msg;
  108   struct sockaddr_nl nladdr;
  109   ssize_t rc;
  110 
  111   while (1)
  112     {
  113       msg.msg_control = NULL;
  114       msg.msg_controllen = 0;
  115       msg.msg_name = &nladdr;
  116       msg.msg_namelen = sizeof(nladdr);
  117       msg.msg_iov = &iov;
  118       msg.msg_iovlen = 1;
  119       msg.msg_flags = 0;
  120       
  121       while ((rc = recvmsg(daemon->netlinkfd, &msg, flags | MSG_PEEK | MSG_TRUNC)) == -1 &&
  122          errno == EINTR);
  123       
  124       /* make buffer big enough */
  125       if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
  126     {
  127       /* Very new Linux kernels return the actual size needed, older ones always return truncated size */
  128       if ((size_t)rc == iov.iov_len)
  129         {
  130           if (expand_buf(&iov, rc + 100))
  131         continue;
  132         }
  133       else
  134         expand_buf(&iov, rc);
  135     }
  136 
  137       /* read it for real */
  138       msg.msg_flags = 0;
  139       while ((rc = recvmsg(daemon->netlinkfd, &msg, flags)) == -1 && errno == EINTR);
  140       
  141       /* Make sure this is from the kernel */
  142       if (rc == -1 || nladdr.nl_pid == 0)
  143     break;
  144     }
  145       
  146   /* discard stuff which is truncated at this point (expand_buf() may fail) */
  147   if (msg.msg_flags & MSG_TRUNC)
  148     {
  149       rc = -1;
  150       errno = ENOMEM;
  151     }
  152   
  153   return rc;
  154 }
  155   
  156 
  157 /* family = AF_UNSPEC finds ARP table entries.
  158    family = AF_LOCAL finds MAC addresses.
  159    returns 0 on failure, 1 on success, -1 when restart is required
  160 */
  161 int iface_enumerate(int family, void *parm, int (*callback)())
  162 {
  163   struct sockaddr_nl addr;
  164   struct nlmsghdr *h;
  165   ssize_t len;
  166   static unsigned int seq = 0;
  167   int callback_ok = 1;
  168   unsigned state = 0;
  169 
  170   struct {
  171     struct nlmsghdr nlh;
  172     struct rtgenmsg g; 
  173   } req;
  174 
  175   memset(&req, 0, sizeof(req));
  176   memset(&addr, 0, sizeof(addr));
  177 
  178   addr.nl_family = AF_NETLINK;
  179  
  180   if (family == AF_UNSPEC)
  181     req.nlh.nlmsg_type = RTM_GETNEIGH;
  182   else if (family == AF_LOCAL)
  183     req.nlh.nlmsg_type = RTM_GETLINK;
  184   else
  185     req.nlh.nlmsg_type = RTM_GETADDR;
  186 
  187   req.nlh.nlmsg_len = sizeof(req);
  188   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK; 
  189   req.nlh.nlmsg_pid = 0;
  190   req.nlh.nlmsg_seq = ++seq;
  191   req.g.rtgen_family = family; 
  192 
  193   /* Don't block in recvfrom if send fails */
  194   while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0, 
  195               (struct sockaddr *)&addr, sizeof(addr))));
  196 
  197   if (errno != 0)
  198     return 0;
  199     
  200   while (1)
  201     {
  202       if ((len = netlink_recv(0)) == -1)
  203     {
  204       if (errno == ENOBUFS)
  205         {
  206           nl_multicast_state(state);
  207           return -1;
  208         }
  209       return 0;
  210     }
  211 
  212       for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
  213     if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
  214       {
  215         /* May be multicast arriving async */
  216         state = nl_async(h, state);
  217       }
  218     else if (h->nlmsg_seq != seq)
  219       {
  220         /* May be part of incomplete response to previous request after
  221            ENOBUFS. Drop it. */
  222         continue;
  223       }
  224     else if (h->nlmsg_type == NLMSG_DONE)
  225       return callback_ok;
  226     else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
  227       {
  228         struct ifaddrmsg *ifa = NLMSG_DATA(h);  
  229         struct rtattr *rta = IFA_RTA(ifa);
  230         unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
  231         
  232         if (ifa->ifa_family == family)
  233           {
  234         if (ifa->ifa_family == AF_INET)
  235           {
  236             struct in_addr netmask, addr, broadcast;
  237             char *label = NULL;
  238 
  239             netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
  240 
  241             addr.s_addr = 0;
  242             broadcast.s_addr = 0;
  243             
  244             while (RTA_OK(rta, len1))
  245               {
  246             if (rta->rta_type == IFA_LOCAL)
  247               addr = *((struct in_addr *)(rta+1));
  248             else if (rta->rta_type == IFA_BROADCAST)
  249               broadcast = *((struct in_addr *)(rta+1));
  250             else if (rta->rta_type == IFA_LABEL)
  251               label = RTA_DATA(rta);
  252             
  253             rta = RTA_NEXT(rta, len1);
  254               }
  255             
  256             if (addr.s_addr && callback_ok)
  257               if (!((*callback)(addr, ifa->ifa_index, label,  netmask, broadcast, parm)))
  258             callback_ok = 0;
  259           }
  260         else if (ifa->ifa_family == AF_INET6)
  261           {
  262             struct in6_addr *addrp = NULL;
  263             u32 valid = 0, preferred = 0;
  264             int flags = 0;
  265             
  266             while (RTA_OK(rta, len1))
  267               {
  268             if (rta->rta_type == IFA_ADDRESS)
  269               addrp = ((struct in6_addr *)(rta+1)); 
  270             else if (rta->rta_type == IFA_CACHEINFO)
  271               {
  272                 struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
  273                 preferred = ifc->ifa_prefered;
  274                 valid = ifc->ifa_valid;
  275               }
  276             rta = RTA_NEXT(rta, len1);
  277               }
  278             
  279             if (ifa->ifa_flags & IFA_F_TENTATIVE)
  280               flags |= IFACE_TENTATIVE;
  281             
  282             if (ifa->ifa_flags & IFA_F_DEPRECATED)
  283               flags |= IFACE_DEPRECATED;
  284             
  285             if (!(ifa->ifa_flags & IFA_F_TEMPORARY))
  286               flags |= IFACE_PERMANENT;
  287                 
  288             if (addrp && callback_ok)
  289               if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope), 
  290                     (int)(ifa->ifa_index), flags, 
  291                     (int) preferred, (int)valid, parm)))
  292             callback_ok = 0;
  293           }
  294           }
  295       }
  296     else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
  297       {
  298         struct ndmsg *neigh = NLMSG_DATA(h);  
  299         struct rtattr *rta = NDA_RTA(neigh);
  300         unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
  301         size_t maclen = 0;
  302         char *inaddr = NULL, *mac = NULL;
  303         
  304         while (RTA_OK(rta, len1))
  305           {
  306         if (rta->rta_type == NDA_DST)
  307           inaddr = (char *)(rta+1);
  308         else if (rta->rta_type == NDA_LLADDR)
  309           {
  310             maclen = rta->rta_len - sizeof(struct rtattr);
  311             mac = (char *)(rta+1);
  312           }
  313         
  314         rta = RTA_NEXT(rta, len1);
  315           }
  316 
  317         if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
  318         inaddr && mac && callback_ok)
  319           if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
  320         callback_ok = 0;
  321       }
  322 #ifdef HAVE_DHCP6
  323     else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
  324       {
  325         struct ifinfomsg *link =  NLMSG_DATA(h);
  326         struct rtattr *rta = IFLA_RTA(link);
  327         unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
  328         char *mac = NULL;
  329         size_t maclen = 0;
  330 
  331         while (RTA_OK(rta, len1))
  332           {
  333         if (rta->rta_type == IFLA_ADDRESS)
  334           {
  335             maclen = rta->rta_len - sizeof(struct rtattr);
  336             mac = (char *)(rta+1);
  337           }
  338         
  339         rta = RTA_NEXT(rta, len1);
  340           }
  341 
  342         if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) && 
  343         !((*callback)((int)link->ifi_index, (unsigned int)link->ifi_type, mac, maclen, parm)))
  344           callback_ok = 0;
  345       }
  346 #endif
  347     }
  348 }
  349 
  350 static void nl_multicast_state(unsigned state)
  351 {
  352   ssize_t len;
  353   struct nlmsghdr *h;
  354 
  355   do {
  356     /* don't risk blocking reading netlink messages here. */
  357     while ((len = netlink_recv(MSG_DONTWAIT)) != -1)
  358   
  359       for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
  360     state = nl_async(h, state);
  361   } while (errno == ENOBUFS);
  362 }
  363 
  364 void netlink_multicast(void)
  365 {
  366   unsigned state = 0;
  367   nl_multicast_state(state);
  368 }
  369 
  370 
  371 static unsigned nl_async(struct nlmsghdr *h, unsigned state)
  372 {
  373   if (h->nlmsg_type == NLMSG_ERROR)
  374     {
  375       struct nlmsgerr *err = NLMSG_DATA(h);
  376       if (err->error != 0)
  377     my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
  378     }
  379   else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE &&
  380        (state & STATE_NEWROUTE)==0)
  381     {
  382       /* We arrange to receive netlink multicast messages whenever the network route is added.
  383      If this happens and we still have a DNS packet in the buffer, we re-send it.
  384      This helps on DoD links, where frequently the packet which triggers dialling is
  385      a DNS query, which then gets lost. By re-sending, we can avoid the lookup
  386      failing. */ 
  387       struct rtmsg *rtm = NLMSG_DATA(h);
  388       
  389       if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
  390       (rtm->rtm_table == RT_TABLE_MAIN ||
  391        rtm->rtm_table == RT_TABLE_LOCAL))
  392     {
  393       queue_event(EVENT_NEWROUTE);
  394       state |= STATE_NEWROUTE;
  395     }
  396     }
  397   else if ((h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) &&
  398        (state & STATE_NEWADDR)==0)
  399     {
  400       queue_event(EVENT_NEWADDR);
  401       state |= STATE_NEWADDR;
  402     }
  403   return state;
  404 }
  405 #endif
  406 
  407