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