File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dbus.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 1 week ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    1: /* dnsmasq is Copyright (c) 2000-2022 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_DBUS
   20: 
   21: #include <dbus/dbus.h>
   22: 
   23: const char* introspection_xml_template =
   24: "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
   25: "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
   26: "<node name=\"" DNSMASQ_PATH "\">\n"
   27: "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
   28: "    <method name=\"Introspect\">\n"
   29: "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
   30: "    </method>\n"
   31: "  </interface>\n"
   32: "  <interface name=\"%s\">\n"
   33: "    <method name=\"ClearCache\">\n"
   34: "    </method>\n"
   35: "    <method name=\"GetVersion\">\n"
   36: "      <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
   37: "    </method>\n"
   38: #ifdef HAVE_LOOP
   39: "    <method name=\"GetLoopServers\">\n"
   40: "      <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
   41: "    </method>\n"
   42: #endif
   43: "    <method name=\"SetServers\">\n"
   44: "      <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
   45: "    </method>\n"
   46: "    <method name=\"SetDomainServers\">\n"
   47: "      <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
   48: "    </method>\n"
   49: "    <method name=\"SetServersEx\">\n"
   50: "      <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
   51: "    </method>\n"
   52: "    <method name=\"SetFilterWin2KOption\">\n"
   53: "      <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
   54: "    </method>\n"
   55: "    <method name=\"SetLocaliseQueriesOption\">\n"
   56: "      <arg name=\"localise-queries\" direction=\"in\" type=\"b\"/>\n"
   57: "    </method>\n"
   58: "    <method name=\"SetBogusPrivOption\">\n"
   59: "      <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
   60: "    </method>\n"
   61: "    <signal name=\"DhcpLeaseAdded\">\n"
   62: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
   63: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
   64: "      <arg name=\"hostname\" type=\"s\"/>\n"
   65: "    </signal>\n"
   66: "    <signal name=\"DhcpLeaseDeleted\">\n"
   67: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
   68: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
   69: "      <arg name=\"hostname\" type=\"s\"/>\n"
   70: "    </signal>\n"
   71: "    <signal name=\"DhcpLeaseUpdated\">\n"
   72: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
   73: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
   74: "      <arg name=\"hostname\" type=\"s\"/>\n"
   75: "    </signal>\n"
   76: #ifdef HAVE_DHCP
   77: "    <method name=\"AddDhcpLease\">\n"
   78: "       <arg name=\"ipaddr\" type=\"s\"/>\n"
   79: "       <arg name=\"hwaddr\" type=\"s\"/>\n"
   80: "       <arg name=\"hostname\" type=\"ay\"/>\n"
   81: "       <arg name=\"clid\" type=\"ay\"/>\n"
   82: "       <arg name=\"lease_duration\" type=\"u\"/>\n"
   83: "       <arg name=\"ia_id\" type=\"u\"/>\n"
   84: "       <arg name=\"is_temporary\" type=\"b\"/>\n"
   85: "    </method>\n"
   86: "    <method name=\"DeleteDhcpLease\">\n"
   87: "       <arg name=\"ipaddr\" type=\"s\"/>\n"
   88: "       <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
   89: "    </method>\n"
   90: #endif
   91: "    <method name=\"GetMetrics\">\n"
   92: "      <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
   93: "    </method>\n"
   94: "    <method name=\"GetServerMetrics\">\n"
   95: "      <arg name=\"metrics\" direction=\"out\" type=\"a{ss}\"/>\n"
   96: "    </method>\n"
   97: "    <method name=\"ClearMetrics\">\n"
   98: "    </method>\n"
   99: "  </interface>\n"
  100: "</node>\n";
  101: 
  102: static char *introspection_xml = NULL;
  103: 
  104: struct watch {
  105:   DBusWatch *watch;      
  106:   struct watch *next;
  107: };
  108: 
  109: 
  110: static dbus_bool_t add_watch(DBusWatch *watch, void *data)
  111: {
  112:   struct watch *w;
  113: 
  114:   for (w = daemon->watches; w; w = w->next)
  115:     if (w->watch == watch)
  116:       return TRUE;
  117: 
  118:   if (!(w = whine_malloc(sizeof(struct watch))))
  119:     return FALSE;
  120: 
  121:   w->watch = watch;
  122:   w->next = daemon->watches;
  123:   daemon->watches = w;
  124: 
  125:   (void)data; /* no warning */
  126:   return TRUE;
  127: }
  128: 
  129: static void remove_watch(DBusWatch *watch, void *data)
  130: {
  131:   struct watch **up, *w, *tmp;  
  132:   
  133:   for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
  134:     {
  135:       tmp = w->next;
  136:       if (w->watch == watch)
  137: 	{
  138: 	  *up = tmp;
  139: 	  free(w);
  140: 	}
  141:       else
  142: 	up = &(w->next);
  143:     }
  144: 
  145:   (void)data; /* no warning */
  146: }
  147: 
  148: static DBusMessage* dbus_read_servers(DBusMessage *message)
  149: {
  150:   DBusMessageIter iter;
  151:   union  mysockaddr addr, source_addr;
  152:   char *domain;
  153:   
  154:   if (!dbus_message_iter_init(message, &iter))
  155:     {
  156:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  157:                                     "Failed to initialize dbus message iter");
  158:     }
  159: 
  160:   mark_servers(SERV_FROM_DBUS);
  161:   
  162:   while (1)
  163:     {
  164:       int skip = 0;
  165: 
  166:       if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
  167: 	{
  168: 	  u32 a;
  169: 	  
  170: 	  dbus_message_iter_get_basic(&iter, &a);
  171: 	  dbus_message_iter_next (&iter);
  172: 	  
  173: #ifdef HAVE_SOCKADDR_SA_LEN
  174: 	  source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
  175: #endif
  176: 	  addr.in.sin_addr.s_addr = ntohl(a);
  177: 	  source_addr.in.sin_family = addr.in.sin_family = AF_INET;
  178: 	  addr.in.sin_port = htons(NAMESERVER_PORT);
  179: 	  source_addr.in.sin_addr.s_addr = INADDR_ANY;
  180: 	  source_addr.in.sin_port = htons(daemon->query_port);
  181: 	}
  182:       else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
  183: 	{
  184: 	  unsigned char p[sizeof(struct in6_addr)];
  185: 	  unsigned int i;
  186: 
  187: 	  skip = 1;
  188: 
  189: 	  for(i = 0; i < sizeof(struct in6_addr); i++)
  190: 	    {
  191: 	      dbus_message_iter_get_basic(&iter, &p[i]);
  192: 	      dbus_message_iter_next (&iter);
  193: 	      if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
  194: 		{
  195: 		  i++;
  196: 		  break;
  197: 		}
  198: 	    }
  199: 
  200: 	  if (i == sizeof(struct in6_addr))
  201: 	    {
  202: 	      memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
  203: #ifdef HAVE_SOCKADDR_SA_LEN
  204:               source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
  205: #endif
  206:               source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
  207:               addr.in6.sin6_port = htons(NAMESERVER_PORT);
  208:               source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
  209: 	      source_addr.in6.sin6_scope_id = addr.in6.sin6_scope_id = 0;
  210:               source_addr.in6.sin6_addr = in6addr_any;
  211:               source_addr.in6.sin6_port = htons(daemon->query_port);
  212: 	      skip = 0;
  213: 	    }
  214: 	}
  215:       else
  216: 	/* At the end */
  217: 	break;
  218:       
  219:       /* process each domain */
  220:       do {
  221: 	if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
  222: 	  {
  223: 	    dbus_message_iter_get_basic(&iter, &domain);
  224: 	    dbus_message_iter_next (&iter);
  225: 	  }
  226: 	else
  227: 	  domain = NULL;
  228: 	
  229: 	if (!skip)
  230: 	  add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain, NULL);
  231:      
  232:       } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING); 
  233:     }
  234:    
  235:   /* unlink and free anything still marked. */
  236:   cleanup_servers();
  237:   return NULL;
  238: }
  239: 
  240: #ifdef HAVE_LOOP
  241: static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
  242: {
  243:   DBusMessageIter args, args_iter;
  244:   struct server *serv;
  245:   DBusMessage *reply = dbus_message_new_method_return(message);
  246:    
  247:   dbus_message_iter_init_append (reply, &args);
  248:   dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
  249: 
  250:   for (serv = daemon->servers; serv; serv = serv->next)
  251:     if (serv->flags & SERV_LOOP)
  252:       {
  253: 	(void)prettyprint_addr(&serv->addr, daemon->addrbuff);
  254: 	dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
  255:       }
  256:   
  257:   dbus_message_iter_close_container (&args, &args_iter);
  258: 
  259:   return reply;
  260: }
  261: #endif
  262: 
  263: static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
  264: {
  265:   DBusMessageIter iter, array_iter, string_iter;
  266:   DBusMessage *error = NULL;
  267:   const char *addr_err;
  268:   char *dup = NULL;
  269:   
  270:   if (!dbus_message_iter_init(message, &iter))
  271:     {
  272:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  273:                                     "Failed to initialize dbus message iter");
  274:     }
  275: 
  276:   /* check that the message contains an array of arrays */
  277:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
  278:       (dbus_message_iter_get_element_type(&iter) != (strings ? DBUS_TYPE_STRING : DBUS_TYPE_ARRAY)))
  279:     {
  280:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  281:                                     strings ? "Expected array of string" : "Expected array of string arrays");
  282:      }
  283:  
  284:   mark_servers(SERV_FROM_DBUS);
  285: 
  286:   /* array_iter points to each "as" element in the outer array */
  287:   dbus_message_iter_recurse(&iter, &array_iter);
  288:   while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
  289:     {
  290:       const char *str = NULL;
  291:       union  mysockaddr addr, source_addr;
  292:       u16 flags = 0;
  293:       char interface[IF_NAMESIZE];
  294:       char *str_addr, *str_domain = NULL;
  295:       struct server_details sdetails = { 0 };
  296:       sdetails.addr = &addr;
  297:       sdetails.source_addr = &source_addr;
  298:       sdetails.interface = interface;
  299:       sdetails.flags = &flags;
  300: 
  301:       if (strings)
  302: 	{
  303: 	  dbus_message_iter_get_basic(&array_iter, &str);
  304: 	  if (!str || !strlen (str))
  305: 	    {
  306: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  307: 					     "Empty string");
  308: 	      break;
  309: 	    }
  310: 	  
  311: 	  /* dup the string because it gets modified during parsing */
  312: 	  if (dup)
  313: 	    free(dup);
  314: 	  if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
  315: 	    break;
  316: 	  
  317: 	  strcpy(str_domain, str);
  318: 
  319: 	  /* point to address part of old string for error message */
  320: 	  if ((str_addr = strrchr(str, '/')))
  321: 	    str = str_addr+1;
  322: 	  
  323: 	  if ((str_addr = strrchr(str_domain, '/')))
  324: 	    {
  325: 	      if (*str_domain != '/' || str_addr == str_domain)
  326: 		{
  327: 		  error = dbus_message_new_error_printf(message,
  328: 							DBUS_ERROR_INVALID_ARGS,
  329: 							"No domain terminator '%s'",
  330: 							str);
  331: 		  break;
  332: 		}
  333: 	      *str_addr++ = 0;
  334: 	      str_domain++;
  335: 	    }
  336: 	  else
  337: 	    {
  338: 	      str_addr = str_domain;
  339: 	      str_domain = NULL;
  340: 	    }
  341: 
  342: 	  
  343: 	}
  344:       else
  345: 	{
  346: 	  /* check the types of the struct and its elements */
  347: 	  if ((dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY) ||
  348: 	      (dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_STRING))
  349: 	    {
  350: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  351: 					     "Expected inner array of strings");
  352: 	      break;
  353: 	    }
  354: 	  
  355: 	  /* string_iter points to each "s" element in the inner array */
  356: 	  dbus_message_iter_recurse(&array_iter, &string_iter);
  357: 	  if (dbus_message_iter_get_arg_type(&string_iter) != DBUS_TYPE_STRING)
  358: 	    {
  359: 	      /* no IP address given */
  360: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  361: 					     "Expected IP address");
  362: 	      break;
  363: 	    }
  364: 	  
  365: 	  dbus_message_iter_get_basic(&string_iter, &str);
  366: 	  if (!str || !strlen (str))
  367: 	    {
  368: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  369: 					     "Empty IP address");
  370: 	      break;
  371: 	    }
  372: 	  
  373: 	  /* dup the string because it gets modified during parsing */
  374: 	  if (dup)
  375: 	    free(dup);
  376: 	  if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
  377: 	    break;
  378: 	  
  379: 	  strcpy(str_addr, str);
  380: 	}
  381: 
  382:       if (strings)
  383: 	{
  384: 	  char *p;
  385: 	  
  386: 	  do {
  387: 	    if (str_domain)
  388: 	      {
  389: 		if ((p = strchr(str_domain, '/')))
  390: 		  *p++ = 0;
  391: 	      }
  392: 	    else 
  393: 	      p = NULL;
  394: 	    
  395: 	     if (strings && strlen(str_addr) == 0)
  396: 	       add_update_server(SERV_LITERAL_ADDRESS | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
  397: 	     else
  398: 	       {
  399: 		 if ((addr_err = parse_server(str_addr, &sdetails)))
  400: 		   {
  401: 		     error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  402: 							   "Invalid IP address '%s': %s",
  403: 							   str, addr_err);
  404: 		     break;
  405: 		   }
  406: 		 
  407: 		 while (parse_server_next(&sdetails))
  408: 		   {
  409: 		     if ((addr_err = parse_server_addr(&sdetails)))
  410: 		       {
  411: 			 error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  412: 							       "Invalid IP address '%s': %s",
  413: 							       str, addr_err);
  414: 			 break;
  415: 		       }
  416: 		     
  417: 		     add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
  418: 		   }
  419: 	       }
  420: 	  } while ((str_domain = p));
  421: 	}
  422:       else
  423: 	{
  424: 	  /* jump past the address to the domain list (if any) */
  425: 	  dbus_message_iter_next (&string_iter);
  426: 	  
  427: 	  /* parse domains and add each server/domain pair to the list */
  428: 	  do {
  429: 	    str = NULL;
  430: 	    if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
  431: 	      dbus_message_iter_get_basic(&string_iter, &str);
  432: 	    dbus_message_iter_next (&string_iter);
  433: 
  434: 	    if ((addr_err = parse_server(str_addr, &sdetails)))
  435: 	      {
  436: 		error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  437: 						      "Invalid IP address '%s': %s",
  438: 						      str, addr_err);
  439: 		break;
  440: 	      }
  441: 	    
  442: 	    while (parse_server_next(&sdetails))
  443: 	      {
  444: 		if ((addr_err = parse_server_addr(&sdetails)))
  445: 		  {
  446: 		    error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  447: 							  "Invalid IP address '%s': %s",
  448: 							  str, addr_err);
  449: 		    break;
  450: 		  }
  451: 		
  452: 		/* 0.0.0.0 for server address == NULL, for Dbus */
  453: 		if (addr.in.sin_family == AF_INET &&
  454: 		    addr.in.sin_addr.s_addr == 0)
  455: 		  flags |= SERV_LITERAL_ADDRESS;
  456: 		else
  457: 		  flags &= ~SERV_LITERAL_ADDRESS;
  458: 		
  459: 		add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
  460: 	      }
  461: 	  } while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
  462: 	}
  463:       
  464:       if (sdetails.orig_hostinfo)
  465: 	freeaddrinfo(sdetails.orig_hostinfo);
  466:       
  467:       /* jump to next element in outer array */
  468:       dbus_message_iter_next(&array_iter);
  469:     }
  470: 
  471:   cleanup_servers();
  472:     
  473:   if (dup)
  474:     free(dup);
  475: 
  476:   return error;
  477: }
  478: 
  479: static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
  480: {
  481:   DBusMessageIter iter;
  482:   dbus_bool_t enabled;
  483: 
  484:   if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
  485:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
  486:   
  487:   dbus_message_iter_get_basic(&iter, &enabled);
  488: 
  489:   if (enabled)
  490:     { 
  491:       my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
  492:       set_option_bool(flag);
  493:     }
  494:   else
  495:     {
  496:       my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
  497:       reset_option_bool(flag);
  498:     }
  499: 
  500:   return NULL;
  501: }
  502: 
  503: #ifdef HAVE_DHCP
  504: static DBusMessage *dbus_add_lease(DBusMessage* message)
  505: {
  506:   struct dhcp_lease *lease;
  507:   const char *ipaddr, *hwaddr, *hostname, *tmp;
  508:   const unsigned char* clid;
  509:   int clid_len, hostname_len, hw_len, hw_type;
  510:   dbus_uint32_t expires, ia_id;
  511:   dbus_bool_t is_temporary;
  512:   union all_addr addr;
  513:   time_t now = dnsmasq_time();
  514:   unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
  515: 
  516:   DBusMessageIter iter, array_iter;
  517:   if (!dbus_message_iter_init(message, &iter))
  518:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  519: 				  "Failed to initialize dbus message iter");
  520: 
  521:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  522:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  523: 				  "Expected string as first argument");
  524: 
  525:   dbus_message_iter_get_basic(&iter, &ipaddr);
  526:   dbus_message_iter_next(&iter);
  527: 
  528:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  529:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  530: 				  "Expected string as second argument");
  531:     
  532:   dbus_message_iter_get_basic(&iter, &hwaddr);
  533:   dbus_message_iter_next(&iter);
  534: 
  535:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
  536:       (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
  537:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  538: 				  "Expected byte array as third argument");
  539:     
  540:   dbus_message_iter_recurse(&iter, &array_iter);
  541:   dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
  542:   tmp = memchr(hostname, '\0', hostname_len);
  543:   if (tmp)
  544:     {
  545:       if (tmp == &hostname[hostname_len - 1])
  546: 	hostname_len--;
  547:       else
  548: 	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  549: 				      "Hostname contains an embedded NUL character");
  550:     }
  551:   dbus_message_iter_next(&iter);
  552: 
  553:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
  554:       (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
  555:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  556: 				  "Expected byte array as fourth argument");
  557: 
  558:   dbus_message_iter_recurse(&iter, &array_iter);
  559:   dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
  560:   dbus_message_iter_next(&iter);
  561: 
  562:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
  563:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  564: 				  "Expected uint32 as fifth argument");
  565:     
  566:   dbus_message_iter_get_basic(&iter, &expires);
  567:   dbus_message_iter_next(&iter);
  568: 
  569:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
  570:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  571:                                     "Expected uint32 as sixth argument");
  572:   
  573:   dbus_message_iter_get_basic(&iter, &ia_id);
  574:   dbus_message_iter_next(&iter);
  575: 
  576:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
  577:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  578: 				  "Expected uint32 as sixth argument");
  579: 
  580:   dbus_message_iter_get_basic(&iter, &is_temporary);
  581: 
  582:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
  583:     {
  584:       if (ia_id != 0 || is_temporary)
  585: 	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  586: 				      "ia_id and is_temporary must be zero for IPv4 lease");
  587:       
  588:       if (!(lease = lease_find_by_addr(addr.addr4)))
  589:     	lease = lease4_allocate(addr.addr4);
  590:     }
  591: #ifdef HAVE_DHCP6
  592:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
  593:     {
  594:       if (!(lease = lease6_find_by_addr(&addr.addr6, 128, 0)))
  595: 	lease = lease6_allocate(&addr.addr6,
  596: 				is_temporary ? LEASE_TA : LEASE_NA);
  597:       lease_set_iaid(lease, ia_id);
  598:     }
  599: #endif
  600:   else
  601:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  602: 					 "Invalid IP address '%s'", ipaddr);
  603:    
  604:   hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
  605:   if (hw_len < 0)
  606:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  607: 					 "Invalid HW address '%s'", hwaddr);
  608: 
  609:   if (hw_type == 0 && hw_len != 0)
  610:     hw_type = ARPHRD_ETHER;
  611:   
  612:   lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
  613:                    clid_len, now, 0);
  614:   lease_set_expires(lease, expires, now);
  615:   if (hostname_len != 0)
  616:     lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
  617:   
  618:   lease_update_file(now);
  619:   lease_update_dns(0);
  620: 
  621:   return NULL;
  622: }
  623: 
  624: static DBusMessage *dbus_del_lease(DBusMessage* message)
  625: {
  626:   struct dhcp_lease *lease;
  627:   DBusMessageIter iter;
  628:   const char *ipaddr;
  629:   DBusMessage *reply;
  630:   union all_addr addr;
  631:   dbus_bool_t ret = 1;
  632:   time_t now = dnsmasq_time();
  633: 
  634:   if (!dbus_message_iter_init(message, &iter))
  635:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  636: 				  "Failed to initialize dbus message iter");
  637:    
  638:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  639:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  640: 				  "Expected string as first argument");
  641:    
  642:   dbus_message_iter_get_basic(&iter, &ipaddr);
  643: 
  644:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
  645:     lease = lease_find_by_addr(addr.addr4);
  646: #ifdef HAVE_DHCP6
  647:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
  648:     lease = lease6_find_by_addr(&addr.addr6, 128, 0);
  649: #endif
  650:   else
  651:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  652: 					 "Invalid IP address '%s'", ipaddr);
  653:     
  654:   if (lease)
  655:     {
  656:       lease_prune(lease, now);
  657:       lease_update_file(now);
  658:       lease_update_dns(0);
  659:     }
  660:   else
  661:     ret = 0;
  662:   
  663:   if ((reply = dbus_message_new_method_return(message)))
  664:     dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
  665: 			     DBUS_TYPE_INVALID);
  666:   
  667:     
  668:   return reply;
  669: }
  670: #endif
  671: 
  672: static DBusMessage *dbus_get_metrics(DBusMessage* message)
  673: {
  674:   DBusMessage *reply = dbus_message_new_method_return(message);
  675:   DBusMessageIter array, dict, iter;
  676:   int i;
  677: 
  678:   dbus_message_iter_init_append(reply, &iter);
  679:   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{su}", &array);
  680: 
  681:   for (i = 0; i < __METRIC_MAX; i++) {
  682:     const char *key     = get_metric_name(i);
  683:     dbus_uint32_t value = daemon->metrics[i];
  684: 
  685:     dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
  686:     dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
  687:     dbus_message_iter_append_basic(&dict, DBUS_TYPE_UINT32, &value);
  688:     dbus_message_iter_close_container(&array, &dict);
  689:   }
  690: 
  691:   dbus_message_iter_close_container(&iter, &array);
  692: 
  693:   return reply;
  694: }
  695: 
  696: static void add_dict_entry(DBusMessageIter *container, const char *key, const char *val)
  697: {
  698:   DBusMessageIter dict;
  699: 
  700:   dbus_message_iter_open_container(container, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
  701:   dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
  702:   dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &val);
  703:   dbus_message_iter_close_container(container, &dict);
  704: }
  705: 
  706: static void add_dict_int(DBusMessageIter *container, const char *key, const unsigned int val)
  707: {
  708:   snprintf(daemon->namebuff, MAXDNAME, "%u", val);
  709:   
  710:   add_dict_entry(container, key, daemon->namebuff);
  711: }
  712: 
  713: static DBusMessage *dbus_get_server_metrics(DBusMessage* message)
  714: {
  715:   DBusMessage *reply = dbus_message_new_method_return(message);
  716:   DBusMessageIter server_array, dict_array, server_iter;
  717:   struct server *serv;
  718:   
  719:   dbus_message_iter_init_append(reply, &server_iter);
  720:   dbus_message_iter_open_container(&server_iter, DBUS_TYPE_ARRAY, "a{ss}", &server_array);
  721: 
  722:   /* sum counts from different records for same server */
  723:   for (serv = daemon->servers; serv; serv = serv->next)
  724:     serv->flags &= ~SERV_MARK;
  725:   
  726:   for (serv = daemon->servers; serv; serv = serv->next)
  727:     if (!(serv->flags & SERV_MARK))
  728:       {
  729: 	unsigned int port;
  730: 	unsigned int queries = 0, failed_queries = 0, nxdomain_replies = 0, retrys = 0;
  731: 	unsigned int sigma_latency = 0, count_latency = 0;
  732: 	
  733: 	struct server *serv1;
  734: 
  735: 	for (serv1 = serv; serv1; serv1 = serv1->next)
  736: 	  if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
  737: 	    {
  738: 	      serv1->flags |= SERV_MARK;
  739: 	      queries += serv1->queries;
  740: 	      failed_queries += serv1->failed_queries;
  741: 	      nxdomain_replies += serv1->nxdomain_replies;
  742: 	      retrys += serv1->retrys;
  743: 	      sigma_latency += serv1->query_latency;
  744: 	      count_latency++;
  745: 	    }
  746: 	
  747: 	dbus_message_iter_open_container(&server_array, DBUS_TYPE_ARRAY, "{ss}", &dict_array);
  748: 	
  749: 	port = prettyprint_addr(&serv->addr, daemon->namebuff);
  750: 	add_dict_entry(&dict_array, "address", daemon->namebuff);
  751: 	
  752: 	add_dict_int(&dict_array, "port", port);
  753: 	add_dict_int(&dict_array, "queries", serv->queries);
  754: 	add_dict_int(&dict_array, "failed_queries", serv->failed_queries);
  755: 	add_dict_int(&dict_array, "nxdomain", serv->nxdomain_replies);
  756: 	add_dict_int(&dict_array, "retries", serv->retrys);
  757: 	add_dict_int(&dict_array, "latency", sigma_latency/count_latency);
  758: 	
  759: 	dbus_message_iter_close_container(&server_array, &dict_array);
  760:       }
  761:   
  762:   dbus_message_iter_close_container(&server_iter, &server_array);
  763:   
  764:   return reply;
  765: }
  766: 
  767: DBusHandlerResult message_handler(DBusConnection *connection, 
  768: 				  DBusMessage *message, 
  769: 				  void *user_data)
  770: {
  771:   char *method = (char *)dbus_message_get_member(message);
  772:   DBusMessage *reply = NULL;
  773:   int clear_cache = 0, new_servers = 0;
  774:     
  775:   if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
  776:     {
  777:       /* string length: "%s" provides space for termination zero */
  778:       if (!introspection_xml && 
  779: 	  (introspection_xml = whine_malloc(strlen(introspection_xml_template) + strlen(daemon->dbus_name))))
  780: 	sprintf(introspection_xml, introspection_xml_template, daemon->dbus_name);
  781:     
  782:       if (introspection_xml)
  783: 	{
  784: 	  reply = dbus_message_new_method_return(message);
  785: 	  dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
  786: 	}
  787:     }
  788:   else if (strcmp(method, "GetVersion") == 0)
  789:     {
  790:       char *v = VERSION;
  791:       reply = dbus_message_new_method_return(message);
  792:       
  793:       dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
  794:     }
  795: #ifdef HAVE_LOOP
  796:   else if (strcmp(method, "GetLoopServers") == 0)
  797:     {
  798:       reply = dbus_reply_server_loop(message);
  799:     }
  800: #endif
  801:   else if (strcmp(method, "SetServers") == 0)
  802:     {
  803:       reply = dbus_read_servers(message);
  804:       new_servers = 1;
  805:     }
  806:   else if (strcmp(method, "SetServersEx") == 0)
  807:     {
  808:       reply = dbus_read_servers_ex(message, 0);
  809:       new_servers = 1;
  810:     }
  811:   else if (strcmp(method, "SetDomainServers") == 0)
  812:     {
  813:       reply = dbus_read_servers_ex(message, 1);
  814:       new_servers = 1;
  815:     }
  816:   else if (strcmp(method, "SetFilterWin2KOption") == 0)
  817:     {
  818:       reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
  819:     }
  820:   else if (strcmp(method, "SetLocaliseQueriesOption") == 0)
  821:     {
  822:       reply = dbus_set_bool(message, OPT_LOCALISE, "localise-queries");
  823:     }
  824:   else if (strcmp(method, "SetBogusPrivOption") == 0)
  825:     {
  826:       reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
  827:     }
  828: #ifdef HAVE_DHCP
  829:   else if (strcmp(method, "AddDhcpLease") == 0)
  830:     {
  831:       reply = dbus_add_lease(message);
  832:     }
  833:   else if (strcmp(method, "DeleteDhcpLease") == 0)
  834:     {
  835:       reply = dbus_del_lease(message);
  836:     }
  837: #endif
  838:   else if (strcmp(method, "GetMetrics") == 0)
  839:     {
  840:       reply = dbus_get_metrics(message);
  841:     }
  842:   else if (strcmp(method, "GetServerMetrics") == 0)
  843:     {
  844:       reply = dbus_get_server_metrics(message);
  845:     }
  846:   else if (strcmp(method, "ClearMetrics") == 0)
  847:     {
  848:       clear_metrics();
  849:     }
  850:   else if (strcmp(method, "ClearCache") == 0)
  851:     clear_cache = 1;
  852:   else
  853:     return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
  854:    
  855:   if (new_servers)
  856:     {
  857:       my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
  858:       check_servers(0);
  859:       if (option_bool(OPT_RELOAD))
  860: 	clear_cache = 1;
  861:     }
  862: 
  863:   if (clear_cache)
  864:     clear_cache_and_reload(dnsmasq_time());
  865:   
  866:   (void)user_data; /* no warning */
  867: 
  868:   /* If no reply or no error, return nothing */
  869:   if (!reply)
  870:     reply = dbus_message_new_method_return(message);
  871: 
  872:   if (reply)
  873:     {
  874:       dbus_connection_send (connection, reply, NULL);
  875:       dbus_message_unref (reply);
  876:     }
  877: 
  878:   return (DBUS_HANDLER_RESULT_HANDLED);
  879: }
  880:  
  881: 
  882: /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
  883: char *dbus_init(void)
  884: {
  885:   DBusConnection *connection = NULL;
  886:   DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
  887:   DBusError dbus_error;
  888:   DBusMessage *message;
  889: 
  890:   dbus_error_init (&dbus_error);
  891:   if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
  892:     {
  893:       dbus_error_free(&dbus_error);
  894:       return NULL;
  895:     }
  896:   
  897:   dbus_connection_set_exit_on_disconnect(connection, FALSE);
  898:   dbus_connection_set_watch_functions(connection, add_watch, remove_watch, 
  899: 				      NULL, NULL, NULL);
  900:   dbus_error_init (&dbus_error);
  901:   dbus_bus_request_name (connection, daemon->dbus_name, 0, &dbus_error);
  902:   if (dbus_error_is_set (&dbus_error))
  903:     return (char *)dbus_error.message;
  904:   
  905:   if (!dbus_connection_register_object_path(connection,  DNSMASQ_PATH, 
  906: 					    &dnsmasq_vtable, NULL))
  907:     return _("could not register a DBus message handler");
  908:   
  909:   daemon->dbus = connection; 
  910:   
  911:   if ((message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "Up")))
  912:     {
  913:       dbus_connection_send(connection, message, NULL);
  914:       dbus_message_unref(message);
  915:     }
  916: 
  917:   return NULL;
  918: }
  919:  
  920: 
  921: void set_dbus_listeners(void)
  922: {
  923:   struct watch *w;
  924:   
  925:   for (w = daemon->watches; w; w = w->next)
  926:     if (dbus_watch_get_enabled(w->watch))
  927:       {
  928: 	unsigned int flags = dbus_watch_get_flags(w->watch);
  929: 	int fd = dbus_watch_get_unix_fd(w->watch);
  930: 	
  931: 	if (flags & DBUS_WATCH_READABLE)
  932: 	  poll_listen(fd, POLLIN);
  933: 	
  934: 	if (flags & DBUS_WATCH_WRITABLE)
  935: 	  poll_listen(fd, POLLOUT);
  936: 	
  937: 	poll_listen(fd, POLLERR);
  938:       }
  939: }
  940: 
  941: void check_dbus_listeners()
  942: {
  943:   DBusConnection *connection = (DBusConnection *)daemon->dbus;
  944:   struct watch *w;
  945: 
  946:   for (w = daemon->watches; w; w = w->next)
  947:     if (dbus_watch_get_enabled(w->watch))
  948:       {
  949: 	unsigned int flags = 0;
  950: 	int fd = dbus_watch_get_unix_fd(w->watch);
  951: 	
  952: 	if (poll_check(fd, POLLIN))
  953: 	  flags |= DBUS_WATCH_READABLE;
  954: 	
  955: 	if (poll_check(fd, POLLOUT))
  956: 	  flags |= DBUS_WATCH_WRITABLE;
  957: 	
  958: 	if (poll_check(fd, POLLERR))
  959: 	  flags |= DBUS_WATCH_ERROR;
  960: 
  961: 	if (flags != 0)
  962: 	  dbus_watch_handle(w->watch, flags);
  963:       }
  964: 
  965:   if (connection)
  966:     {
  967:       dbus_connection_ref (connection);
  968:       while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
  969:       dbus_connection_unref (connection);
  970:     }
  971: }
  972: 
  973: #ifdef HAVE_DHCP
  974: void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
  975: {
  976:   DBusConnection *connection = (DBusConnection *)daemon->dbus;
  977:   DBusMessage* message = NULL;
  978:   DBusMessageIter args;
  979:   char *action_str, *mac = daemon->namebuff;
  980:   unsigned char *p;
  981:   int i;
  982: 
  983:   if (!connection)
  984:     return;
  985:   
  986:   if (!hostname)
  987:     hostname = "";
  988:   
  989: #ifdef HAVE_DHCP6
  990:    if (lease->flags & (LEASE_TA | LEASE_NA))
  991:      {
  992:        print_mac(mac, lease->clid, lease->clid_len);
  993:        inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
  994:      }
  995:    else
  996: #endif
  997:      {
  998:        p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
  999: 			   lease->hwaddr, lease->clid_len, lease->clid, &i);
 1000:        print_mac(mac, p, i);
 1001:        inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
 1002:      }
 1003: 
 1004:   if (action == ACTION_DEL)
 1005:     action_str = "DhcpLeaseDeleted";
 1006:   else if (action == ACTION_ADD)
 1007:     action_str = "DhcpLeaseAdded";
 1008:   else if (action == ACTION_OLD)
 1009:     action_str = "DhcpLeaseUpdated";
 1010:   else
 1011:     return;
 1012: 
 1013:   if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, action_str)))
 1014:     return;
 1015:   
 1016:   dbus_message_iter_init_append(message, &args);
 1017:   
 1018:   if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &daemon->addrbuff) &&
 1019:       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
 1020:       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
 1021:     dbus_connection_send(connection, message, NULL);
 1022:   
 1023:   dbus_message_unref(message);
 1024: }
 1025: #endif
 1026: 
 1027: #endif

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