1 /*
2  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
3  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
4  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/time.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <net/if.h>
26 #include <net/if_types.h>
27 #include <ctype.h>
28 #include <err.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <event.h>
34 
35 #include "mdnsd.h"
36 #include "log.h"
37 
38 extern struct mdnsd_conf *conf;
39 
40 int	 if_act_start(struct iface *);
41 int	 if_act_reset(struct iface *);
42 
43 struct {
44 	int			state;
45 	enum iface_event	event;
46 	enum iface_action	action;
47 	int			new_state;
48 } iface_fsm[] = {
49     /* current state	event that happened	action to take	resulting state */
50     {IF_STA_DOWN,	IF_EVT_UP,		IF_ACT_STRT,	0},
51     {IF_STA_ANY,	IF_EVT_DOWN,		IF_ACT_RST,	IF_STA_DOWN},
52     {-1,		IF_EVT_NOTHING,		IF_ACT_NOTHING,	0},
53 };
54 
55 const char * const if_action_names[] = {
56 	"NOTHING",
57 	"START",
58 	"RESET"
59 };
60 
61 const char * const if_event_names[] = {
62 	"NOTHING",
63 	"UP",
64 	"DOWN",
65 };
66 
67 int
if_fsm(struct iface * iface,enum iface_event event)68 if_fsm(struct iface *iface, enum iface_event event)
69 {
70 	int	 old_state;
71 	int	 new_state = 0;
72 	int	 i, ret = 0;
73 
74 	old_state = iface->state;
75 
76 	for (i = 0; iface_fsm[i].state != -1; i++)
77 		if ((iface_fsm[i].state & old_state) &&
78 		    (iface_fsm[i].event == event)) {
79 			new_state = iface_fsm[i].new_state;
80 			break;
81 		}
82 
83 	if (iface_fsm[i].state == -1) {
84 		/* event outside of the defined fsm, ignore it. */
85 		log_debug("if_fsm: interface %s, "
86 		    "event '%s' not expected in state '%s'", iface->name,
87 		    if_event_name(event), if_state_name(old_state));
88 		return (0);
89 	}
90 
91 	switch (iface_fsm[i].action) {
92 	case IF_ACT_STRT:
93 		ret = if_act_start(iface);
94 		break;
95 	case IF_ACT_RST:
96 		ret = if_act_reset(iface);
97 		break;
98 	case IF_ACT_NOTHING:
99 		/* do nothing */
100 		break;
101 	}
102 
103 	if (ret) {
104 		log_debug("if_fsm: error changing state for interface %s, "
105 		    "event '%s', state '%s'", iface->name, if_event_name(event),
106 		    if_state_name(old_state));
107 		return (0);
108 	}
109 
110 	if (new_state != 0)
111 		iface->state = new_state;
112 
113 	log_debug("if_fsm: event '%s' resulted in action '%s' and changing "
114 	    "state for interface %s from '%s' to '%s'",
115 	    if_event_name(event), if_action_name(iface_fsm[i].action),
116 	    iface->name, if_state_name(old_state), if_state_name(iface->state));
117 
118 	return (ret);
119 }
120 
121 struct iface *
if_find_index(u_short ifindex)122 if_find_index(u_short ifindex)
123 {
124 	struct iface	 *iface;
125 
126 	LIST_FOREACH(iface, &conf->iface_list, entry) {
127 		if (iface->ifindex == ifindex)
128 			return (iface);
129 	}
130 
131 	return (NULL);
132 }
133 
134 struct iface *
if_find_iface(unsigned int ifindex,struct in_addr src)135 if_find_iface(unsigned int ifindex, struct in_addr src)
136 {
137 	struct iface	*iface = NULL;
138 
139 	/* returned interface needs to be active */
140 	LIST_FOREACH(iface, &conf->iface_list, entry) {
141 		if (ifindex != 0 && ifindex == iface->ifindex &&
142 		    (iface->addr.s_addr & iface->mask.s_addr) ==
143 		    (src.s_addr & iface->mask.s_addr))
144 			/*
145 			 * XXX may fail on P2P links because src and dst don't
146 			 * have to share a common subnet on the otherhand
147 			 * checking something like this will help to support
148 			 * multiple networks configured on one interface.
149 			 */
150 			return (iface);
151 	}
152 
153 	return (NULL);
154 }
155 
156 /* actions */
157 int
if_act_start(struct iface * iface)158 if_act_start(struct iface *iface)
159 {
160 	struct in_addr	 addr;
161 	struct timeval	 now;
162 
163 	if (!((iface->flags & IFF_UP) &&
164 	    (LINK_STATE_IS_UP(iface->linkstate) ||
165 	    (iface->linkstate == LINK_STATE_UNKNOWN &&
166 	    iface->media_type != IFT_CARP)))) {
167 		log_debug("if_act_start: interface %s link down",
168 		    iface->name);
169 		return (0);
170 	}
171 
172 	gettimeofday(&now, NULL);
173 	iface->uptime = now.tv_sec;
174 
175 	switch (iface->type) {
176 	case IF_TYPE_POINTOPOINT:
177 	case IF_TYPE_BROADCAST:
178 		inet_aton(ALL_MDNS_DEVICES, &addr);
179 		if (if_join_group(iface, &addr)) {
180 			log_warn("if_act_start: error joining group %s, "
181 			    "interface %s", inet_ntoa(addr), iface->name);
182 			return (-1);
183 		}
184 
185 		iface->state = IF_STA_ACTIVE;
186 		break;
187 	default:
188 		fatalx("if_act_start: unknown interface type");
189 	}
190 
191 	/* publish all groups on this interface */
192 	pg_publish_byiface(iface);
193 
194 	return (0);
195 }
196 
197 int
if_act_reset(struct iface * iface)198 if_act_reset(struct iface *iface)
199 {
200 	struct in_addr		 addr;
201 
202 	switch (iface->type) {
203 	case IF_TYPE_POINTOPOINT:
204 	case IF_TYPE_BROADCAST:
205 		inet_aton(ALL_MDNS_DEVICES, &addr);
206 		if (if_leave_group(iface, &addr)) {
207 			log_warn("if_act_reset: error leaving group %s, "
208 			    "interface %s", inet_ntoa(addr), iface->name);
209 		}
210 		break;
211 	default:
212 		fatalx("if_act_reset: unknown interface type");
213 	}
214 
215 	return (0);
216 }
217 
218 const char *
if_event_name(int event)219 if_event_name(int event)
220 {
221 	return (if_event_names[event]);
222 }
223 
224 const char *
if_action_name(int action)225 if_action_name(int action)
226 {
227 	return (if_action_names[action]);
228 }
229 
230 /* misc */
231 int
if_set_mcast_ttl(int fd,u_int8_t ttl)232 if_set_mcast_ttl(int fd, u_int8_t ttl)
233 {
234 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
235 	    (char *)&ttl, sizeof(ttl)) < 0) {
236 		log_warn("if_set_mcast_ttl: error setting "
237 		    "IP_MULTICAST_TTL to %d", ttl);
238 		return (-1);
239 	}
240 
241 	return (0);
242 }
243 
244 int
if_set_opt(int fd)245 if_set_opt(int fd)
246 {
247 	int	 yes = 1;
248 
249 	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &yes,
250 	    sizeof(int)) < 0) {
251 		log_warn("if_set_opt: error setting IP_RECVIF");
252 		return (-1);
253 	}
254 
255 	if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &yes,
256 	    sizeof(int)) < 0) {
257 		log_warn("if_set_opt: error setting IP_RECVDSTADDR");
258 		return (-1);
259 	}
260 
261 	return (0);
262 }
263 
264 int
if_set_tos(int fd,int tos)265 if_set_tos(int fd, int tos)
266 {
267 	if (setsockopt(fd, IPPROTO_IP, IP_TOS,
268 	    (int *)&tos, sizeof(tos)) < 0) {
269 		log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos);
270 		return (-1);
271 	}
272 
273 	return (0);
274 }
275 
276 int
if_set_mcast(struct iface * iface)277 if_set_mcast(struct iface *iface)
278 {
279 	switch (iface->type) {
280 	case IF_TYPE_POINTOPOINT:
281 	case IF_TYPE_BROADCAST:
282 		if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
283 		    &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) {
284 			log_debug("if_set_mcast: error setting "
285 				"IP_MULTICAST_IF, interface %s", iface->name);
286 			return (-1);
287 		}
288 		break;
289 	default:
290 		fatalx("if_set_mcast: unknown interface type");
291 	}
292 
293 	return (0);
294 }
295 
296 int
if_set_mcast_loop(int fd)297 if_set_mcast_loop(int fd)
298 {
299 	u_int8_t	 loop = 0;
300 
301 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
302 	    (char *)&loop, sizeof(loop)) < 0) {
303 		log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
304 		return (-1);
305 	}
306 
307 	return (0);
308 }
309 
310 void
if_set_recvbuf(int fd)311 if_set_recvbuf(int fd)
312 {
313 	int	 bsize;
314 
315 	bsize = 65535;
316 	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
317 	    sizeof(bsize)) == -1)
318 		bsize /= 2;
319 }
320 
321 int
if_join_group(struct iface * iface,struct in_addr * addr)322 if_join_group(struct iface *iface, struct in_addr *addr)
323 {
324 	struct ip_mreq	 mreq;
325 
326 	switch (iface->type) {
327 	case IF_TYPE_POINTOPOINT:
328 	case IF_TYPE_BROADCAST:
329 		mreq.imr_multiaddr.s_addr = addr->s_addr;
330 		mreq.imr_interface.s_addr = iface->addr.s_addr;
331 
332 		if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
333 		    (void *)&mreq, sizeof(mreq)) < 0)
334 			return (-1);
335 		break;
336 	default:
337 		fatalx("if_join_group: unknown interface type");
338 	}
339 
340 	return (0);
341 }
342 
343 int
if_leave_group(struct iface * iface,struct in_addr * addr)344 if_leave_group(struct iface *iface, struct in_addr *addr)
345 {
346 	struct ip_mreq	 mreq;
347 
348 	switch (iface->type) {
349 	case IF_TYPE_POINTOPOINT:
350 	case IF_TYPE_BROADCAST:
351 		mreq.imr_multiaddr.s_addr = addr->s_addr;
352 		mreq.imr_interface.s_addr = iface->addr.s_addr;
353 
354 		if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
355 		    (void *)&mreq, sizeof(mreq)) < 0)
356 			return (-1);
357 		break;
358 	default:
359 		fatalx("if_leave_group: unknown interface type");
360 	}
361 
362 	return (0);
363 }
364 
365 struct iface *
if_new(struct kif * kif)366 if_new(struct kif *kif)
367 {
368 	struct sockaddr_in	*sain;
369 	struct iface		*iface;
370 	struct ifreq		*ifr;
371 	int			s;
372 	int succeed = 0;
373 
374 	if ((iface = calloc(1, sizeof(*iface))) == NULL)
375 		err(1, "if_new: calloc");
376 
377 	iface->state = IF_STA_DOWN;
378 
379 	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
380 
381 	if ((ifr = calloc(1, sizeof(*ifr))) == NULL)
382 		err(1, "if_new: calloc");
383 
384 	/* set up ifreq */
385 	strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name));
386 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
387 		err(1, "if_new: socket");
388 
389 	/* get type */
390 	if (kif->flags & IFF_POINTOPOINT)
391 		iface->type = IF_TYPE_POINTOPOINT;
392 	if (kif->flags & IFF_BROADCAST &&
393 	    kif->flags & IFF_MULTICAST)
394 		iface->type = IF_TYPE_BROADCAST;
395 	if (kif->flags & IFF_LOOPBACK) {
396 		iface->type = IF_TYPE_POINTOPOINT;
397 		/* XXX protect loopback from sending packets over lo? */
398 	}
399 
400 	/* get mtu, index and flags */
401 	iface->mtu = kif->mtu;
402 	iface->ifindex = kif->ifindex;
403 	iface->flags = kif->flags;
404 	iface->linkstate = kif->link_state;
405 	iface->media_type = kif->media_type;
406 	iface->baudrate = kif->baudrate;
407 	iface->ea = kif->ea;
408 
409 	/* get address */
410 	if (ioctl(s, SIOCGIFADDR, ifr) < 0) {
411 		log_warn("if_new: cannot get address");
412 		goto end;
413 	}
414 	sain = (struct sockaddr_in *)&ifr->ifr_addr;
415 	iface->addr = sain->sin_addr;
416 
417 	/* get mask */
418 	if (ioctl(s, SIOCGIFNETMASK, ifr) < 0) {
419 		log_warn("if_new: cannot get mask");
420 		goto end;
421 	}
422 	sain = (struct sockaddr_in *)&ifr->ifr_addr;
423 	iface->mask = sain->sin_addr;
424 
425 	/* get p2p dst address */
426 	if (kif->flags & IFF_POINTOPOINT) {
427 		if (ioctl(s, SIOCGIFDSTADDR, ifr) < 0) {
428 			log_warn("if_new: cannot get dst addr");
429 			goto end;
430 		}
431 		sain = (struct sockaddr_in *)&ifr->ifr_addr;
432 		iface->dst = sain->sin_addr;
433 	}
434 
435 	/* get the primary group for this interface */
436 	if (conf->no_workstation == 0)
437 		iface->pge_workstation = pge_new_workstation(iface);
438 
439 	succeed = 1;
440 
441 end:
442 	if (!succeed) {
443 		free(iface);
444 		iface = NULL;
445 	}
446 
447 	free(ifr);
448 	close(s);
449 
450 	return (iface);
451 }
452