1 /* dnsmasq is Copyright (c) 2000-2014 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 dbus_read_servers(DBusMessage
*message
)
113 DBusMessageIter iter
;
114 union mysockaddr addr
, source_addr
;
117 dbus_message_iter_init(message
, &iter
);
119 mark_servers(SERV_FROM_DBUS
);
125 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_UINT32
)
129 dbus_message_iter_get_basic(&iter
, &a
);
130 dbus_message_iter_next (&iter
);
132 #ifdef HAVE_SOCKADDR_SA_LEN
133 source_addr
.in
.sin_len
= addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
135 addr
.in
.sin_addr
.s_addr
= ntohl(a
);
136 source_addr
.in
.sin_family
= addr
.in
.sin_family
= AF_INET
;
137 addr
.in
.sin_port
= htons(NAMESERVER_PORT
);
138 source_addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
139 source_addr
.in
.sin_port
= htons(daemon
->query_port
);
141 else if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_BYTE
)
143 unsigned char p
[sizeof(struct in6_addr
)];
148 for(i
= 0; i
< sizeof(struct in6_addr
); i
++)
150 dbus_message_iter_get_basic(&iter
, &p
[i
]);
151 dbus_message_iter_next (&iter
);
152 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BYTE
)
157 my_syslog(LOG_WARNING
, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
159 if (i
== sizeof(struct in6_addr
)-1)
161 memcpy(&addr
.in6
.sin6_addr
, p
, sizeof(struct in6_addr
));
162 #ifdef HAVE_SOCKADDR_SA_LEN
163 source_addr
.in6
.sin6_len
= addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
165 source_addr
.in6
.sin6_family
= addr
.in6
.sin6_family
= AF_INET6
;
166 addr
.in6
.sin6_port
= htons(NAMESERVER_PORT
);
167 source_addr
.in6
.sin6_flowinfo
= addr
.in6
.sin6_flowinfo
= 0;
168 source_addr
.in6
.sin6_scope_id
= addr
.in6
.sin6_scope_id
= 0;
169 source_addr
.in6
.sin6_addr
= in6addr_any
;
170 source_addr
.in6
.sin6_port
= htons(daemon
->query_port
);
179 /* process each domain */
181 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
)
183 dbus_message_iter_get_basic(&iter
, &domain
);
184 dbus_message_iter_next (&iter
);
190 add_update_server(SERV_FROM_DBUS
, &addr
, &source_addr
, NULL
, domain
);
192 } while (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
);
195 /* unlink and free anything still marked. */
199 static DBusMessage
* dbus_read_servers_ex(DBusMessage
*message
, int strings
)
201 DBusMessageIter iter
, array_iter
, string_iter
;
202 DBusMessage
*error
= NULL
;
203 const char *addr_err
;
206 if (!dbus_message_iter_init(message
, &iter
))
208 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
209 "Failed to initialize dbus message iter");
212 /* check that the message contains an array of arrays */
213 if ((dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
) ||
214 (dbus_message_iter_get_element_type(&iter
) != (strings
? DBUS_TYPE_STRING
: DBUS_TYPE_ARRAY
)))
216 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
217 strings
? "Expected array of string" : "Expected array of string arrays");
220 mark_servers(SERV_FROM_DBUS
);
222 /* array_iter points to each "as" element in the outer array */
223 dbus_message_iter_recurse(&iter
, &array_iter
);
224 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
)
226 const char *str
= NULL
;
227 union mysockaddr addr
, source_addr
;
229 char interface
[IF_NAMESIZE
];
230 char *str_addr
, *str_domain
= NULL
;
234 dbus_message_iter_get_basic(&array_iter
, &str
);
235 if (!str
|| !strlen (str
))
237 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
242 /* dup the string because it gets modified during parsing */
245 if (!(dup
= str_domain
= whine_malloc(strlen(str
)+1)))
248 strcpy(str_domain
, str
);
250 /* point to address part of old string for error message */
251 if ((str_addr
= strrchr(str
, '/')))
254 if ((str_addr
= strrchr(str_domain
, '/')))
256 if (*str_domain
!= '/' || str_addr
== str_domain
)
258 error
= dbus_message_new_error_printf(message
,
259 DBUS_ERROR_INVALID_ARGS
,
260 "No domain terminator '%s'",
269 str_addr
= str_domain
;
277 /* check the types of the struct and its elements */
278 if ((dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_ARRAY
) ||
279 (dbus_message_iter_get_element_type(&array_iter
) != DBUS_TYPE_STRING
))
281 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
282 "Expected inner array of strings");
286 /* string_iter points to each "s" element in the inner array */
287 dbus_message_iter_recurse(&array_iter
, &string_iter
);
288 if (dbus_message_iter_get_arg_type(&string_iter
) != DBUS_TYPE_STRING
)
290 /* no IP address given */
291 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
292 "Expected IP address");
296 dbus_message_iter_get_basic(&string_iter
, &str
);
297 if (!str
|| !strlen (str
))
299 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
304 /* dup the string because it gets modified during parsing */
307 if (!(dup
= str_addr
= whine_malloc(strlen(str
)+1)))
310 strcpy(str_addr
, str
);
313 memset(&addr
, 0, sizeof(addr
));
314 memset(&source_addr
, 0, sizeof(source_addr
));
315 memset(&interface
, 0, sizeof(interface
));
317 /* parse the IP address */
318 if ((addr_err
= parse_server(str_addr
, &addr
, &source_addr
, (char *) &interface
, &flags
)))
320 error
= dbus_message_new_error_printf(message
, DBUS_ERROR_INVALID_ARGS
,
321 "Invalid IP address '%s': %s",
326 /* 0.0.0.0 for server address == NULL, for Dbus */
327 if (addr
.in
.sin_family
== AF_INET
&&
328 addr
.in
.sin_addr
.s_addr
== 0)
329 flags
|= SERV_NO_ADDR
;
338 if ((p
= strchr(str_domain
, '/')))
344 add_update_server(flags
| SERV_FROM_DBUS
, &addr
, &source_addr
, interface
, str_domain
);
345 } while ((str_domain
= p
));
349 /* jump past the address to the domain list (if any) */
350 dbus_message_iter_next (&string_iter
);
352 /* parse domains and add each server/domain pair to the list */
355 if (dbus_message_iter_get_arg_type(&string_iter
) == DBUS_TYPE_STRING
)
356 dbus_message_iter_get_basic(&string_iter
, &str
);
357 dbus_message_iter_next (&string_iter
);
359 add_update_server(flags
| SERV_FROM_DBUS
, &addr
, &source_addr
, interface
, str
);
360 } while (dbus_message_iter_get_arg_type(&string_iter
) == DBUS_TYPE_STRING
);
363 /* jump to next element in outer array */
364 dbus_message_iter_next(&array_iter
);
375 DBusHandlerResult
message_handler(DBusConnection
*connection
,
376 DBusMessage
*message
,
379 char *method
= (char *)dbus_message_get_member(message
);
380 DBusMessage
*reply
= NULL
;
381 int clear_cache
= 0, new_servers
= 0;
383 if (dbus_message_is_method_call(message
, DBUS_INTERFACE_INTROSPECTABLE
, "Introspect"))
385 /* string length: "%s" provides space for termination zero */
386 if (!introspection_xml
&&
387 (introspection_xml
= whine_malloc(strlen(introspection_xml_template
) + strlen(daemon
->dbus_name
))))
388 sprintf(introspection_xml
, introspection_xml_template
, daemon
->dbus_name
);
390 if (introspection_xml
)
392 reply
= dbus_message_new_method_return(message
);
393 dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection_xml
, DBUS_TYPE_INVALID
);
396 else if (strcmp(method
, "GetVersion") == 0)
399 reply
= dbus_message_new_method_return(message
);
401 dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &v
, DBUS_TYPE_INVALID
);
403 else if (strcmp(method
, "SetServers") == 0)
405 dbus_read_servers(message
);
408 else if (strcmp(method
, "SetServersEx") == 0)
410 reply
= dbus_read_servers_ex(message
, 0);
413 else if (strcmp(method
, "SetDomainServers") == 0)
415 reply
= dbus_read_servers_ex(message
, 1);
418 else if (strcmp(method
, "ClearCache") == 0)
421 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED
);
425 my_syslog(LOG_INFO
, _("setting upstream servers from DBus"));
427 if (option_bool(OPT_RELOAD
))
432 clear_cache_and_reload(dnsmasq_time());
434 method
= user_data
; /* no warning */
436 /* If no reply or no error, return nothing */
438 reply
= dbus_message_new_method_return(message
);
442 dbus_connection_send (connection
, reply
, NULL
);
443 dbus_message_unref (reply
);
446 return (DBUS_HANDLER_RESULT_HANDLED
);
450 /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
451 char *dbus_init(void)
453 DBusConnection
*connection
= NULL
;
454 DBusObjectPathVTable dnsmasq_vtable
= {NULL
, &message_handler
, NULL
, NULL
, NULL
, NULL
};
455 DBusError dbus_error
;
456 DBusMessage
*message
;
458 dbus_error_init (&dbus_error
);
459 if (!(connection
= dbus_bus_get (DBUS_BUS_SYSTEM
, &dbus_error
)))
462 dbus_connection_set_exit_on_disconnect(connection
, FALSE
);
463 dbus_connection_set_watch_functions(connection
, add_watch
, remove_watch
,
465 dbus_error_init (&dbus_error
);
466 dbus_bus_request_name (connection
, daemon
->dbus_name
, 0, &dbus_error
);
467 if (dbus_error_is_set (&dbus_error
))
468 return (char *)dbus_error
.message
;
470 if (!dbus_connection_register_object_path(connection
, DNSMASQ_PATH
,
471 &dnsmasq_vtable
, NULL
))
472 return _("could not register a DBus message handler");
474 daemon
->dbus
= connection
;
476 if ((message
= dbus_message_new_signal(DNSMASQ_PATH
, daemon
->dbus_name
, "Up")))
478 dbus_connection_send(connection
, message
, NULL
);
479 dbus_message_unref(message
);
486 void set_dbus_listeners(int *maxfdp
,
487 fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
491 for (w
= daemon
->watches
; w
; w
= w
->next
)
492 if (dbus_watch_get_enabled(w
->watch
))
494 unsigned int flags
= dbus_watch_get_flags(w
->watch
);
495 int fd
= dbus_watch_get_unix_fd(w
->watch
);
497 bump_maxfd(fd
, maxfdp
);
499 if (flags
& DBUS_WATCH_READABLE
)
502 if (flags
& DBUS_WATCH_WRITABLE
)
509 void check_dbus_listeners(fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
511 DBusConnection
*connection
= (DBusConnection
*)daemon
->dbus
;
514 for (w
= daemon
->watches
; w
; w
= w
->next
)
515 if (dbus_watch_get_enabled(w
->watch
))
517 unsigned int flags
= 0;
518 int fd
= dbus_watch_get_unix_fd(w
->watch
);
520 if (FD_ISSET(fd
, rset
))
521 flags
|= DBUS_WATCH_READABLE
;
523 if (FD_ISSET(fd
, wset
))
524 flags
|= DBUS_WATCH_WRITABLE
;
526 if (FD_ISSET(fd
, eset
))
527 flags
|= DBUS_WATCH_ERROR
;
530 dbus_watch_handle(w
->watch
, flags
);
535 dbus_connection_ref (connection
);
536 while (dbus_connection_dispatch (connection
) == DBUS_DISPATCH_DATA_REMAINS
);
537 dbus_connection_unref (connection
);
542 void emit_dbus_signal(int action
, struct dhcp_lease
*lease
, char *hostname
)
544 DBusConnection
*connection
= (DBusConnection
*)daemon
->dbus
;
545 DBusMessage
* message
= NULL
;
546 DBusMessageIter args
;
547 char *action_str
, *mac
= daemon
->namebuff
;
558 if (lease
->flags
& (LEASE_TA
| LEASE_NA
))
560 print_mac(mac
, lease
->clid
, lease
->clid_len
);
561 inet_ntop(AF_INET6
, lease
->hwaddr
, daemon
->addrbuff
, ADDRSTRLEN
);
566 p
= extended_hwaddr(lease
->hwaddr_type
, lease
->hwaddr_len
,
567 lease
->hwaddr
, lease
->clid_len
, lease
->clid
, &i
);
568 print_mac(mac
, p
, i
);
569 inet_ntop(AF_INET
, &lease
->addr
, daemon
->addrbuff
, ADDRSTRLEN
);
572 if (action
== ACTION_DEL
)
573 action_str
= "DhcpLeaseDeleted";
574 else if (action
== ACTION_ADD
)
575 action_str
= "DhcpLeaseAdded";
576 else if (action
== ACTION_OLD
)
577 action_str
= "DhcpLeaseUpdated";
581 if (!(message
= dbus_message_new_signal(DNSMASQ_PATH
, daemon
->dbus_name
, action_str
)))
584 dbus_message_iter_init_append(message
, &args
);
586 if (dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &daemon
->addrbuff
) &&
587 dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &mac
) &&
588 dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &hostname
))
589 dbus_connection_send(connection
, message
, NULL
);
591 dbus_message_unref(message
);