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
rsrr_init(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
rsrr_read(int f,fd_set * rfd)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
rsrr_accept(int recvlen)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
rsrr_accept_iq(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
rsrr_accept_rq(struct rsrr_rq * route_query,int flags,struct gtable * gt_notify)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
rsrr_send(int sendlen)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
rsrr_cache(struct gtable * gt,struct rsrr_rq * route_query)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_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
rsrr_cache_send(struct gtable * gt,int notify)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_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
rsrr_cache_clean(struct gtable * gt)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
rsrr_clean(void)491 rsrr_clean(void)
492 {
493 unlink(RSRR_SERV_PATH);
494 }
495
496 #endif /* RSRR */
497