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