]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/dbus.c
import of dnsmasq-2.23.tar.gz
[people/ms/dnsmasq.git] / src / dbus.c
1 /* dnsmasq is Copyright (c) 2000-2005 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.
6
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.
11 */
12
13 #include "dnsmasq.h"
14
15 #ifdef HAVE_DBUS
16
17 #define DBUS_API_SUBJECT_TO_CHANGE
18 #include <dbus/dbus.h>
19
20 struct watch {
21 DBusWatch *watch;
22 struct watch *next;
23 };
24
25
26 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
27 {
28 struct daemon *daemon = data;
29 struct watch *w;
30
31 for (w = daemon->watches; w; w = w->next)
32 if (w->watch == watch)
33 return TRUE;
34
35 if (!(w = malloc(sizeof(struct watch))))
36 return FALSE;
37
38 w->watch = watch;
39 w->next = daemon->watches;
40 daemon->watches = w;
41
42 dbus_watch_set_data (watch, (void *)daemon, NULL);
43
44 return TRUE;
45 }
46
47 static void remove_watch(DBusWatch *watch, void *data)
48 {
49 struct daemon *daemon = data;
50 struct watch **up, *w;
51
52 for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
53 if (w->watch == watch)
54 {
55 *up = w->next;
56 free(w);
57 }
58 else
59 up = &(w->next);
60 }
61
62 static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
63 {
64 struct server *serv, *tmp, **up;
65 DBusMessageIter iter;
66 union mysockaddr addr, source_addr;
67 char *domain;
68
69 dbus_message_iter_init(message, &iter);
70
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;
75
76 while (1)
77 {
78 int skip = 0;
79
80 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
81 {
82 u32 a;
83
84 dbus_message_iter_get_basic(&iter, &a);
85 dbus_message_iter_next (&iter);
86
87 #ifdef HAVE_SOCKADDR_SA_LEN
88 source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
89 #endif
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);
95 }
96 else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
97 {
98 unsigned char p[sizeof(struct in6_addr)];
99 unsigned int i;
100
101 skip = 1;
102
103 for(i = 0; i < sizeof(struct in6_addr); i++)
104 {
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)
108 break;
109 }
110
111 #ifndef HAVE_IPV6
112 syslog(LOG_WARNING, "attempt to set an IPv6 server address via DBus - no IPv6 support");
113 #else
114 if (i == sizeof(struct in6_addr)-1)
115 {
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);
119 #endif
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);
125 skip = 0;
126 }
127 #endif
128 }
129 else
130 /* At the end */
131 break;
132
133 do {
134 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
135 {
136 dbus_message_iter_get_basic(&iter, &domain);
137 dbus_message_iter_next (&iter);
138 }
139 else
140 domain = NULL;
141
142 if (!skip)
143 {
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))
148 {
149 if (!(serv->flags & SERV_HAS_DOMAIN) && !domain)
150 {
151 serv->flags &= ~SERV_MARK;
152 break;
153 }
154 if ((serv->flags & SERV_HAS_DOMAIN) &&
155 domain &&
156 hostname_isequal(domain, serv->domain))
157 {
158 serv->flags &= ~SERV_MARK;
159 break;
160 }
161 }
162
163 if (!serv && (serv = malloc(sizeof (struct server))))
164 {
165 /* Not found, create a new one. */
166 if (domain)
167 serv->domain = malloc(strlen(domain)+1);
168 if (domain && !serv->domain)
169 {
170 free(serv);
171 serv = NULL;
172 }
173 else
174 {
175 serv->next = daemon->servers;
176 daemon->servers = serv;
177 serv->flags = SERV_FROM_DBUS;
178 serv->sfd = NULL;
179 if (domain)
180 {
181 strcpy(serv->domain, domain);
182 serv->flags |= SERV_HAS_DOMAIN;
183 }
184 }
185 }
186
187 if (serv)
188 {
189 if (source_addr.in.sin_family == AF_INET &&
190 addr.in.sin_addr.s_addr == 0 &&
191 serv->domain)
192 serv->flags |= SERV_NO_ADDR;
193 else
194 {
195 serv->flags &= ~SERV_NO_ADDR;
196 serv->addr = addr;
197 serv->source_addr = source_addr;
198 }
199 }
200 }
201 } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
202 }
203
204 /* unlink and free anything still marked. */
205 for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
206 {
207 tmp = serv->next;
208 if (serv->flags & SERV_MARK)
209 {
210 *up = serv->next;
211 free(serv);
212 }
213 else
214 up = &serv->next;
215 }
216
217 }
218
219 DBusHandlerResult message_handler (DBusConnection *connection,
220 DBusMessage *message,
221 void *user_data)
222 {
223 char *method = (char *)dbus_message_get_member(message);
224 struct daemon *daemon = (struct daemon *)user_data;
225
226 if (strcmp(method, "GetVersion") == 0)
227 {
228 char *v = VERSION;
229 DBusMessage *reply = dbus_message_new_method_return(message);
230
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);
234 }
235 else if (strcmp(method, "SetServers") == 0)
236 {
237 syslog(LOG_INFO, "setting upstream servers from DBus");
238 dbus_read_servers(daemon, message);
239 check_servers(daemon);
240 }
241 else if (strcmp(method, "ClearCache") == 0)
242 clear_cache_and_reload(daemon, dnsmasq_time(daemon->uptime_fd));
243 else
244 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
245
246 return (DBUS_HANDLER_RESULT_HANDLED);
247
248 }
249
250
251 /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
252 char *dbus_init(struct daemon *daemon)
253 {
254 DBusConnection *connection = NULL;
255 DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
256 DBusError dbus_error;
257 DBusMessage *message;
258
259 dbus_error_init (&dbus_error);
260 if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
261 return NULL;
262
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;
270
271 if (!dbus_connection_register_object_path(connection, DNSMASQ_PATH,
272 &dnsmasq_vtable, daemon))
273 return "could not register a DBus message handler";
274
275 daemon->dbus = connection;
276
277 if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
278 dbus_connection_send(connection, message, NULL);
279
280 return NULL;
281 }
282
283
284 int set_dbus_listeners(struct daemon *daemon, int maxfd,
285 fd_set *rset, fd_set *wset, fd_set *eset)
286 {
287 struct watch *w;
288
289 for (w = daemon->watches; w; w = w->next)
290 if (dbus_watch_get_enabled(w->watch))
291 {
292 unsigned int flags = dbus_watch_get_flags(w->watch);
293 int fd = dbus_watch_get_fd(w->watch);
294
295 if (fd > maxfd)
296 maxfd = fd;
297
298 if (flags & DBUS_WATCH_READABLE)
299 FD_SET(fd, rset);
300
301 if (flags & DBUS_WATCH_WRITABLE)
302 FD_SET(fd, wset);
303
304 FD_SET(fd, eset);
305 }
306 return maxfd;
307 }
308
309 void check_dbus_listeners(struct daemon *daemon,
310 fd_set *rset, fd_set *wset, fd_set *eset)
311 {
312 DBusConnection *connection = (DBusConnection *)daemon->dbus;
313 struct watch *w;
314
315 for (w = daemon->watches; w; w = w->next)
316 if (dbus_watch_get_enabled(w->watch))
317 {
318 unsigned int flags = 0;
319 int fd = dbus_watch_get_fd(w->watch);
320
321 if (FD_ISSET(fd, rset))
322 flags |= DBUS_WATCH_READABLE;
323
324 if (FD_ISSET(fd, wset))
325 flags |= DBUS_WATCH_WRITABLE;
326
327 if (FD_ISSET(fd, eset))
328 flags |= DBUS_WATCH_ERROR;
329
330 if (flags != 0)
331 dbus_watch_handle(w->watch, flags);
332 }
333
334 if (connection)
335 {
336 dbus_connection_ref (connection);
337 while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
338 dbus_connection_unref (connection);
339 }
340 }
341
342 #endif