Diff for /embedaddon/dnsmasq/src/netlink.c between versions 1.1.1.2 and 1.1.1.4

version 1.1.1.2, 2014/06/15 16:31:38 version 1.1.1.4, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 22 Line 22
 #include <linux/netlink.h>  #include <linux/netlink.h>
 #include <linux/rtnetlink.h>  #include <linux/rtnetlink.h>
   
   /* Blergh. Radv does this, so that's our excuse. */
   #ifndef SOL_NETLINK
   #define SOL_NETLINK 270
   #endif
   
   #ifndef NETLINK_NO_ENOBUFS
   #define NETLINK_NO_ENOBUFS 5
   #endif
   
 /* linux 2.6.19 buggers up the headers, patch it up here. */   /* linux 2.6.19 buggers up the headers, patch it up here. */ 
 #ifndef IFA_RTA  #ifndef IFA_RTA
 #  define IFA_RTA(r)  \  #  define IFA_RTA(r)  \
Line 38 Line 47
 static struct iovec iov;  static struct iovec iov;
 static u32 netlink_pid;  static u32 netlink_pid;
   
static int nl_async(struct nlmsghdr *h);static void nl_async(struct nlmsghdr *h);
   
void netlink_init(void)char *netlink_init(void)
 {  {
   struct sockaddr_nl addr;    struct sockaddr_nl addr;
   socklen_t slen = sizeof(addr);    socklen_t slen = sizeof(addr);
     int opt = 1;
   
   addr.nl_family = AF_NETLINK;    addr.nl_family = AF_NETLINK;
   addr.nl_pad = 0;    addr.nl_pad = 0;
Line 51  void netlink_init(void) Line 61  void netlink_init(void)
   addr.nl_groups = RTMGRP_IPV4_ROUTE;    addr.nl_groups = RTMGRP_IPV4_ROUTE;
   if (option_bool(OPT_CLEVERBIND))    if (option_bool(OPT_CLEVERBIND))
     addr.nl_groups |= RTMGRP_IPV4_IFADDR;        addr.nl_groups |= RTMGRP_IPV4_IFADDR;  
 #ifdef HAVE_IPV6  
   addr.nl_groups |= RTMGRP_IPV6_ROUTE;    addr.nl_groups |= RTMGRP_IPV6_ROUTE;
   if (option_bool(OPT_CLEVERBIND))    if (option_bool(OPT_CLEVERBIND))
     addr.nl_groups |= RTMGRP_IPV6_IFADDR;      addr.nl_groups |= RTMGRP_IPV6_IFADDR;
#endif
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
   if (daemon->doing_ra || daemon->doing_dhcp6)    if (daemon->doing_ra || daemon->doing_dhcp6)
     addr.nl_groups |= RTMGRP_IPV6_IFADDR;      addr.nl_groups |= RTMGRP_IPV6_IFADDR;
Line 73  void netlink_init(void) Line 82  void netlink_init(void)
     }      }
       
   if (daemon->netlinkfd == -1 ||     if (daemon->netlinkfd == -1 || 
      getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == 1)      getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1)
     die(_("cannot create netlink socket: %s"), NULL, EC_MISC);      die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
     
   
   /* save pid assigned by bind() and retrieved by getsockname() */     /* save pid assigned by bind() and retrieved by getsockname() */ 
   netlink_pid = addr.nl_pid;    netlink_pid = addr.nl_pid;
       
   iov.iov_len = 100;    iov.iov_len = 100;
   iov.iov_base = safe_malloc(iov.iov_len);    iov.iov_base = safe_malloc(iov.iov_len);
     
     if (daemon->kernel_version >= KERNEL_VERSION(2,6,30) &&
         setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1)
       return _("warning: failed to set NETLINK_NO_ENOBUFS on netlink socket");
     
     return NULL;
 }  }
   
 static ssize_t netlink_recv(void)  static ssize_t netlink_recv(void)
Line 142  int iface_enumerate(int family, void *parm, int (*call Line 158  int iface_enumerate(int family, void *parm, int (*call
   struct nlmsghdr *h;    struct nlmsghdr *h;
   ssize_t len;    ssize_t len;
   static unsigned int seq = 0;    static unsigned int seq = 0;
  int callback_ok = 1, newaddr = 0;  int callback_ok = 1;
   
   struct {    struct {
     struct nlmsghdr nlh;      struct nlmsghdr nlh;
     struct rtgenmsg g;       struct rtgenmsg g; 
   } req;    } req;
   
     memset(&req, 0, sizeof(req));
     memset(&addr, 0, sizeof(addr));
   
   addr.nl_family = AF_NETLINK;    addr.nl_family = AF_NETLINK;
   addr.nl_pad = 0;  
   addr.nl_groups = 0;  
   addr.nl_pid = 0; /* address to kernel */  
     
  again:    again: 
   if (family == AF_UNSPEC)    if (family == AF_UNSPEC)
Line 169  int iface_enumerate(int family, void *parm, int (*call Line 185  int iface_enumerate(int family, void *parm, int (*call
   req.g.rtgen_family = family;     req.g.rtgen_family = family; 
   
   /* Don't block in recvfrom if send fails */    /* Don't block in recvfrom if send fails */
  while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,   while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0, 
                      (struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send());                          (struct sockaddr *)&addr, sizeof(addr))));
  
  if (len == -1)  if (errno != 0)
     return 0;      return 0;
           
   while (1)    while (1)
Line 188  int iface_enumerate(int family, void *parm, int (*call Line 204  int iface_enumerate(int family, void *parm, int (*call
         }          }
   
       for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))        for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
        if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)        if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
           {            {
             /* May be multicast arriving async */              /* May be multicast arriving async */
            if (nl_async(h))            nl_async(h);
              { 
                newaddr = 1;  
                enumerate_interfaces(1); /* reset */ 
              } 
           }            }
        else if (h->nlmsg_type == NLMSG_DONE)        else if (h->nlmsg_seq != seq)
           {            {
            /* handle async new interface address arrivals, these have to be done            /* May be part of incomplete response to previous request after
               after we complete as we're not re-entrant */               ENOBUFS. Drop it. */
            if (newaddr)             continue;
              newaddress(dnsmasq_time()); 
                 
            return callback_ok; 
           }            }
           else if (h->nlmsg_type == NLMSG_DONE)
             return callback_ok;
         else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)          else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
           {            {
             struct ifaddrmsg *ifa = NLMSG_DATA(h);                struct ifaddrmsg *ifa = NLMSG_DATA(h);  
Line 219  int iface_enumerate(int family, void *parm, int (*call Line 230  int iface_enumerate(int family, void *parm, int (*call
                     struct in_addr netmask, addr, broadcast;                      struct in_addr netmask, addr, broadcast;
                     char *label = NULL;                      char *label = NULL;
   
                    netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));                    netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
 
                     addr.s_addr = 0;                      addr.s_addr = 0;
                     broadcast.s_addr = 0;                      broadcast.s_addr = 0;
                                           
Line 239  int iface_enumerate(int family, void *parm, int (*call Line 251  int iface_enumerate(int family, void *parm, int (*call
                       if (!((*callback)(addr, ifa->ifa_index, label,  netmask, broadcast, parm)))                        if (!((*callback)(addr, ifa->ifa_index, label,  netmask, broadcast, parm)))
                         callback_ok = 0;                          callback_ok = 0;
                   }                    }
 #ifdef HAVE_IPV6  
                 else if (ifa->ifa_family == AF_INET6)                  else if (ifa->ifa_family == AF_INET6)
                   {                    {
                     struct in6_addr *addrp = NULL;                      struct in6_addr *addrp = NULL;
Line 274  int iface_enumerate(int family, void *parm, int (*call Line 285  int iface_enumerate(int family, void *parm, int (*call
                                         (int) preferred, (int)valid, parm)))                                          (int) preferred, (int)valid, parm)))
                         callback_ok = 0;                          callback_ok = 0;
                   }                    }
 #endif  
               }                }
           }            }
         else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)          else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
Line 298  int iface_enumerate(int family, void *parm, int (*call Line 308  int iface_enumerate(int family, void *parm, int (*call
                 rta = RTA_NEXT(rta, len1);                  rta = RTA_NEXT(rta, len1);
               }                }
   
            if (inaddr && mac && callback_ok)            if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
                 inaddr && mac && callback_ok)
               if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))                if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
                 callback_ok = 0;                  callback_ok = 0;
           }            }
Line 330  int iface_enumerate(int family, void *parm, int (*call Line 341  int iface_enumerate(int family, void *parm, int (*call
     }      }
 }  }
   
void netlink_multicast(time_t now)void netlink_multicast(void)
 {  {
   ssize_t len;    ssize_t len;
   struct nlmsghdr *h;    struct nlmsghdr *h;
  int flags, newaddr = 0;  int flags;
       
   /* don't risk blocking reading netlink messages here. */    /* don't risk blocking reading netlink messages here. */
   if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||    if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
Line 343  void netlink_multicast(time_t now) Line 354  void netlink_multicast(time_t now)
       
   if ((len = netlink_recv()) != -1)    if ((len = netlink_recv()) != -1)
     for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))      for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
      if (nl_async(h))      nl_async(h);
        newaddr = 1; 
       
   /* restore non-blocking status */    /* restore non-blocking status */
   fcntl(daemon->netlinkfd, F_SETFL, flags);    fcntl(daemon->netlinkfd, F_SETFL, flags);
     
   if (newaddr)   
     newaddress(now);  
 }  }
   
static int nl_async(struct nlmsghdr *h)static void nl_async(struct nlmsghdr *h)
 {  {
   if (h->nlmsg_type == NLMSG_ERROR)    if (h->nlmsg_type == NLMSG_ERROR)
     {      {
       struct nlmsgerr *err = NLMSG_DATA(h);        struct nlmsgerr *err = NLMSG_DATA(h);
       if (err->error != 0)        if (err->error != 0)
         my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));          my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
       return 0;  
     }      }
   else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)     else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) 
     {      {
Line 371  static int nl_async(struct nlmsghdr *h) Line 377  static int nl_async(struct nlmsghdr *h)
          failing. */            failing. */ 
       struct rtmsg *rtm = NLMSG_DATA(h);        struct rtmsg *rtm = NLMSG_DATA(h);
               
      if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)      if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
        {          (rtm->rtm_table == RT_TABLE_MAIN ||
          /* Force re-reading resolv file right now, for luck. */           rtm->rtm_table == RT_TABLE_LOCAL))
          daemon->last_resolv = 0;        queue_event(EVENT_NEWROUTE);
           
          if (daemon->srv_save) 
            { 
              int fd; 
 
              if (daemon->srv_save->sfd) 
                fd = daemon->srv_save->sfd->fd; 
              else if (daemon->rfd_save && daemon->rfd_save->refcount != 0) 
                fd = daemon->rfd_save->fd; 
              else 
                return 0; 
               
              while(sendto(fd, daemon->packet, daemon->packet_len, 0, 
                           &daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());  
            } 
        } 
      return 0; 
     }      }
   else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)     else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) 
    return 1; /* clever bind mode - rescan */    queue_event(EVENT_NEWADDR);
   
  return 0; 
 }  }
 #endif  #endif
   

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>