1 /* $OpenBSD: rsrr.c,v 1.16 2019/06/28 13:32:48 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
rsrr_init(void)84 rsrr_init(void)
85 {
86 struct sockaddr_un serv_addr;
87
88 if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
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) == -1)
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
rsrr_read(int f)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 == -1) {
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
rsrr_accept(int recvlen)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
rsrr_accept_iq(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
rsrr_accept_rq(struct rsrr_rq * route_query,int flags,struct gtable * gt_notify)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
rsrr_send(int sendlen)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 == -1) {
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
rsrr_cache(struct gtable * gt,struct rsrr_rq * route_query)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
rsrr_cache_send(struct gtable * gt,int notify)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
rsrr_cache_clean(struct gtable * gt)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
rsrr_clean(void)480 rsrr_clean(void)
481 {
482 unlink(RSRR_SERV_PATH);
483 }
484
485 #endif /* RSRR */
486