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_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_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