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