1 /* dnsmasq is Copyright (c) 2000-2005 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.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
17 #define DBUS_API_SUBJECT_TO_CHANGE
18 #include <dbus/dbus.h>
26 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
)
28 struct daemon
*daemon
= data
;
31 for (w
= daemon
->watches
; w
; w
= w
->next
)
32 if (w
->watch
== watch
)
35 if (!(w
= malloc(sizeof(struct watch
))))
39 w
->next
= daemon
->watches
;
42 dbus_watch_set_data (watch
, (void *)daemon
, NULL
);
47 static void remove_watch(DBusWatch
*watch
, void *data
)
49 struct daemon
*daemon
= data
;
50 struct watch
**up
, *w
;
52 for (up
= &(daemon
->watches
), w
= daemon
->watches
; w
; w
= w
->next
)
53 if (w
->watch
== watch
)
62 static void dbus_read_servers(struct daemon
*daemon
, DBusMessage
*message
)
64 struct server
*serv
, *tmp
, **up
;
66 union mysockaddr addr
, source_addr
;
69 dbus_message_iter_init(message
, &iter
);
71 /* mark everything from DBUS */
72 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
73 if (serv
->flags
& SERV_FROM_DBUS
)
74 serv
->flags
|= SERV_MARK
;
80 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_UINT32
)
84 dbus_message_iter_get_basic(&iter
, &a
);
85 dbus_message_iter_next (&iter
);
87 #ifdef HAVE_SOCKADDR_SA_LEN
88 source_addr
.in
.sin_len
= addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
90 addr
.in
.sin_addr
.s_addr
= ntohl(a
);
91 source_addr
.in
.sin_family
= addr
.in
.sin_family
= AF_INET
;
92 addr
.in
.sin_port
= htons(NAMESERVER_PORT
);
93 source_addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
94 source_addr
.in
.sin_port
= htons(daemon
->query_port
);
96 else if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_BYTE
)
98 unsigned char p
[sizeof(struct in6_addr
)];
103 for(i
= 0; i
< sizeof(struct in6_addr
); i
++)
105 dbus_message_iter_get_basic(&iter
, &p
[i
]);
106 dbus_message_iter_next (&iter
);
107 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BYTE
)
112 syslog(LOG_WARNING
, "attempt to set an IPv6 server address via DBus - no IPv6 support");
114 if (i
== sizeof(struct in6_addr
)-1)
116 memcpy(&addr
.in6
.sin6_addr
, p
, sizeof(struct in6_addr
));
117 #ifdef HAVE_SOCKADDR_SA_LEN
118 source_addr
.in6
.sin6_len
= addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
120 source_addr
.in6
.sin6_family
= addr
.in6
.sin6_family
= AF_INET6
;
121 addr
.in6
.sin6_port
= htons(NAMESERVER_PORT
);
122 source_addr
.in6
.sin6_flowinfo
= addr
.in6
.sin6_flowinfo
= htonl(0);
123 source_addr
.in6
.sin6_addr
= in6addr_any
;
124 source_addr
.in6
.sin6_port
= htons(daemon
->query_port
);
134 if (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
)
136 dbus_message_iter_get_basic(&iter
, &domain
);
137 dbus_message_iter_next (&iter
);
144 /* See if this is already there, and unmark */
145 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
146 if ((serv
->flags
& SERV_FROM_DBUS
) &&
147 (serv
->flags
& SERV_MARK
))
149 if (!(serv
->flags
& SERV_HAS_DOMAIN
) && !domain
)
151 serv
->flags
&= ~SERV_MARK
;
154 if ((serv
->flags
& SERV_HAS_DOMAIN
) &&
156 hostname_isequal(domain
, serv
->domain
))
158 serv
->flags
&= ~SERV_MARK
;
163 if (!serv
&& (serv
= malloc(sizeof (struct server
))))
165 /* Not found, create a new one. */
167 serv
->domain
= malloc(strlen(domain
)+1);
168 if (domain
&& !serv
->domain
)
175 serv
->next
= daemon
->servers
;
176 daemon
->servers
= serv
;
177 serv
->flags
= SERV_FROM_DBUS
;
181 strcpy(serv
->domain
, domain
);
182 serv
->flags
|= SERV_HAS_DOMAIN
;
189 if (source_addr
.in
.sin_family
== AF_INET
&&
190 addr
.in
.sin_addr
.s_addr
== 0 &&
192 serv
->flags
|= SERV_NO_ADDR
;
195 serv
->flags
&= ~SERV_NO_ADDR
;
197 serv
->source_addr
= source_addr
;
201 } while (dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_STRING
);
204 /* unlink and free anything still marked. */
205 for (serv
= daemon
->servers
, up
= &daemon
->servers
; serv
; serv
= tmp
)
208 if (serv
->flags
& SERV_MARK
)
219 DBusHandlerResult
message_handler (DBusConnection
*connection
,
220 DBusMessage
*message
,
223 char *method
= (char *)dbus_message_get_member(message
);
224 struct daemon
*daemon
= (struct daemon
*)user_data
;
226 if (strcmp(method
, "GetVersion") == 0)
229 DBusMessage
*reply
= dbus_message_new_method_return(message
);
231 dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &v
, DBUS_TYPE_INVALID
);
232 dbus_connection_send (connection
, reply
, NULL
);
233 dbus_message_unref (reply
);
235 else if (strcmp(method
, "SetServers") == 0)
237 syslog(LOG_INFO
, "setting upstream servers from DBus");
238 dbus_read_servers(daemon
, message
);
239 check_servers(daemon
);
241 else if (strcmp(method
, "ClearCache") == 0)
242 clear_cache_and_reload(daemon
, dnsmasq_time(daemon
->uptime_fd
));
244 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED
);
246 return (DBUS_HANDLER_RESULT_HANDLED
);
251 /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
252 char *dbus_init(struct daemon
*daemon
)
254 DBusConnection
*connection
= NULL
;
255 DBusObjectPathVTable dnsmasq_vtable
= {NULL
, &message_handler
, NULL
, NULL
, NULL
, NULL
};
256 DBusError dbus_error
;
257 DBusMessage
*message
;
259 dbus_error_init (&dbus_error
);
260 if (!(connection
= dbus_bus_get (DBUS_BUS_SYSTEM
, &dbus_error
)))
263 dbus_connection_set_exit_on_disconnect(connection
, FALSE
);
264 dbus_connection_set_watch_functions(connection
, add_watch
, remove_watch
,
265 NULL
, (void *)daemon
, NULL
);
266 dbus_error_init (&dbus_error
);
267 dbus_bus_request_name (connection
, DNSMASQ_SERVICE
, 0, &dbus_error
);
268 if (dbus_error_is_set (&dbus_error
))
269 return (char *)dbus_error
.message
;
271 if (!dbus_connection_register_object_path(connection
, DNSMASQ_PATH
,
272 &dnsmasq_vtable
, daemon
))
273 return "could not register a DBus message handler";
275 daemon
->dbus
= connection
;
277 if ((message
= dbus_message_new_signal(DNSMASQ_PATH
, DNSMASQ_SERVICE
, "Up")))
278 dbus_connection_send(connection
, message
, NULL
);
284 int set_dbus_listeners(struct daemon
*daemon
, int maxfd
,
285 fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
289 for (w
= daemon
->watches
; w
; w
= w
->next
)
290 if (dbus_watch_get_enabled(w
->watch
))
292 unsigned int flags
= dbus_watch_get_flags(w
->watch
);
293 int fd
= dbus_watch_get_fd(w
->watch
);
298 if (flags
& DBUS_WATCH_READABLE
)
301 if (flags
& DBUS_WATCH_WRITABLE
)
309 void check_dbus_listeners(struct daemon
*daemon
,
310 fd_set
*rset
, fd_set
*wset
, fd_set
*eset
)
312 DBusConnection
*connection
= (DBusConnection
*)daemon
->dbus
;
315 for (w
= daemon
->watches
; w
; w
= w
->next
)
316 if (dbus_watch_get_enabled(w
->watch
))
318 unsigned int flags
= 0;
319 int fd
= dbus_watch_get_fd(w
->watch
);
321 if (FD_ISSET(fd
, rset
))
322 flags
|= DBUS_WATCH_READABLE
;
324 if (FD_ISSET(fd
, wset
))
325 flags
|= DBUS_WATCH_WRITABLE
;
327 if (FD_ISSET(fd
, eset
))
328 flags
|= DBUS_WATCH_ERROR
;
331 dbus_watch_handle(w
->watch
, flags
);
336 dbus_connection_ref (connection
);
337 while (dbus_connection_dispatch (connection
) == DBUS_DISPATCH_DATA_REMAINS
);
338 dbus_connection_unref (connection
);