1 /*
2  * Copyright (c) 2010, 2011 Christiano F. Haesbaert <haesbaert@haesbaert.org>
3  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <arpa/nameser.h>
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 #include "mdnsd.h"
36 #include "mdns.h"
37 #include "log.h"
38 #include "control.h"
39 
40 #define	CONTROL_BACKLOG	5
41 
42 struct ctl_conn	*control_connbyfd(int);
43 struct ctl_conn	*control_connbypid(pid_t);
44 void		 control_close(int);
45 void		 control_lookup(struct ctl_conn *, struct imsg *);
46 void		 control_browse_add(struct ctl_conn *, struct imsg *);
47 void		 control_browse_del(struct ctl_conn *, struct imsg *);
48 void		 control_resolve(struct ctl_conn *, struct imsg *);
49 void		 control_group_add(struct ctl_conn *, struct imsg *);
50 void		 control_group_reset(struct ctl_conn *, struct imsg *);
51 void		 control_group_commit(struct ctl_conn *, struct imsg *);
52 void		 control_group_add_service(struct ctl_conn *, struct imsg *);
53 
54 extern struct mdnsd_conf *conf;
55 
56 struct control_state control_state;
57 
58 void
control_lookup(struct ctl_conn * c,struct imsg * imsg)59 control_lookup(struct ctl_conn *c, struct imsg *imsg)
60 {
61 	struct rrset	 mlkup, *rrs;
62 	struct rr	*rr;
63 	struct query	*q;
64 	struct timeval	 tv;
65 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup))
66 		return;
67 
68 	memcpy(&mlkup, imsg->data, sizeof(mlkup));
69 	mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients are nice */
70 
71 	switch (mlkup.type) {
72 	case T_A:		/* FALLTHROUGH */
73 	case T_HINFO:		/* FALLTHROUGH */
74 	case T_PTR:		/* FALLTHROUGH */
75 	case T_SRV:		/* FALLTHROUGH */
76 	case T_TXT:		/* FALLTHROUGH */
77 		break;
78 	default:
79 		log_warnx("Lookup type %d not supported/implemented",
80 		    mlkup.type);
81 		return;
82 	}
83 
84 	if (mlkup.class != C_IN) {
85 		log_warnx("Lookup class %d not supported/implemented",
86 		    mlkup.class);
87 		return;
88 	}
89 
90 	/* Check if control has this query already, if so don't do anything */
91 	LIST_FOREACH(q, &c->qlist, entry) {
92 		if (q->style != QUERY_LOOKUP)
93 			continue;
94 		LIST_FOREACH(rrs, &q->rrslist, entry)
95 		    if (rrset_cmp(rrs, &mlkup) == 0) {
96 			    log_debug("control already querying for %s",
97 				rrs_str(rrs));
98 			    return;
99 		    }
100 	}
101 
102 	log_debug("looking up %s (%s %d)", mlkup.dname, rr_type_name(mlkup.type),
103 	    mlkup.class);
104 
105 	/*
106 	 * Look for answers in our cache
107 	 */
108 	rr = cache_lookup(&mlkup);
109 	/* cache hit */
110 	if (rr != NULL) {
111 		if (control_send_rr(c, rr, IMSG_CTL_LOOKUP) == -1)
112 			log_warnx("query_answer error");
113 		return;
114 	}
115 
116 	if (question_add(&mlkup) == NULL) {
117 		log_warnx("Can't add question for %s (%s)", rrs_str(&mlkup));
118 		return;
119 	}
120 
121 	/* cache miss */
122 	if ((q = calloc(1, sizeof(*q))) == NULL)
123 		fatal("calloc");
124 	if ((rrs = calloc(1, sizeof(*rrs))) == NULL)
125 		fatal("calloc");
126 	LIST_INIT(&q->rrslist);
127 	q->style = QUERY_LOOKUP;
128 	q->ctl = c;
129 	*rrs = mlkup;
130 	LIST_INSERT_HEAD(&q->rrslist, rrs, entry);
131 	LIST_INSERT_HEAD(&c->qlist, q, entry);
132 	timerclear(&tv);
133 	tv.tv_usec = FIRST_QUERYTIME;
134 	evtimer_set(&q->timer, query_fsm, q);
135 	evtimer_add(&q->timer, &tv);
136 }
137 
138 void
control_browse_add(struct ctl_conn * c,struct imsg * imsg)139 control_browse_add(struct ctl_conn *c, struct imsg *imsg)
140 {
141 	struct rrset	 mlkup, *rrs;
142 	struct rr	*rr;
143 	struct query 	*q;
144 	struct timeval	 tv;
145 
146 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup))
147 		return;
148 
149 	memcpy(&mlkup, imsg->data, sizeof(mlkup));
150 	mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients were nice */
151 
152 	if (mlkup.type != T_PTR) {
153 		log_warnx("Browse type %d not supported/implemented",
154 		    mlkup.type);
155 		return;
156 	}
157 
158 	if (mlkup.class != C_IN) {
159 		log_warnx("Browse class %d not supported/implemented",
160 		    mlkup.class);
161 		return;
162 	}
163 
164 	/* Check if control has this query already, if so don't do anything */
165 	LIST_FOREACH(q, &c->qlist, entry) {
166 		if (q->style != QUERY_BROWSE)
167 			continue;
168 		if (rrset_cmp(q->br_ptr, &mlkup) == 0) {
169 			log_warnx("control already querying for %s",
170 			    rrs_str(q->br_ptr));
171 			return;
172 		}
173 	}
174 
175 	log_debug("Browse add %s (%s %d)", mlkup.dname, rr_type_name(mlkup.type),
176 	    mlkup.class);
177 
178 	/*
179 	 * Look for answers in our cache
180 	 */
181 	CACHE_FOREACH_RRS(rr, &mlkup) {
182 		if ((rr->flags & RR_FLAG_PUBLISHED) == 0)
183 			continue;
184 		if (control_send_rr(c, rr, IMSG_CTL_BROWSE_ADD) == -1)
185 			log_warnx("control_send_rr error 2");
186 	}
187 
188 	if (question_add(&mlkup) == NULL) {
189 		log_warnx("Can't add question for %s", rrs_str(&mlkup));
190 		return;
191 	}
192 
193 	if ((q = calloc(1, sizeof(*q))) == NULL)
194 		fatal("calloc");
195 	if ((rrs = calloc(1, sizeof(*rrs))) == NULL)
196 		fatal("calloc");
197 	*rrs = mlkup;
198 	LIST_INIT(&q->rrslist);
199 	q->style  = QUERY_BROWSE;
200 	q->ctl	  = c;
201 	q->br_ptr = rrs;
202 	LIST_INSERT_HEAD(&q->rrslist, rrs, entry);
203 	LIST_INSERT_HEAD(&c->qlist, q, entry);
204 	timerclear(&tv);
205 	tv.tv_usec = FIRST_QUERYTIME;
206 	evtimer_set(&q->timer, query_fsm, q);
207 	evtimer_add(&q->timer, &tv);
208 }
209 
210 void
control_browse_del(struct ctl_conn * c,struct imsg * imsg)211 control_browse_del(struct ctl_conn *c, struct imsg *imsg)
212 {
213 	struct rrset	 mlkup;
214 	struct query	*q;
215 
216 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup))
217 		return;
218 
219 	memcpy(&mlkup, imsg->data, sizeof(mlkup));
220 	mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients were nice */
221 
222 	if (mlkup.type != T_PTR) {
223 		log_warnx("Browse type %d not supported/implemented",
224 		    mlkup.type);
225 		return;
226 	}
227 
228 	if (mlkup.class != C_IN) {
229 		log_warnx("Browse class %d not supported/implemented",
230 		    mlkup.class);
231 		return;
232 	}
233 
234 	LIST_FOREACH(q, &c->qlist, entry) {
235 		if (q->style != QUERY_BROWSE)
236 			continue;
237 		if (rrset_cmp(q->br_ptr, &mlkup) != 0)
238 			continue;
239 		query_remove(q);
240 		return;
241 	}
242 
243 	log_warnx("Trying to remove non existant query");
244 }
245 
246 void
control_resolve(struct ctl_conn * c,struct imsg * imsg)247 control_resolve(struct ctl_conn *c, struct imsg *imsg)
248 {
249 	char			 msg[MAXHOSTNAMELEN];
250 	struct rrset		 *rrs_srv, *rrs_txt, *rrs_a, *rrs_aux;
251 	struct rr		*srv_cache;
252 	struct query		*q;
253 	struct timeval		 tv;
254 
255 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
256 		log_warnx("control_resolve: Invalid msg len");
257 		return;
258 	}
259 
260 	memcpy(msg, imsg->data, sizeof(msg));
261 	msg[sizeof(msg) - 1] = '\0';
262 
263 	/* Check if control has this query already, if so don't do anything */
264 	LIST_FOREACH(q, &c->qlist, entry) {
265 		if (q->style != QUERY_RESOLVE)
266 			continue;
267 		if (strcmp(msg, q->ms_srv->dname) == 0) {
268 			log_debug("control already resolving %s",
269 			    q->ms_srv->dname);
270 			return;
271 		}
272 	}
273 
274 	log_debug("Resolve %s", msg);
275 
276 	/*
277 	 * Try getting answer withing our cache entries
278 	 */
279 	if (control_try_answer_ms(c, msg) == 1) {
280 		log_debug("Resolve for %s all in cache", msg);
281 		return;
282 	}
283 
284 	/*
285 	 * If we got here we need to make a query.
286 	 */
287 	if ((q = calloc(1, sizeof(*q))) == NULL)
288 		fatal("calloc");
289 	LIST_INSERT_HEAD(&c->qlist, q, entry);
290 	LIST_INIT(&q->rrslist);
291 	q->style = QUERY_RESOLVE;
292 	q->ctl = c;
293 	timerclear(&tv);
294 	tv.tv_usec = FIRST_QUERYTIME;
295 	evtimer_set(&q->timer, query_fsm, q);
296 	evtimer_add(&q->timer, &tv);
297 
298 	if ((rrs_srv = calloc(1, sizeof(*rrs_srv))) == NULL)
299 		err(1, "calloc");
300 	if ((rrs_txt = calloc(1, sizeof(*rrs_txt))) == NULL)
301 		err(1, "calloc");
302 
303 	if (strlcpy(rrs_srv->dname, msg, sizeof(rrs_srv->dname)) >=
304 	    sizeof(rrs_srv->dname)) {
305 		log_warnx("control_resolve: msg too long, dropping");
306 		free(rrs_srv);
307 		free(rrs_txt);
308 		return;
309 	}
310 	rrs_srv->class = C_IN;
311 	rrs_srv->type  = T_SRV;
312 	strlcpy(rrs_txt->dname, msg, sizeof(rrs_txt->dname));
313 	rrs_txt->class = C_IN;
314 	rrs_txt->type = T_TXT;
315 	q->ms_srv = rrs_srv;
316 	LIST_INSERT_HEAD(&q->rrslist, rrs_srv, entry);
317 	LIST_INSERT_HEAD(&q->rrslist, rrs_txt, entry);
318 	if ((srv_cache = cache_lookup(rrs_srv)) != NULL) {
319 		if ((rrs_a = calloc(1, sizeof(*rrs_a))) == NULL)
320 			err(1, "calloc");
321 		strlcpy(rrs_a->dname, srv_cache->rdata.SRV.target,
322 		    sizeof(rrs_a->dname));
323 		rrs_a->class = C_IN;
324 		rrs_a->type = T_A;
325 		q->ms_a = rrs_a;
326 		LIST_INSERT_HEAD(&q->rrslist, rrs_a, entry);
327 	}
328 
329 	LIST_FOREACH(rrs_aux, &q->rrslist, entry) {
330 		if (question_add(rrs_aux) == NULL) {
331 			log_warnx("control_resolve: question_add error");
332 			query_remove(q);
333 			return;
334 		}
335 	}
336 }
337 
338 void
control_group_add(struct ctl_conn * c,struct imsg * imsg)339 control_group_add(struct ctl_conn *c, struct imsg *imsg)
340 {
341 	char		 msg[MAXHOSTNAMELEN];
342 
343 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
344 		log_warnx("control_group_add: Invalid group len");
345 		return;
346 	}
347 
348 	memcpy(msg, imsg->data, sizeof(msg));
349 	msg[sizeof(msg) - 1] = '\0';
350 	/*
351 	 * Check if the user hasn't already added this group, we'll issue an
352 	 * error when he commits.
353 	 */
354 	if (pg_get(0, msg, c) != NULL)
355 		return;
356 	/*
357 	 * Initialize group in temporary list, when user commits the group, we
358 	 * will process it all.
359 	 */
360 	(void)pg_get(1, msg, c);
361 }
362 
363 void
control_group_add_service(struct ctl_conn * c,struct imsg * imsg)364 control_group_add_service(struct ctl_conn *c, struct imsg *imsg)
365 {
366 	struct pg		*pg;
367 	struct pge		*pge;
368 	struct mdns_service	 msg, *ms;
369 
370 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
371 		log_warnx("control_group_add_service: Invalid group len");
372 		return;
373 	}
374 	memcpy(&msg, imsg->data, sizeof(msg));
375 	msg.name[sizeof(msg.name) - 1] = '\0';
376 	ms = &msg;
377 	/* Default to ourself if target hostname not provided  */
378 	if (strlen(ms->target) == 0)
379 		(void)strlcpy(ms->target, conf->myname, sizeof(ms->target));
380 
381 	/* Group not found, or not newgroup commited */
382 	pg = pg_get(0, ms->name, c);
383 	if (pg == NULL ||
384 	    (pg != NULL && pg->state != PG_STA_NEW)) {
385 		log_warnx("Controller trying to add service to invalid group");
386 		return;
387 	}
388 
389 	if ((pge = pge_from_ms(pg, ms, ALL_IFACE)) == NULL) {
390 		/* XXX assume collision */
391 		pg->state = PG_STA_COLLISION;
392 		return;
393 	}
394 }
395 
396 void
control_group_reset(struct ctl_conn * c,struct imsg * imsg)397 control_group_reset(struct ctl_conn *c, struct imsg *imsg)
398 {
399 	char		 msg[MAXHOSTNAMELEN];
400 	struct pg	*pg;
401 
402 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
403 		log_warnx("control_group_reset: Invalid group len");
404 		return;
405 	}
406 
407 	memcpy(msg, imsg->data, sizeof(msg));
408 	msg[sizeof(msg) - 1] = '\0';
409 
410 	if ((pg = pg_get(0, msg, NULL)) == NULL) {
411 		log_debug("control_group_reset: group %s not found",
412 		    msg);
413 		return;
414 	}
415 
416 	pg_kill(pg);
417 
418 	log_debug("group %s reseted", msg);
419 }
420 
421 /*
422  * XXX revise all this, we must have a flag in group if we had a collision when
423  * adding an entry.
424  */
425 void
control_group_commit(struct ctl_conn * c,struct imsg * imsg)426 control_group_commit(struct ctl_conn *c, struct imsg *imsg)
427 {
428 	char		 msg[MAXHOSTNAMELEN];
429 	struct pg	*pg;
430 	struct pge	*pge;
431 	struct timeval	 tv;
432 
433 	if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
434 		log_warnx("control_group_commit: Invalid group len");
435 		return;
436 	}
437 	memcpy(msg, imsg->data, sizeof(msg));
438 	msg[sizeof(msg) - 1] = '\0';
439 
440 	/* Check if we have the group under our control. */
441 	pg = pg_get(0, msg, c);
442 	if (pg == NULL) {
443 		/*
444 		 * If we don't, check if someone else does, if yes, we
445 		 * probabably failed adding some service due to a collision, so
446 		 * guess this is a collision :-), yes this is disgusting, will
447 		 * fix it someday.
448 		 */
449 		TAILQ_FOREACH(pg, &pg_queue, entry) {
450 			if (strcmp(pg->name, msg) != 0)
451 				continue;
452 			control_notify_pg(c, pg,
453 			    IMSG_CTL_GROUP_ERR_COLLISION);
454 			return;
455 		}
456 
457 		control_notify_pg(c, pg,
458 		    IMSG_CTL_GROUP_ERR_NOT_FOUND);
459 		return;
460 	}
461 
462 	/* Check if we got a collision */
463 	if (pg->state == PG_STA_COLLISION) {
464 		control_notify_pg(pg->c, pg,
465 		    IMSG_CTL_GROUP_ERR_COLLISION);
466 		pg_kill(pg);
467 		return;
468 	}
469 
470 	/* Mark we got a commit */
471 	pg->state = PG_STA_COMMITED;
472 
473 	timerclear(&tv);
474 	tv.tv_usec = RANDOM_PROBETIME;
475 	LIST_FOREACH(pge, &pg->pge_list, pge_entry) {
476 		pge_fsm_restart(pge, &tv);
477 	}
478 }
479 
480 int
control_init(void)481 control_init(void)
482 {
483 	struct sockaddr_un	 sun;
484 	int			 fd;
485 	mode_t			 old_umask;
486 
487 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
488 		log_warn("control_init: socket");
489 		return (-1);
490 	}
491 
492 	bzero(&sun, sizeof(sun));
493 	sun.sun_family = AF_UNIX;
494 	strlcpy(sun.sun_path, MDNSD_SOCKET, sizeof(sun.sun_path));
495 
496 	if (unlink(MDNSD_SOCKET) == -1)
497 		if (errno != ENOENT) {
498 			log_warn("control_init: unlink %s", MDNSD_SOCKET);
499 			close(fd);
500 			return (-1);
501 		}
502 
503 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
504 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
505 		log_warn("control_init: bind: %s", MDNSD_SOCKET);
506 		close(fd);
507 		umask(old_umask);
508 		return (-1);
509 	}
510 	umask(old_umask);
511 
512 	if (chmod(MDNSD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
513 		log_warn("control_init: chmod");
514 		close(fd);
515 		(void)unlink(MDNSD_SOCKET);
516 		return (-1);
517 	}
518 
519 	session_socket_blockmode(fd, BM_NONBLOCK);
520 	control_state.fd = fd;
521 
522 	return (0);
523 }
524 
525 int
control_listen(void)526 control_listen(void)
527 {
528 
529 	if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
530 		log_warn("control_listen: listen");
531 		return (-1);
532 	}
533 
534 	event_set(&control_state.ev, control_state.fd, EV_READ | EV_PERSIST,
535 	    control_accept, NULL);
536 	event_add(&control_state.ev, NULL);
537 
538 	return (0);
539 }
540 
541 void
control_cleanup(void)542 control_cleanup(void)
543 {
544 	unlink(MDNSD_SOCKET);
545 }
546 
547 void
control_accept(int listenfd,short event,void * bula)548 control_accept(int listenfd, short event, void *bula)
549 {
550 	int			 connfd;
551 	socklen_t		 len;
552 	struct sockaddr_un	 sun;
553 	struct ctl_conn		*c;
554 
555 	len = sizeof(sun);
556 	if ((connfd = accept(listenfd,
557 	    (struct sockaddr *)&sun, &len)) == -1) {
558 		if (errno != EWOULDBLOCK && errno != EINTR)
559 			log_warn("control_accept: accept");
560 		return;
561 	}
562 
563 	session_socket_blockmode(connfd, BM_NONBLOCK);
564 
565 	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
566 		log_warn("control_accept");
567 		close(connfd);
568 		return;
569 	}
570 
571 	LIST_INIT(&c->qlist);
572 	imsg_init(&c->iev.ibuf, connfd);
573 	c->iev.handler = control_dispatch_imsg;
574 	c->iev.events = EV_READ;
575 	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
576 	    c->iev.handler, &c->iev);
577 	event_add(&c->iev.ev, NULL);
578 
579 	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
580 }
581 
582 struct ctl_conn *
control_connbyfd(int fd)583 control_connbyfd(int fd)
584 {
585 	struct ctl_conn	*c;
586 
587 	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
588 	     c = TAILQ_NEXT(c, entry))
589 		;	/* nothing */
590 
591 	return (c);
592 }
593 
594 struct ctl_conn *
control_connbypid(pid_t pid)595 control_connbypid(pid_t pid)
596 {
597 	struct ctl_conn	*c;
598 
599 	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid;
600 	     c = TAILQ_NEXT(c, entry))
601 		;	/* nothing */
602 
603 	return (c);
604 }
605 
606 void
control_close(int fd)607 control_close(int fd)
608 {
609 	struct ctl_conn	*c;
610 	struct query	*q;
611 	struct pg	*pg, *pg_next;
612 
613 	if ((c = control_connbyfd(fd)) == NULL) {
614 		log_warn("control_close: fd %d: not found", fd);
615 		return;
616 	}
617 	msgbuf_clear(&c->iev.ibuf.w);
618 	TAILQ_REMOVE(&ctl_conns, c, entry);
619 
620 	event_del(&c->iev.ev);
621 	close(c->iev.ibuf.fd);
622 	while ((q = LIST_FIRST(&c->qlist)) != NULL)
623 		query_remove(q);
624 	/*
625 	 * Clean up all groups belonging to this controller
626 	 */
627 	for (pg = TAILQ_FIRST(&pg_queue); pg != NULL;
628 	     pg = pg_next) {
629 		pg_next = TAILQ_NEXT(pg, entry);
630 		if (pg->c == c)
631 			pg_kill(pg);
632 	}
633 	free(c);
634 }
635 
636 void
control_dispatch_imsg(int fd,short event,void * bula)637 control_dispatch_imsg(int fd, short event, void *bula)
638 {
639 	struct ctl_conn	*c;
640 	struct imsg	 imsg;
641 	ssize_t		 n;
642 
643 	if ((c = control_connbyfd(fd)) == NULL) {
644 		log_warn("control_dispatch_imsg: fd %d: not found", fd);
645 		return;
646 	}
647 
648 	if (event & EV_READ) {
649 		if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) {
650 			control_close(fd);
651 			return;
652 		}
653 	}
654 	if (event & EV_WRITE) {
655 		if (msgbuf_write(&c->iev.ibuf.w) == -1) {
656 			control_close(fd);
657 			return;
658 		}
659 	}
660 
661 	for (;;) {
662 		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
663 			control_close(fd);
664 			return;
665 		}
666 
667 		if (n == 0)
668 			break;
669 
670 		switch (imsg.hdr.type) {
671 		case IMSG_CTL_LOOKUP:
672 			control_lookup(c, &imsg);
673 			break;
674 		case IMSG_CTL_BROWSE_ADD:
675 			control_browse_add(c, &imsg);
676 			break;
677 		case IMSG_CTL_BROWSE_DEL:
678 			control_browse_del(c, &imsg);
679 			break;
680 		case IMSG_CTL_RESOLVE:
681 			control_resolve(c, &imsg);
682 			break;
683 		case IMSG_CTL_GROUP_ADD:
684 			control_group_add(c, &imsg);
685 			break;
686 		case IMSG_CTL_GROUP_RESET:
687 			control_group_reset(c, &imsg);
688 			break;
689 		case IMSG_CTL_GROUP_COMMIT:
690 			control_group_commit(c, &imsg);
691 			break;
692 		case IMSG_CTL_GROUP_ADD_SERVICE:
693 			control_group_add_service(c, &imsg);
694 			break;
695 		default:
696 			log_debug("control_dispatch_imsg: "
697 			    "error handling imsg %d", imsg.hdr.type);
698 			break;
699 		}
700 		imsg_free(&imsg);
701 	}
702 
703 	imsg_event_add(&c->iev);
704 }
705 
706 void
session_socket_blockmode(int fd,enum blockmodes bm)707 session_socket_blockmode(int fd, enum blockmodes bm)
708 {
709 	int	flags;
710 
711 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
712 		fatal("fcntl F_GETFL");
713 
714 	if (bm == BM_NONBLOCK)
715 		flags |= O_NONBLOCK;
716 	else
717 		flags &= ~O_NONBLOCK;
718 
719 	if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
720 		fatal("fcntl F_SETFL");
721 }
722 
723 int
control_send_rr(struct ctl_conn * c,struct rr * rr,int msgtype)724 control_send_rr(struct ctl_conn *c, struct rr *rr, int msgtype)
725 {
726 	int r;
727 	int inaddrany = RR_INADDRANY(rr);
728 
729 	log_debug("control_send_rr (%s) %s", rr_type_name(rr->rrs.type),
730 	    rr->rrs.dname);
731 
732 	/* Patch up T_A with the first interface address */
733 	if (inaddrany)
734 		rr->rdata.A.s_addr = LIST_FIRST(&conf->iface_list)->addr.s_addr;
735 	r = mdnsd_imsg_compose_ctl(c, msgtype, rr, sizeof(*rr));
736 	if (inaddrany)
737 		rr->rdata.A.s_addr = INADDR_ANY;
738 
739 	return (r);
740 }
741 
742 int
control_send_ms(struct ctl_conn * c,struct mdns_service * ms,int msgtype)743 control_send_ms(struct ctl_conn *c, struct mdns_service *ms, int msgtype)
744 {
745 	log_debug("control_send_ms %s", ms->name);
746 
747 	return (mdnsd_imsg_compose_ctl(c, msgtype, ms, sizeof(*ms)));
748 }
749 
750 /*
751  * 1 = Success, 0 = Fail
752  */
753 int
control_try_answer_ms(struct ctl_conn * c,char dname[MAXHOSTNAMELEN])754 control_try_answer_ms(struct ctl_conn *c, char dname[MAXHOSTNAMELEN])
755 {
756 	struct rr *srv, *txt, *a;
757 	struct rrset rrs;
758 	struct mdns_service ms;
759 
760 	srv = txt = a = NULL;
761 
762 	/*
763 	 * Look for answers in our cache
764 	 */
765 	log_debug("control_try_answer_ms %s", dname);
766 	strlcpy(rrs.dname, dname, sizeof(rrs.dname));
767 	rrs.class = C_IN;
768 	rrs.type = T_SRV;
769 	if ((srv = cache_lookup(&rrs)) == NULL)
770 		return (0);
771 	rrs.type = T_TXT;
772 	if ((txt = cache_lookup(&rrs)) == NULL)
773 		return (0);
774 	strlcpy(rrs.dname, srv->rdata.SRV.target, sizeof(rrs.dname));
775 	rrs.type = T_A;
776 	if ((a = cache_lookup(&rrs)) == NULL)
777 		return (0);
778 
779 	bzero(&ms, sizeof(ms));
780 	strlcpy(ms.name, srv->rrs.dname, sizeof(ms.name));
781 	strlcpy(ms.target, rrs.dname, sizeof(ms.target));
782 	strlcpy(ms.txt, txt->rdata.TXT, sizeof(ms.txt));
783 	ms.priority = srv->rdata.SRV.priority;
784 	ms.weight = srv->rdata.SRV.weight;
785 	ms.port = srv->rdata.SRV.port;
786 	/* Patch up T_A with the first interface address */
787 	if (RR_INADDRANY(a))
788 		ms.addr = LIST_FIRST(&conf->iface_list)->addr;
789 	else
790 		ms.addr = a->rdata.A;
791 	if (control_send_ms(c, &ms, IMSG_CTL_RESOLVE) == -1)
792 		log_warnx("control_send_ms error");
793 
794 	return (1);
795 }
796 
797 int
control_notify_pg(struct ctl_conn * c,struct pg * pg,int msgtype)798 control_notify_pg(struct ctl_conn *c, struct pg *pg, int msgtype)
799 {
800 	log_debug("control_notify_pg %s msg %d", pg->name, msgtype);
801 
802 	if (c == NULL) {
803 		log_warnx("Calling control_notify_pg() with NULL !");
804 		return (-1);
805 	}
806 
807 	return (mdnsd_imsg_compose_ctl(c, msgtype, pg->name,
808 	    sizeof(pg->name)));
809 }
810