1 /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
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.
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.
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/>.
21 #include <dbus/dbus.h>
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"
32 " <interface name=\"%s\">\n"
33 " <method name=\"ClearCache\">\n"
35 " <method name=\"GetVersion\">\n"
36 " <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
38 " <method name=\"SetServers\">\n"
39 " <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
41 " <method name=\"SetDomainServers\">\n"
42 " <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
44 " <method name=\"SetServersEx\">\n"
45 " <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
47 " <signal name=\"DhcpLeaseAdded\">\n"
48 " <arg name=\"ipaddr\" type=\"s\"/>\n"
49 " <arg name=\"hwaddr\" type=\"s\"/>\n"
50 " <arg name=\"hostname\" type=\"s\"/>\n"
52 " <signal name=\"DhcpLeaseDeleted\">\n"
53 " <arg name=\"ipaddr\" type=\"s\"/>\n"
54 " <arg name=\"hwaddr\" type=\"s\"/>\n"
55 " <arg name=\"hostname\" type=\"s\"/>\n"
57 " <signal name=\"DhcpLeaseUpdated\">\n"
58 " <arg name=\"ipaddr\" type=\"s\"/>\n"
59 " <arg name=\"hwaddr\" type=\"s\"/>\n"
60 " <arg name=\"hostname\" type=\"s\"/>\n"
65 static char *introspection_xml
= NULL
;
73 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
)
77 for (w
= daemon
->watches
; w
; w
= w
->next
)
78 if (w
->watch
== watch
)
81 if (!(w
= whine_malloc(sizeof(struct watch
))))
85 w
->next
= daemon
->watches
;
88 w
= data
; /* no warning */
92 static void remove_watch(DBusWatch
*watch
, void *data
)
94 struct watch
**up
, *w
, *tmp
;
96 for (up
= &(daemon
->watches
), w
= daemon
->watches
; w
; w
= tmp
)
99 if (w
->watch
== watch
)
108 w
= data
; /* no warning */
111 static void add_update_server(union mysockaddr
*addr
,
112 union mysockaddr
*source_addr
,
113 const char *interface
,
118 /* See if there is a suitable candidate, and unmark */
119 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
120 if ((serv
->flags
& SERV_FROM_DBUS
) &&
121 (serv
->flags
& SERV_MARK
))
125 if (!(serv
->flags
& SERV_HAS_DOMAIN
) || !hostname_isequal(domain
, serv
->domain
))
130 if (serv
->flags
& SERV_HAS_DOMAIN
)
134 serv
->flags
&= ~SERV_MARK
;
139 if (!serv
&& (serv
= whine_malloc(sizeof (struct server
))))
141 /* Not found, create a new one. */
142 memset(serv
, 0, sizeof(struct server
));
144 if (domain
&& !(serv
->domain
= whine_malloc(strlen(domain
)+1)))
151 serv
->next
= daemon
->servers
;
152 daemon
->servers
= serv
;
153 serv
->flags
= SERV_FROM_DBUS
;
156 strcpy(serv
->domain
, domain
);
157 serv
->flags
|= SERV_HAS_DOMAIN
;
165 strcpy(serv
->interface
, interface
);
167 serv
->interface
[0] = 0;
169 if (source_addr
->in
.sin_family
== AF_INET
&&
170 addr
->in
.sin_addr
.s_addr
== 0 &&
172 serv
->flags
|= SERV_NO_ADDR
;
175 serv
->flags
&= ~SERV_NO_ADDR
;
177 serv
->source_addr
= *source_addr
;
182 static void mark_dbus(void)
186 /* mark everything from DBUS */
187 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
188 if (serv
->flags
& SERV_FROM_DBUS
)
189 serv
->flags
|= SERV_MARK
;
192 static void cleanup_dbus()
194 struct server
*serv
, *tmp
, **up
;
196 /* unlink and free anything still marked. */
197 for (serv
= daemon
->servers
, up
= &daemon
->servers
; serv
; serv
= tmp
)
200 if (serv
->flags
& SERV_MARK
)
213 static void dbus_read_servers(DBusMessage
*message
)
215 DBusMessageIter iter
;
216 union mysockaddr addr
, source_addr
;
219 dbus_message_iter_init(message
, &iter
);
227 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_UINT32
)
231 dbus_message_iter_get_basic(&iter
, &a
);
232 dbus_message_iter_next (&iter
);
234 #ifdef HAVE_SOCKADDR_SA_LEN
235 source_addr
.in
.sin_len
= addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
237 addr
.in
.sin_addr
.s_addr
= ntohl(a
);
238 source_addr
.in
.sin_family
= addr
.in
.sin_family
= AF_INET
;
239 addr
.in
.sin_port
= htons(NAMESERVER_PORT
);
240 source_addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
241 source_addr
.in
.sin_port
= htons(daemon
->query_port
);
243 else if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_BYTE
)
245 unsigned char p
[sizeof(struct in6_addr
)];
250 for(i
= 0; i
< sizeof(struct in6_addr
); i
++)
252 dbus_message_iter_get_basic(&iter
, &p
[i
]);
253 dbus_message_iter_next (&iter
);
254 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BYTE
)
259 my_syslog(LOG_WARNING
, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
261 if (i
== sizeof(struct in6_addr
)-1)
263 memcpy(&addr
.in6
.sin6_addr
, p
, sizeof(struct in6_addr
));
264 #ifdef HAVE_SOCKADDR_SA_LEN
265 source_addr
.in6
.sin6_len
= addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
267 source_addr
.in6
.sin6_family
= addr
.in6
.sin6_family
= AF_INET6
;
268 addr
.in6
.sin6_port
= htons(NAMESERVER_PORT
);
269 source_addr
.in6
.sin6_flowinfo
= addr
.in6
.sin6_flowinfo
= 0;
270 source_addr
.in6
.sin6_scope_id
= addr
.in6
.sin6_scope_id
= 0;
271 source_addr
.in6
.sin6_addr
= in6addr_any
;
272 source_addr
.in6
.sin6_port
= htons(daemon
->query_port
);
281 /* process each domain */
283 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
)
285 dbus_message_iter_get_basic(&iter
, &domain
);
286 dbus_message_iter_next (&iter
);
292 add_update_server(&addr
, &source_addr
, NULL
, domain
);
294 } while (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
);
297 /* unlink and free anything still marked. */
301 static DBusMessage
* dbus_read_servers_ex(DBusMessage
*message
, int strings
)
303 DBusMessageIter iter
, array_iter
, string_iter
;
304 DBusMessage
*error
= NULL
;
305 const char *addr_err
;
308 my_syslog(LOG_INFO
, _("setting upstream servers from DBus"));
310 if (!dbus_message_iter_init(message
, &iter
))
312 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
313 "Failed to initialize dbus message iter");
316 /* check that the message contains an array of arrays */
317 if ((dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
) ||
318 (dbus_message_iter_get_element_type(&iter
) != (strings
? DBUS_TYPE_STRING
: DBUS_TYPE_ARRAY
)))
320 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
321 strings
? "Expected array of string" : "Expected array of string arrays");
326 /* array_iter points to each "as" element in the outer array */
327 dbus_message_iter_recurse(&iter
, &array_iter
);
328 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
)
330 const char *str
= NULL
;
331 union mysockaddr addr
, source_addr
;
332 char interface
[IF_NAMESIZE
];
333 char *str_addr
, *str_domain
= NULL
;
337 dbus_message_iter_get_basic(&array_iter
, &str
);
338 if (!str
|| !strlen (str
))
340 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
345 /* dup the string because it gets modified during parsing */
348 if (!(dup
= str_domain
= whine_malloc(strlen(str
)+1)))
351 strcpy(str_domain
, str
);
353 /* point to address part of old string for error message */
354 if ((str_addr
= strrchr(str
, '/')))
357 if ((str_addr
= strrchr(str_domain
, '/')))
359 if (*str_domain
!= '/' || str_addr
== str_domain
)
361 error
= dbus_message_new_error_printf(message
,
362 DBUS_ERROR_INVALID_ARGS
,
363 "No domain terminator '%s'",
372 str_addr
= str_domain
;
380 /* check the types of the struct and its elements */
381 if ((dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_ARRAY
) ||
382 (dbus_message_iter_get_element_type(&array_iter
) != DBUS_TYPE_STRING
))
384 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
385 "Expected inner array of strings");
389 /* string_iter points to each "s" element in the inner array */
390 dbus_message_iter_recurse(&array_iter
, &string_iter
);
391 if (dbus_message_iter_get_arg_type(&string_iter
) != DBUS_TYPE_STRING
)
393 /* no IP address given */
394 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
395 "Expected IP address");
399 dbus_message_iter_get_basic(&string_iter
, &str
);
400 if (!str
|| !strlen (str
))
402 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
407 /* dup the string because it gets modified during parsing */
410 if (!(dup
= str_addr
= whine_malloc(strlen(str
)+1)))
413 strcpy(str_addr
, str
);
416 memset(&addr
, 0, sizeof(addr
));
417 memset(&source_addr
, 0, sizeof(source_addr
));
418 memset(&interface
, 0, sizeof(interface
));
420 /* parse the IP address */
421 addr_err
= parse_server(str_addr
, &addr
, &source_addr
, (char *) &interface
, NULL
);
425 error
= dbus_message_new_error_printf(message
, DBUS_ERROR_INVALID_ARGS
,
426 "Invalid IP address '%s': %s",
438 if ((p
= strchr(str_domain
, '/')))
444 add_update_server(&addr
, &source_addr
, interface
, str_domain
);
445 } while ((str_domain
= p
));
449 /* jump past the address to the domain list (if any) */
450 dbus_message_iter_next (&string_iter
);
452 /* parse domains and add each server/domain pair to the list */
455 if (dbus_message_iter_get_arg_type(&string_iter
) == DBUS_TYPE_STRING
)
456 dbus_message_iter_get_basic(&string_iter
, &str
);
457 dbus_message_iter_next (&string_iter
);
459 add_update_server(&addr
, &source_addr
, interface
, str
);
460 } while (dbus_message_iter_get_arg_type(&string_iter
) == DBUS_TYPE_STRING
);
463 /* jump to next element in outer array */
464 dbus_message_iter_next(&array_iter
);
475 DBusHandlerResult
message_handler(DBusConnection
*connection
,
476 DBusMessage
*message
,
479 char *method
= (char *)dbus_message_get_member(message
);
480 DBusMessage
*reply
= NULL
;
482 if (dbus_message_is_method_call(message
, DBUS_INTERFACE_INTROSPECTABLE
, "Introspect"))
484 /* string length: "%s" provides space for termination zero */
485 if (!introspection_xml
&&
486 (introspection_xml
= whine_malloc(strlen(introspection_xml_template
) + strlen(daemon
->dbus_name
))))
487 sprintf(introspection_xml
, introspection_xml_template
, daemon
->dbus_name
);
489 if (introspection_xml
)
491 reply
= dbus_message_new_method_return(message
);
492 dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection_xml
, DBUS_TYPE_INVALID
);
495 else if (strcmp(method
, "GetVersion") == 0)
498 reply
= dbus_message_new_method_return(message
);
500 dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &v
, DBUS_TYPE_INVALID
);
502 else if (strcmp(method
, "SetServers") == 0)
504 my_syslog(LOG_INFO
, _("setting upstream servers from DBus"));
505 dbus_read_servers(message
);
508 else if (strcmp(method
, "SetServersEx") == 0)
510 reply
= dbus_read_servers_ex(message
, 0);
513 else if (strcmp(method
, "SetDomainServers") == 0)
515 reply
= dbus_read_servers_ex(message
, 1);
518 else if (strcmp(method
, "ClearCache") == 0)
519 clear_cache_and_reload(dnsmasq_time());
521 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED
);
523 method
= user_data
; /* no warning */
525 /* If no reply or no error, return nothing */
527 reply
= dbus_message_new_method_return(message
);
531 dbus_connection_send (connection
, reply
, NULL
);
532 dbus_message_unref (reply
);
535 return (DBUS_HANDLER_RESULT_HANDLED
);
539 /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
540 char *dbus_init(void)
542 DBusConnection
*connection
= NULL
;
543 DBusObjectPathVTable dnsmasq_vtable
= {NULL
, &message_handler
, NULL
, NULL
, NULL
, NULL
};
544 DBusError dbus_error
;
545 DBusMessage
*message
;
547 dbus_error_init (&dbus_error
);
548 if (!(connection
= dbus_bus_get (DBUS_BUS_SYSTEM
, &dbus_error
)))
551 dbus_connection_set_exit_on_disconnect(connection
, FALSE
);
552 dbus_connection_set_watch_functions(connection
, add_watch
, remove_watch
,
554 dbus_error_init (&dbus_error
);
555 dbus_bus_request_name (connection
, daemon
->dbus_name
, 0, &dbus_error
);
556 if (dbus_error_is_set (&dbus_error
))
557 return (char *)dbus_error
.message
;
559 if (!dbus_connection_register_object_path(connection
, DNSMASQ_PATH
,
560 &dnsmasq_vtable
, NULL
))
561 return _("could not register a DBus message handler");
563 daemon
->dbus
= connection
;
565 if ((message
= dbus_message_new_signal(DNSMASQ_PATH
, daemon
->dbus_name
, "Up")))
567 dbus_connection_send(connection
, message
, NULL
);
568 dbus_message_unref(message
);
575 void set_dbus_listeners(int *maxfdp
,
576 fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
580 for (w
= daemon
->watches
; w
; w
= w
->next
)
581 if (dbus_watch_get_enabled(w
->watch
))
583 unsigned int flags
= dbus_watch_get_flags(w
->watch
);
584 int fd
= dbus_watch_get_unix_fd(w
->watch
);
586 bump_maxfd(fd
, maxfdp
);
588 if (flags
& DBUS_WATCH_READABLE
)
591 if (flags
& DBUS_WATCH_WRITABLE
)
598 void check_dbus_listeners(fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
600 DBusConnection
*connection
= (DBusConnection
*)daemon
->dbus
;
603 for (w
= daemon
->watches
; w
; w
= w
->next
)
604 if (dbus_watch_get_enabled(w
->watch
))
606 unsigned int flags
= 0;
607 int fd
= dbus_watch_get_unix_fd(w
->watch
);
609 if (FD_ISSET(fd
, rset
))
610 flags
|= DBUS_WATCH_READABLE
;
612 if (FD_ISSET(fd
, wset
))
613 flags
|= DBUS_WATCH_WRITABLE
;
615 if (FD_ISSET(fd
, eset
))
616 flags
|= DBUS_WATCH_ERROR
;
619 dbus_watch_handle(w
->watch
, flags
);
624 dbus_connection_ref (connection
);
625 while (dbus_connection_dispatch (connection
) == DBUS_DISPATCH_DATA_REMAINS
);
626 dbus_connection_unref (connection
);
631 void emit_dbus_signal(int action
, struct dhcp_lease
*lease
, char *hostname
)
633 DBusConnection
*connection
= (DBusConnection
*)daemon
->dbus
;
634 DBusMessage
* message
= NULL
;
635 DBusMessageIter args
;
636 char *action_str
, *mac
= daemon
->namebuff
;
647 if (lease
->flags
& (LEASE_TA
| LEASE_NA
))
649 print_mac(mac
, lease
->clid
, lease
->clid_len
);
650 inet_ntop(AF_INET6
, lease
->hwaddr
, daemon
->addrbuff
, ADDRSTRLEN
);
655 p
= extended_hwaddr(lease
->hwaddr_type
, lease
->hwaddr_len
,
656 lease
->hwaddr
, lease
->clid_len
, lease
->clid
, &i
);
657 print_mac(mac
, p
, i
);
658 inet_ntop(AF_INET
, &lease
->addr
, daemon
->addrbuff
, ADDRSTRLEN
);
661 if (action
== ACTION_DEL
)
662 action_str
= "DhcpLeaseDeleted";
663 else if (action
== ACTION_ADD
)
664 action_str
= "DhcpLeaseAdded";
665 else if (action
== ACTION_OLD
)
666 action_str
= "DhcpLeaseUpdated";
670 if (!(message
= dbus_message_new_signal(DNSMASQ_PATH
, daemon
->dbus_name
, action_str
)))
673 dbus_message_iter_init_append(message
, &args
);
675 if (dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &daemon
->addrbuff
) &&
676 dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &mac
) &&
677 dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &hostname
))
678 dbus_connection_send(connection
, message
, NULL
);
680 dbus_message_unref(message
);