1 /* dnsmasq is Copyright (c) 2000-2015 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"
39 " <method name=\"GetLoopServers\">\n"
40 " <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
43 " <method name=\"SetServers\">\n"
44 " <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
46 " <method name=\"SetDomainServers\">\n"
47 " <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
49 " <method name=\"SetServersEx\">\n"
50 " <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
52 " <method name=\"SetFilterWin2KOption\">\n"
53 " <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
55 " <method name=\"SetBogusPrivOption\">\n"
56 " <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
58 " <signal name=\"DhcpLeaseAdded\">\n"
59 " <arg name=\"ipaddr\" type=\"s\"/>\n"
60 " <arg name=\"hwaddr\" type=\"s\"/>\n"
61 " <arg name=\"hostname\" type=\"s\"/>\n"
63 " <signal name=\"DhcpLeaseDeleted\">\n"
64 " <arg name=\"ipaddr\" type=\"s\"/>\n"
65 " <arg name=\"hwaddr\" type=\"s\"/>\n"
66 " <arg name=\"hostname\" type=\"s\"/>\n"
68 " <signal name=\"DhcpLeaseUpdated\">\n"
69 " <arg name=\"ipaddr\" type=\"s\"/>\n"
70 " <arg name=\"hwaddr\" type=\"s\"/>\n"
71 " <arg name=\"hostname\" type=\"s\"/>\n"
76 static char *introspection_xml
= NULL
;
84 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
)
88 for (w
= daemon
->watches
; w
; w
= w
->next
)
89 if (w
->watch
== watch
)
92 if (!(w
= whine_malloc(sizeof(struct watch
))))
96 w
->next
= daemon
->watches
;
99 w
= data
; /* no warning */
103 static void remove_watch(DBusWatch
*watch
, void *data
)
105 struct watch
**up
, *w
, *tmp
;
107 for (up
= &(daemon
->watches
), w
= daemon
->watches
; w
; w
= tmp
)
110 if (w
->watch
== watch
)
119 w
= data
; /* no warning */
122 static void dbus_read_servers(DBusMessage
*message
)
124 DBusMessageIter iter
;
125 union mysockaddr addr
, source_addr
;
128 dbus_message_iter_init(message
, &iter
);
130 mark_servers(SERV_FROM_DBUS
);
136 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_UINT32
)
140 dbus_message_iter_get_basic(&iter
, &a
);
141 dbus_message_iter_next (&iter
);
143 #ifdef HAVE_SOCKADDR_SA_LEN
144 source_addr
.in
.sin_len
= addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
146 addr
.in
.sin_addr
.s_addr
= ntohl(a
);
147 source_addr
.in
.sin_family
= addr
.in
.sin_family
= AF_INET
;
148 addr
.in
.sin_port
= htons(NAMESERVER_PORT
);
149 source_addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
150 source_addr
.in
.sin_port
= htons(daemon
->query_port
);
152 else if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_BYTE
)
154 unsigned char p
[sizeof(struct in6_addr
)];
159 for(i
= 0; i
< sizeof(struct in6_addr
); i
++)
161 dbus_message_iter_get_basic(&iter
, &p
[i
]);
162 dbus_message_iter_next (&iter
);
163 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BYTE
)
171 my_syslog(LOG_WARNING
, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
173 if (i
== sizeof(struct in6_addr
))
175 memcpy(&addr
.in6
.sin6_addr
, p
, sizeof(struct in6_addr
));
176 #ifdef HAVE_SOCKADDR_SA_LEN
177 source_addr
.in6
.sin6_len
= addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
179 source_addr
.in6
.sin6_family
= addr
.in6
.sin6_family
= AF_INET6
;
180 addr
.in6
.sin6_port
= htons(NAMESERVER_PORT
);
181 source_addr
.in6
.sin6_flowinfo
= addr
.in6
.sin6_flowinfo
= 0;
182 source_addr
.in6
.sin6_scope_id
= addr
.in6
.sin6_scope_id
= 0;
183 source_addr
.in6
.sin6_addr
= in6addr_any
;
184 source_addr
.in6
.sin6_port
= htons(daemon
->query_port
);
193 /* process each domain */
195 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
)
197 dbus_message_iter_get_basic(&iter
, &domain
);
198 dbus_message_iter_next (&iter
);
204 add_update_server(SERV_FROM_DBUS
, &addr
, &source_addr
, NULL
, domain
);
206 } while (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
);
209 /* unlink and free anything still marked. */
214 static DBusMessage
*dbus_reply_server_loop(DBusMessage
*message
)
216 DBusMessageIter args
, args_iter
;
218 DBusMessage
*reply
= dbus_message_new_method_return(message
);
220 dbus_message_iter_init_append (reply
, &args
);
221 dbus_message_iter_open_container (&args
, DBUS_TYPE_ARRAY
,DBUS_TYPE_STRING_AS_STRING
, &args_iter
);
223 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
224 if (serv
->flags
& SERV_LOOP
)
226 prettyprint_addr(&serv
->addr
, daemon
->addrbuff
);
227 dbus_message_iter_append_basic (&args_iter
, DBUS_TYPE_STRING
, &daemon
->addrbuff
);
230 dbus_message_iter_close_container (&args
, &args_iter
);
236 static DBusMessage
* dbus_read_servers_ex(DBusMessage
*message
, int strings
)
238 DBusMessageIter iter
, array_iter
, string_iter
;
239 DBusMessage
*error
= NULL
;
240 const char *addr_err
;
243 if (!dbus_message_iter_init(message
, &iter
))
245 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
246 "Failed to initialize dbus message iter");
249 /* check that the message contains an array of arrays */
250 if ((dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
) ||
251 (dbus_message_iter_get_element_type(&iter
) != (strings
? DBUS_TYPE_STRING
: DBUS_TYPE_ARRAY
)))
253 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
254 strings
? "Expected array of string" : "Expected array of string arrays");
257 mark_servers(SERV_FROM_DBUS
);
259 /* array_iter points to each "as" element in the outer array */
260 dbus_message_iter_recurse(&iter
, &array_iter
);
261 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
)
263 const char *str
= NULL
;
264 union mysockaddr addr
, source_addr
;
266 char interface
[IF_NAMESIZE
];
267 char *str_addr
, *str_domain
= NULL
;
271 dbus_message_iter_get_basic(&array_iter
, &str
);
272 if (!str
|| !strlen (str
))
274 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
279 /* dup the string because it gets modified during parsing */
282 if (!(dup
= str_domain
= whine_malloc(strlen(str
)+1)))
285 strcpy(str_domain
, str
);
287 /* point to address part of old string for error message */
288 if ((str_addr
= strrchr(str
, '/')))
291 if ((str_addr
= strrchr(str_domain
, '/')))
293 if (*str_domain
!= '/' || str_addr
== str_domain
)
295 error
= dbus_message_new_error_printf(message
,
296 DBUS_ERROR_INVALID_ARGS
,
297 "No domain terminator '%s'",
306 str_addr
= str_domain
;
314 /* check the types of the struct and its elements */
315 if ((dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_ARRAY
) ||
316 (dbus_message_iter_get_element_type(&array_iter
) != DBUS_TYPE_STRING
))
318 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
319 "Expected inner array of strings");
323 /* string_iter points to each "s" element in the inner array */
324 dbus_message_iter_recurse(&array_iter
, &string_iter
);
325 if (dbus_message_iter_get_arg_type(&string_iter
) != DBUS_TYPE_STRING
)
327 /* no IP address given */
328 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
329 "Expected IP address");
333 dbus_message_iter_get_basic(&string_iter
, &str
);
334 if (!str
|| !strlen (str
))
336 error
= dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
341 /* dup the string because it gets modified during parsing */
344 if (!(dup
= str_addr
= whine_malloc(strlen(str
)+1)))
347 strcpy(str_addr
, str
);
350 memset(&addr
, 0, sizeof(addr
));
351 memset(&source_addr
, 0, sizeof(source_addr
));
352 memset(&interface
, 0, sizeof(interface
));
354 /* parse the IP address */
355 if ((addr_err
= parse_server(str_addr
, &addr
, &source_addr
, (char *) &interface
, &flags
)))
357 error
= dbus_message_new_error_printf(message
, DBUS_ERROR_INVALID_ARGS
,
358 "Invalid IP address '%s': %s",
363 /* 0.0.0.0 for server address == NULL, for Dbus */
364 if (addr
.in
.sin_family
== AF_INET
&&
365 addr
.in
.sin_addr
.s_addr
== 0)
366 flags
|= SERV_NO_ADDR
;
375 if ((p
= strchr(str_domain
, '/')))
381 add_update_server(flags
| SERV_FROM_DBUS
, &addr
, &source_addr
, interface
, str_domain
);
382 } while ((str_domain
= p
));
386 /* jump past the address to the domain list (if any) */
387 dbus_message_iter_next (&string_iter
);
389 /* parse domains and add each server/domain pair to the list */
392 if (dbus_message_iter_get_arg_type(&string_iter
) == DBUS_TYPE_STRING
)
393 dbus_message_iter_get_basic(&string_iter
, &str
);
394 dbus_message_iter_next (&string_iter
);
396 add_update_server(flags
| SERV_FROM_DBUS
, &addr
, &source_addr
, interface
, str
);
397 } while (dbus_message_iter_get_arg_type(&string_iter
) == DBUS_TYPE_STRING
);
400 /* jump to next element in outer array */
401 dbus_message_iter_next(&array_iter
);
412 static DBusMessage
*dbus_set_bool(DBusMessage
*message
, int flag
, char *name
)
414 DBusMessageIter iter
;
417 if (!dbus_message_iter_init(message
, &iter
) || dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BOOLEAN
)
418 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
, "Expected boolean argument");
420 dbus_message_iter_get_basic(&iter
, &enabled
);
424 my_syslog(LOG_INFO
, "Enabling --%s option from D-Bus", name
);
425 set_option_bool(flag
);
429 my_syslog(LOG_INFO
, "Disabling --%s option from D-Bus", name
);
430 reset_option_bool(flag
);
436 DBusHandlerResult
message_handler(DBusConnection
*connection
,
437 DBusMessage
*message
,
440 char *method
= (char *)dbus_message_get_member(message
);
441 DBusMessage
*reply
= NULL
;
442 int clear_cache
= 0, new_servers
= 0;
444 if (dbus_message_is_method_call(message
, DBUS_INTERFACE_INTROSPECTABLE
, "Introspect"))
446 /* string length: "%s" provides space for termination zero */
447 if (!introspection_xml
&&
448 (introspection_xml
= whine_malloc(strlen(introspection_xml_template
) + strlen(daemon
->dbus_name
))))
449 sprintf(introspection_xml
, introspection_xml_template
, daemon
->dbus_name
);
451 if (introspection_xml
)
453 reply
= dbus_message_new_method_return(message
);
454 dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection_xml
, DBUS_TYPE_INVALID
);
457 else if (strcmp(method
, "GetVersion") == 0)
460 reply
= dbus_message_new_method_return(message
);
462 dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &v
, DBUS_TYPE_INVALID
);
465 else if (strcmp(method
, "GetLoopServers") == 0)
467 reply
= dbus_reply_server_loop(message
);
470 else if (strcmp(method
, "SetServers") == 0)
472 dbus_read_servers(message
);
475 else if (strcmp(method
, "SetServersEx") == 0)
477 reply
= dbus_read_servers_ex(message
, 0);
480 else if (strcmp(method
, "SetDomainServers") == 0)
482 reply
= dbus_read_servers_ex(message
, 1);
485 else if (strcmp(method
, "SetFilterWin2KOption") == 0)
487 reply
= dbus_set_bool(message
, OPT_FILTER
, "filterwin2k");
489 else if (strcmp(method
, "SetBogusPrivOption") == 0)
491 reply
= dbus_set_bool(message
, OPT_BOGUSPRIV
, "bogus-priv");
493 else if (strcmp(method
, "ClearCache") == 0)
496 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED
);
500 my_syslog(LOG_INFO
, _("setting upstream servers from DBus"));
502 if (option_bool(OPT_RELOAD
))
507 clear_cache_and_reload(dnsmasq_time());
509 method
= user_data
; /* no warning */
511 /* If no reply or no error, return nothing */
513 reply
= dbus_message_new_method_return(message
);
517 dbus_connection_send (connection
, reply
, NULL
);
518 dbus_message_unref (reply
);
521 return (DBUS_HANDLER_RESULT_HANDLED
);
525 /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
526 char *dbus_init(void)
528 DBusConnection
*connection
= NULL
;
529 DBusObjectPathVTable dnsmasq_vtable
= {NULL
, &message_handler
, NULL
, NULL
, NULL
, NULL
};
530 DBusError dbus_error
;
531 DBusMessage
*message
;
533 dbus_error_init (&dbus_error
);
534 if (!(connection
= dbus_bus_get (DBUS_BUS_SYSTEM
, &dbus_error
)))
537 dbus_connection_set_exit_on_disconnect(connection
, FALSE
);
538 dbus_connection_set_watch_functions(connection
, add_watch
, remove_watch
,
540 dbus_error_init (&dbus_error
);
541 dbus_bus_request_name (connection
, daemon
->dbus_name
, 0, &dbus_error
);
542 if (dbus_error_is_set (&dbus_error
))
543 return (char *)dbus_error
.message
;
545 if (!dbus_connection_register_object_path(connection
, DNSMASQ_PATH
,
546 &dnsmasq_vtable
, NULL
))
547 return _("could not register a DBus message handler");
549 daemon
->dbus
= connection
;
551 if ((message
= dbus_message_new_signal(DNSMASQ_PATH
, daemon
->dbus_name
, "Up")))
553 dbus_connection_send(connection
, message
, NULL
);
554 dbus_message_unref(message
);
561 void set_dbus_listeners(int *maxfdp
,
562 fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
566 for (w
= daemon
->watches
; w
; w
= w
->next
)
567 if (dbus_watch_get_enabled(w
->watch
))
569 unsigned int flags
= dbus_watch_get_flags(w
->watch
);
570 int fd
= dbus_watch_get_unix_fd(w
->watch
);
572 bump_maxfd(fd
, maxfdp
);
574 if (flags
& DBUS_WATCH_READABLE
)
577 if (flags
& DBUS_WATCH_WRITABLE
)
584 void check_dbus_listeners(fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
586 DBusConnection
*connection
= (DBusConnection
*)daemon
->dbus
;
589 for (w
= daemon
->watches
; w
; w
= w
->next
)
590 if (dbus_watch_get_enabled(w
->watch
))
592 unsigned int flags
= 0;
593 int fd
= dbus_watch_get_unix_fd(w
->watch
);
595 if (FD_ISSET(fd
, rset
))
596 flags
|= DBUS_WATCH_READABLE
;
598 if (FD_ISSET(fd
, wset
))
599 flags
|= DBUS_WATCH_WRITABLE
;
601 if (FD_ISSET(fd
, eset
))
602 flags
|= DBUS_WATCH_ERROR
;
605 dbus_watch_handle(w
->watch
, flags
);
610 dbus_connection_ref (connection
);
611 while (dbus_connection_dispatch (connection
) == DBUS_DISPATCH_DATA_REMAINS
);
612 dbus_connection_unref (connection
);
617 void emit_dbus_signal(int action
, struct dhcp_lease
*lease
, char *hostname
)
619 DBusConnection
*connection
= (DBusConnection
*)daemon
->dbus
;
620 DBusMessage
* message
= NULL
;
621 DBusMessageIter args
;
622 char *action_str
, *mac
= daemon
->namebuff
;
633 if (lease
->flags
& (LEASE_TA
| LEASE_NA
))
635 print_mac(mac
, lease
->clid
, lease
->clid_len
);
636 inet_ntop(AF_INET6
, &lease
->addr6
, daemon
->addrbuff
, ADDRSTRLEN
);
641 p
= extended_hwaddr(lease
->hwaddr_type
, lease
->hwaddr_len
,
642 lease
->hwaddr
, lease
->clid_len
, lease
->clid
, &i
);
643 print_mac(mac
, p
, i
);
644 inet_ntop(AF_INET
, &lease
->addr
, daemon
->addrbuff
, ADDRSTRLEN
);
647 if (action
== ACTION_DEL
)
648 action_str
= "DhcpLeaseDeleted";
649 else if (action
== ACTION_ADD
)
650 action_str
= "DhcpLeaseAdded";
651 else if (action
== ACTION_OLD
)
652 action_str
= "DhcpLeaseUpdated";
656 if (!(message
= dbus_message_new_signal(DNSMASQ_PATH
, daemon
->dbus_name
, action_str
)))
659 dbus_message_iter_init_append(message
, &args
);
661 if (dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &daemon
->addrbuff
) &&
662 dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &mac
) &&
663 dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
, &hostname
))
664 dbus_connection_send(connection
, message
, NULL
);
666 dbus_message_unref(message
);