xref: /openbsd/usr.sbin/mrouted/rsrr.c (revision 404b540a)
1 /*	$OpenBSD: rsrr.c,v 1.10 2004/08/01 18:32:19 deraadt Exp $	*/
2 /*	$NetBSD: rsrr.c,v 1.3 1995/12/10 10:07:14 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1993, 1998-2001.
6  * The University of Southern California/Information Sciences Institute.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
35  * April 1995.
36  */
37 
38 /* May 1995 -- Added support for Route Change Notification */
39 
40 #ifdef RSRR
41 
42 #include "defs.h"
43 #include <sys/param.h>
44 #if (defined(BSD) && (BSD >= 199103))
45 #include <stddef.h>
46 #endif
47 
48 /* Taken from prune.c */
49 /*
50  * checks for scoped multicast addresses
51  */
52 #define GET_SCOPE(gt) { \
53 	register int _i; \
54 	if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \
55 	    for (_i = 0; _i < numvifs; _i++) \
56 		if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
57 		    VIFM_SET(_i, (gt)->gt_scope); \
58 	}
59 
60 /*
61  * Exported variables.
62  */
63 int rsrr_socket;			/* interface to reservation protocol */
64 
65 /*
66  * Global RSRR variables.
67  */
68 char rsrr_recv_buf[RSRR_MAX_LEN];	/* RSRR receive buffer */
69 char rsrr_send_buf[RSRR_MAX_LEN];	/* RSRR send buffer */
70 
71 struct sockaddr_un client_addr;
72 int client_length = sizeof(client_addr);
73 
74 
75 /*
76  * Procedure definitions needed internally.
77  */
78 static void	rsrr_accept(int recvlen);
79 static void	rsrr_accept_iq(void);
80 static int	rsrr_accept_rq(struct rsrr_rq *route_query, int flags,
81 		    struct gtable *gt_notify);
82 static int	rsrr_send(int sendlen);
83 static void	rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query);
84 
85 /* Initialize RSRR socket */
86 void
87 rsrr_init(void)
88 {
89     int servlen;
90     struct sockaddr_un serv_addr;
91 
92     if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
93 	logit(LOG_ERR, errno, "Can't create RSRR socket");
94 
95     unlink(RSRR_SERV_PATH);
96     bzero((char *) &serv_addr, sizeof(serv_addr));
97     serv_addr.sun_family = AF_UNIX;
98     strlcpy(serv_addr.sun_path, RSRR_SERV_PATH, sizeof serv_addr.sun_path);
99 #if (defined(BSD) && (BSD >= 199103))
100     servlen = offsetof(struct sockaddr_un, sun_path) +
101 		strlen(serv_addr.sun_path);
102     serv_addr.sun_len = servlen;
103 #else
104     servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
105 #endif
106 
107     if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
108 	logit(LOG_ERR, errno, "Can't bind RSRR socket");
109 
110     if (register_input_handler(rsrr_socket,rsrr_read) < 0)
111 	logit(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
112 }
113 
114 /* Read a message from the RSRR socket */
115 void
116 rsrr_read(int f, fd_set *rfd)
117 {
118     int rsrr_recvlen;
119     sigset_t mask, omask;
120 
121     bzero((char *) &client_addr, sizeof(client_addr));
122     rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
123 			    0, (struct sockaddr *)&client_addr, &client_length);
124     if (rsrr_recvlen < 0) {
125 	if (errno != EINTR)
126 	    logit(LOG_ERR, errno, "RSRR recvfrom");
127 	return;
128     }
129     /* Use of omask taken from main() */
130     sigemptyset(&mask);
131     sigaddset(&mask, SIGALRM);
132     sigprocmask(SIG_BLOCK, &mask, &omask);
133     rsrr_accept(rsrr_recvlen);
134     sigprocmask(SIG_SETMASK, &omask, NULL);
135 }
136 
137 /* Accept a message from the reservation protocol and take
138  * appropriate action.
139  */
140 static void
141 rsrr_accept(int recvlen)
142 {
143     struct rsrr_header *rsrr;
144     struct rsrr_rq *route_query;
145 
146     if (recvlen < RSRR_HEADER_LEN) {
147 	logit(LOG_WARNING, 0,
148 	    "Received RSRR packet of %d bytes, which is less than min size",
149 	    recvlen);
150 	return;
151     }
152 
153     rsrr = (struct rsrr_header *) rsrr_recv_buf;
154 
155     if (rsrr->version > RSRR_MAX_VERSION) {
156 	logit(LOG_WARNING, 0,
157 	    "Received RSRR packet version %d, which I don't understand",
158 	    rsrr->version);
159 	return;
160     }
161 
162     switch (rsrr->version) {
163       case 1:
164 	switch (rsrr->type) {
165 	  case RSRR_INITIAL_QUERY:
166 	    /* Send Initial Reply to client */
167 	    logit(LOG_INFO, 0, "Received Initial Query\n");
168 	    rsrr_accept_iq();
169 	    break;
170 	  case RSRR_ROUTE_QUERY:
171 	    /* Check size */
172 	    if (recvlen < RSRR_RQ_LEN) {
173 		logit(LOG_WARNING, 0,
174 		    "Received Route Query of %d bytes, which is too small",
175 		    recvlen);
176 		break;
177 	    }
178 	    /* Get the query */
179 	    route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
180 	    logit(LOG_INFO, 0,
181 		"Received Route Query for src %s grp %s notification %d",
182 		inet_fmt(route_query->source_addr.s_addr, s1),
183 		inet_fmt(route_query->dest_addr.s_addr,s2),
184 		BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
185 	    /* Send Route Reply to client */
186 	    rsrr_accept_rq(route_query,rsrr->flags,NULL);
187 	    break;
188 	  default:
189 	    logit(LOG_WARNING, 0,
190 		"Received RSRR packet type %d, which I don't handle",
191 		rsrr->type);
192 	    break;
193 	}
194 	break;
195 
196       default:
197 	logit(LOG_WARNING, 0,
198 	    "Received RSRR packet version %d, which I don't understand",
199 	    rsrr->version);
200 	break;
201     }
202 }
203 
204 /* Send an Initial Reply to the reservation protocol. */
205 static void
206 rsrr_accept_iq(void)
207 {
208     struct rsrr_header *rsrr;
209     struct rsrr_vif *vif_list;
210     struct uvif *v;
211     int vifi, sendlen;
212 
213     /* Check for space.  There should be room for plenty of vifs,
214      * but we should check anyway.
215      */
216     if (numvifs > RSRR_MAX_VIFS) {
217 	logit(LOG_WARNING, 0,
218 	    "Can't send RSRR Route Reply because %d is too many vifs %d",
219 	    numvifs);
220 	return;
221     }
222 
223     /* Set up message */
224     rsrr = (struct rsrr_header *) rsrr_send_buf;
225     rsrr->version = 1;
226     rsrr->type = RSRR_INITIAL_REPLY;
227     rsrr->flags = 0;
228     rsrr->num = numvifs;
229 
230     vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
231 
232     /* Include the vif list. */
233     for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
234 	vif_list[vifi].id = vifi;
235 	vif_list[vifi].status = 0;
236 	if (v->uv_flags & VIFF_DISABLED)
237 	    BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
238 	vif_list[vifi].threshold = v->uv_threshold;
239 	vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
240     }
241 
242     /* Get the size. */
243     sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
244 
245     /* Send it. */
246     logit(LOG_INFO, 0, "Send RSRR Initial Reply");
247     rsrr_send(sendlen);
248 }
249 
250 /* Send a Route Reply to the reservation protocol.  The Route Query
251  * contains the query to which we are responding.  The flags contain
252  * the incoming flags from the query or, for route change
253  * notification, the flags that should be set for the reply.  The
254  * kernel table entry contains the routing info to use for a route
255  * change notification.
256  */
257 static int
258 rsrr_accept_rq(struct rsrr_rq *route_query, int flags, struct gtable *gt_notify)
259 {
260     struct rsrr_header *rsrr;
261     struct rsrr_rr *route_reply;
262     struct gtable *gt,local_g;
263     struct rtentry *r;
264     int sendlen,i;
265     u_long mcastgrp;
266 
267     /* Set up message */
268     rsrr = (struct rsrr_header *) rsrr_send_buf;
269     rsrr->version = 1;
270     rsrr->type = RSRR_ROUTE_REPLY;
271     rsrr->flags = 0;
272     rsrr->num = 0;
273 
274     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
275     route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
276     route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
277     route_reply->query_id = route_query->query_id;
278 
279     /* Blank routing entry for error. */
280     route_reply->in_vif = 0;
281     route_reply->reserved = 0;
282     route_reply->out_vif_bm = 0;
283 
284     /* Get the size. */
285     sendlen = RSRR_RR_LEN;
286 
287     /* If kernel table entry is defined, then we are sending a Route Reply
288      * due to a Route Change Notification event.  Use the kernel table entry
289      * to supply the routing info.
290      */
291     if (gt_notify) {
292 	/* Set flags */
293 	rsrr->flags = flags;
294 	/* Include the routing entry. */
295 	route_reply->in_vif = gt_notify->gt_route->rt_parent;
296 	route_reply->out_vif_bm = gt_notify->gt_grpmems;
297 
298     } else if (find_src_grp(route_query->source_addr.s_addr, 0,
299 			    route_query->dest_addr.s_addr)) {
300 
301 	/* Found kernel entry. Code taken from add_table_entry() */
302 	gt = gtp ? gtp->gt_gnext : kernel_table;
303 
304 	/* Include the routing entry. */
305 	route_reply->in_vif = gt->gt_route->rt_parent;
306 	route_reply->out_vif_bm = gt->gt_grpmems;
307 
308 	/* Cache reply if using route change notification. */
309 	if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
310 	    rsrr_cache(gt,route_query);
311 	    BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
312 	}
313 
314     } else {
315 	/* No kernel entry; use routing table. */
316 	r = determine_route(route_query->source_addr.s_addr);
317 
318 	if (r != NULL) {
319 	    /* We need to mimic what will happen if a data packet
320 	     * is forwarded by multicast routing -- the kernel will
321 	     * make an upcall and mrouted will install a route in the kernel.
322 	     * Our outgoing vif bitmap should reflect what that table
323 	     * will look like.  Grab code from add_table_entry().
324 	     * This is gross, but it's probably better to be accurate.
325 	     */
326 
327 	    gt = &local_g;
328 	    mcastgrp = route_query->dest_addr.s_addr;
329 
330 	    gt->gt_mcastgrp	= mcastgrp;
331 	    gt->gt_grpmems	= 0;
332 	    gt->gt_scope	= 0;
333 	    gt->gt_route        = r;
334 
335 	    /* obtain the multicast group membership list */
336 	    for (i = 0; i < numvifs; i++) {
337 		if (VIFM_ISSET(i, r->rt_children) &&
338 		    !(VIFM_ISSET(i, r->rt_leaves)))
339 		    VIFM_SET(i, gt->gt_grpmems);
340 
341 		if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
342 		    VIFM_SET(i, gt->gt_grpmems);
343 	    }
344 
345 	    GET_SCOPE(gt);
346 	    gt->gt_grpmems &= ~gt->gt_scope;
347 
348 	    /* Include the routing entry. */
349 	    route_reply->in_vif = gt->gt_route->rt_parent;
350 	    route_reply->out_vif_bm = gt->gt_grpmems;
351 
352 	} else {
353 	    /* Set error bit. */
354 	    BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
355 	}
356     }
357 
358     if (gt_notify)
359 	logit(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
360 
361     else
362 	logit(LOG_INFO, 0, "Send RSRR Route Reply");
363 
364     logit(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
365 	inet_fmt(route_reply->source_addr.s_addr,s1),
366 	inet_fmt(route_reply->dest_addr.s_addr,s2),
367 	route_reply->in_vif,route_reply->out_vif_bm);
368 
369     /* Send it. */
370     return rsrr_send(sendlen);
371 }
372 
373 /* Send an RSRR message. */
374 static int
375 rsrr_send(int sendlen)
376 {
377     int error;
378 
379     /* Send it. */
380     error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
381 		   (struct sockaddr *)&client_addr, client_length);
382 
383     /* Check for errors. */
384     if (error < 0) {
385 	logit(LOG_WARNING, errno, "Failed send on RSRR socket");
386     } else if (error != sendlen) {
387 	logit(LOG_WARNING, 0,
388 	    "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
389     }
390     return error;
391 }
392 
393 /* Cache a message being sent to a client.  Currently only used for
394  * caching Route Reply messages for route change notification.
395  */
396 static void
397 rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query)
398 {
399     struct rsrr_cache *rc, **rcnp;
400     struct rsrr_header *rsrr;
401 
402     rsrr = (struct rsrr_header *) rsrr_send_buf;
403 
404     rcnp = &gt->gt_rsrr_cache;
405     while ((rc = *rcnp) != NULL) {
406 	if ((rc->route_query.source_addr.s_addr ==
407 	     route_query->source_addr.s_addr) &&
408 	    (rc->route_query.dest_addr.s_addr ==
409 	     route_query->dest_addr.s_addr) &&
410 	    (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
411 	    /* Cache entry already exists.
412 	     * Check if route notification bit has been cleared.
413 	     */
414 	    if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
415 		/* Delete cache entry. */
416 		*rcnp = rc->next;
417 		free(rc);
418 	    } else {
419 		/* Update */
420 		rc->route_query.query_id = route_query->query_id;
421 		logit(LOG_DEBUG, 0,
422 			"Update cached query id %ld from client %s\n",
423 			rc->route_query.query_id, rc->client_addr.sun_path);
424 	    }
425 	    return;
426 	}
427 	rcnp = &rc->next;
428     }
429 
430     /* Cache entry doesn't already exist.  Create one and insert at
431      * front of list.
432      */
433     rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
434     if (rc == NULL)
435 	logit(LOG_ERR, 0, "ran out of memory");
436     rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
437     rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
438     rc->route_query.query_id = route_query->query_id;
439     strlcpy(rc->client_addr.sun_path, client_addr.sun_path,
440 	sizeof rc->client_addr.sun_path);
441     rc->client_length = client_length;
442     rc->next = gt->gt_rsrr_cache;
443     gt->gt_rsrr_cache = rc;
444     logit(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
445 	   rc->route_query.query_id,rc->client_addr.sun_path);
446 }
447 
448 /* Send all the messages in the cache.  Currently this is used to send
449  * all the cached Route Reply messages for route change notification.
450  */
451 void
452 rsrr_cache_send(struct gtable *gt, int notify)
453 {
454     struct rsrr_cache *rc, **rcnp;
455     int flags = 0;
456 
457     if (notify)
458 	BIT_SET(flags,RSRR_NOTIFICATION_BIT);
459 
460     rcnp = &gt->gt_rsrr_cache;
461     while ((rc = *rcnp) != NULL) {
462 	if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
463 	    logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
464 		   rc->route_query.query_id,rc->client_addr.sun_path);
465 	    /* Delete cache entry. */
466 	    *rcnp = rc->next;
467 	    free(rc);
468 	} else {
469 	    rcnp = &rc->next;
470 	}
471     }
472 }
473 
474 /* Clean the cache by deleting all entries. */
475 void
476 rsrr_cache_clean(struct gtable *gt)
477 {
478     struct rsrr_cache *rc,*rc_next;
479 
480     printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
481     rc = gt->gt_rsrr_cache;
482     while (rc) {
483 	rc_next = rc->next;
484 	free(rc);
485 	rc = rc_next;
486     }
487     gt->gt_rsrr_cache = NULL;
488 }
489 
490 void
491 rsrr_clean(void)
492 {
493     unlink(RSRR_SERV_PATH);
494 }
495 
496 #endif /* RSRR */
497