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

version 1.1.1.4, 2021/03/17 00:56:46 version 1.1.1.5, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley/* dnsmasq is Copyright (c) 2000-2022 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 41 Line 41
   
 #ifndef NDA_RTA  #ifndef NDA_RTA
 #  define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))   #  define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) 
#endif #endif
   
   /* Used to request refresh of addresses or routes just once,
    * when multiple changes might be announced. */
   enum async_states {
     STATE_NEWADDR = (1 << 0),
     STATE_NEWROUTE = (1 << 1),
   };
   
   
 static struct iovec iov;  static struct iovec iov;
 static u32 netlink_pid;  static u32 netlink_pid;
   
static void nl_async(struct nlmsghdr *h);static unsigned nl_async(struct nlmsghdr *h, unsigned state);
 static void nl_multicast_state(unsigned state);
   
 char *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;
   addr.nl_pid = 0; /* autobind */    addr.nl_pid = 0; /* autobind */
   addr.nl_groups = RTMGRP_IPV4_ROUTE;    addr.nl_groups = RTMGRP_IPV4_ROUTE;
  if (option_bool(OPT_CLEVERBIND))  addr.nl_groups |= RTMGRP_IPV4_IFADDR;  
    addr.nl_groups |= RTMGRP_IPV4_IFADDR;   
   addr.nl_groups |= RTMGRP_IPV6_ROUTE;    addr.nl_groups |= RTMGRP_IPV6_ROUTE;
  if (option_bool(OPT_CLEVERBIND))  addr.nl_groups |= RTMGRP_IPV6_IFADDR;
    addr.nl_groups |= RTMGRP_IPV6_IFADDR; 
   
 #ifdef HAVE_DHCP6  
   if (daemon->doing_ra || daemon->doing_dhcp6)  
     addr.nl_groups |= RTMGRP_IPV6_IFADDR;  
 #endif  
     
   /* May not be able to have permission to set multicast groups don't die in that case */    /* May not be able to have permission to set multicast groups don't die in that case */
   if ((daemon->netlinkfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1)    if ((daemon->netlinkfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1)
     {      {
Line 92  char *netlink_init(void) Line 92  char *netlink_init(void)
   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;    return NULL;
 }  }
   
static ssize_t netlink_recv(void)static ssize_t netlink_recv(int flags)
 {  {
   struct msghdr msg;    struct msghdr msg;
   struct sockaddr_nl nladdr;    struct sockaddr_nl nladdr;
Line 115  static ssize_t netlink_recv(void) Line 111  static ssize_t netlink_recv(void)
       msg.msg_iovlen = 1;        msg.msg_iovlen = 1;
       msg.msg_flags = 0;        msg.msg_flags = 0;
               
      while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);      while ((rc = recvmsg(daemon->netlinkfd, &msg, flags | MSG_PEEK | MSG_TRUNC)) == -1 &&
              errno == EINTR);
               
       /* make buffer big enough */        /* make buffer big enough */
       if (rc != -1 && (msg.msg_flags & MSG_TRUNC))        if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
Line 132  static ssize_t netlink_recv(void) Line 129  static ssize_t netlink_recv(void)
   
       /* read it for real */        /* read it for real */
       msg.msg_flags = 0;        msg.msg_flags = 0;
      while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);      while ((rc = recvmsg(daemon->netlinkfd, &msg, flags)) == -1 && errno == EINTR);
               
       /* Make sure this is from the kernel */        /* Make sure this is from the kernel */
       if (rc == -1 || nladdr.nl_pid == 0)        if (rc == -1 || nladdr.nl_pid == 0)
Line 151  static ssize_t netlink_recv(void) Line 148  static ssize_t netlink_recv(void)
       
   
 /* family = AF_UNSPEC finds ARP table entries.  /* family = AF_UNSPEC finds ARP table entries.
   family = AF_LOCAL finds MAC addresses. */   family = AF_LOCAL finds MAC addresses.
    returns 0 on failure, 1 on success, -1 when restart is required
 */
 int iface_enumerate(int family, void *parm, int (*callback)())  int iface_enumerate(int family, void *parm, int (*callback)())
 {  {
   struct sockaddr_nl addr;    struct sockaddr_nl addr;
Line 159  int iface_enumerate(int family, void *parm, int (*call Line 158  int iface_enumerate(int family, void *parm, int (*call
   ssize_t len;    ssize_t len;
   static unsigned int seq = 0;    static unsigned int seq = 0;
   int callback_ok = 1;    int callback_ok = 1;
     unsigned state = 0;
   
   struct {    struct {
     struct nlmsghdr nlh;      struct nlmsghdr nlh;
Line 170  int iface_enumerate(int family, void *parm, int (*call Line 170  int iface_enumerate(int family, void *parm, int (*call
   
   addr.nl_family = AF_NETLINK;    addr.nl_family = AF_NETLINK;
     
  again:   
   if (family == AF_UNSPEC)    if (family == AF_UNSPEC)
     req.nlh.nlmsg_type = RTM_GETNEIGH;      req.nlh.nlmsg_type = RTM_GETNEIGH;
   else if (family == AF_LOCAL)    else if (family == AF_LOCAL)
Line 193  int iface_enumerate(int family, void *parm, int (*call Line 192  int iface_enumerate(int family, void *parm, int (*call
           
   while (1)    while (1)
     {      {
      if ((len = netlink_recv()) == -1)      if ((len = netlink_recv(0)) == -1)
         {          {
           if (errno == ENOBUFS)            if (errno == ENOBUFS)
             {              {
              sleep(1);              nl_multicast_state(state);
              goto again;              return -1;
             }              }
           return 0;            return 0;
         }          }
Line 207  int iface_enumerate(int family, void *parm, int (*call Line 206  int iface_enumerate(int family, void *parm, int (*call
         if (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 */
            nl_async(h);            state = nl_async(h, state);
           }            }
         else if (h->nlmsg_seq != seq)          else if (h->nlmsg_seq != seq)
           {            {
Line 259  int iface_enumerate(int family, void *parm, int (*call Line 258  int iface_enumerate(int family, void *parm, int (*call
                                           
                     while (RTA_OK(rta, len1))                      while (RTA_OK(rta, len1))
                       {                        {
                        if (rta->rta_type == IFA_ADDRESS)                        /*
                          * Important comment: (from if_addr.h)
                          * IFA_ADDRESS is prefix address, rather than local interface address.
                          * It makes no difference for normally configured broadcast interfaces,
                          * but for point-to-point IFA_ADDRESS is DESTINATION address,
                          * local address is supplied in IFA_LOCAL attribute.
                          */
                         if (rta->rta_type == IFA_LOCAL)
                           addrp = ((struct in6_addr *)(rta+1));
                         else if (rta->rta_type == IFA_ADDRESS && !addrp)
                           addrp = ((struct in6_addr *)(rta+1));                             addrp = ((struct in6_addr *)(rta+1)); 
                         else if (rta->rta_type == IFA_CACHEINFO)                          else if (rta->rta_type == IFA_CACHEINFO)
                           {                            {
Line 341  int iface_enumerate(int family, void *parm, int (*call Line 349  int iface_enumerate(int family, void *parm, int (*call
     }      }
 }  }
   
void netlink_multicast(void)static void nl_multicast_state(unsigned state)
 {  {
   ssize_t len;    ssize_t len;
   struct nlmsghdr *h;    struct nlmsghdr *h;
  int flags;
   do {
     /* don't risk blocking reading netlink messages here. */
     while ((len = netlink_recv(MSG_DONTWAIT)) != -1)
       
  /* don't risk blocking reading netlink messages here. */      for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
  if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||        state = nl_async(h, state);
      fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)   } while (errno == ENOBUFS);
    return; 
   
  if ((len = netlink_recv()) != -1) 
    for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) 
      nl_async(h); 
   
  /* restore non-blocking status */ 
  fcntl(daemon->netlinkfd, F_SETFL, flags); 
 }  }
   
static void nl_async(struct nlmsghdr *h)void netlink_multicast(void)
 {  {
     unsigned state = 0;
     nl_multicast_state(state);
   }
   
   
   static unsigned nl_async(struct nlmsghdr *h, unsigned state)
   {
   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)));
     }      }
  else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE  else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE &&
            (state & STATE_NEWROUTE)==0)
     {      {
       /* We arrange to receive netlink multicast messages whenever the network route is added.        /* We arrange to receive netlink multicast messages whenever the network route is added.
          If this happens and we still have a DNS packet in the buffer, we re-send it.           If this happens and we still have a DNS packet in the buffer, we re-send it.
Line 380  static void nl_async(struct nlmsghdr *h) Line 391  static void nl_async(struct nlmsghdr *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 ||            (rtm->rtm_table == RT_TABLE_MAIN ||
            rtm->rtm_table == RT_TABLE_LOCAL))             rtm->rtm_table == RT_TABLE_LOCAL))
        queue_event(EVENT_NEWROUTE);        {
           queue_event(EVENT_NEWROUTE);
           state |= STATE_NEWROUTE;
         }
     }      }
  else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)   else if ((h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) &&
    queue_event(EVENT_NEWADDR);           (state & STATE_NEWADDR)==0)
     {
       queue_event(EVENT_NEWADDR);
       state |= STATE_NEWADDR;
     }
   return state;
 }  }
#endif#endif /* HAVE_LINUX_NETWORK */
 
       

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


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