blob: 40db33f5e461b066a521a7a36f08bb6673070c71 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIP version 1 and 2.
vincentfbf5d032005-09-29 11:25:50 +00002 * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
paul718e3742002-12-13 20:15:29 +00003 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org>
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "if.h"
26#include "command.h"
27#include "prefix.h"
28#include "table.h"
29#include "thread.h"
30#include "memory.h"
31#include "log.h"
32#include "stream.h"
33#include "filter.h"
34#include "sockunion.h"
hasso1af81932004-09-26 16:11:14 +000035#include "sockopt.h"
paul718e3742002-12-13 20:15:29 +000036#include "routemap.h"
hasso16705132003-05-25 14:49:19 +000037#include "if_rmap.h"
paul718e3742002-12-13 20:15:29 +000038#include "plist.h"
39#include "distribute.h"
vincentc1a03d42005-09-28 15:47:44 +000040#include "md5.h"
paul718e3742002-12-13 20:15:29 +000041#include "keychain.h"
pauledd7c242003-06-04 13:59:38 +000042#include "privs.h"
paul718e3742002-12-13 20:15:29 +000043
44#include "ripd/ripd.h"
45#include "ripd/rip_debug.h"
46
paul0b3acf42004-09-17 08:39:08 +000047/* UDP receive buffer size */
48#define RIP_UDP_RCV_BUF 41600
49
50/* privileges global */
pauledd7c242003-06-04 13:59:38 +000051extern struct zebra_privs_t ripd_privs;
52
paul718e3742002-12-13 20:15:29 +000053/* RIP Structure. */
54struct rip *rip = NULL;
55
56/* RIP neighbor address table. */
57struct route_table *rip_neighbor_table;
58
59/* RIP route changes. */
60long rip_global_route_changes = 0;
61
62/* RIP queries. */
63long rip_global_queries = 0;
64
65/* Prototypes. */
pauldc63bfd2005-10-25 23:31:05 +000066static void rip_event (enum rip_event, int);
67static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char);
68static int rip_triggered_update (struct thread *);
69static int rip_update_jitter (unsigned long);
70
paul718e3742002-12-13 20:15:29 +000071/* RIP output routes type. */
72enum
73{
74 rip_all_route,
75 rip_changed_route
76};
77
78/* RIP command strings. */
79struct message rip_msg[] =
80{
81 {RIP_REQUEST, "REQUEST"},
82 {RIP_RESPONSE, "RESPONSE"},
83 {RIP_TRACEON, "TRACEON"},
84 {RIP_TRACEOFF, "TRACEOFF"},
85 {RIP_POLL, "POLL"},
86 {RIP_POLL_ENTRY, "POLL ENTRY"},
87 {0, NULL}
88};
paul718e3742002-12-13 20:15:29 +000089
90/* Utility function to set boradcast option to the socket. */
pauldc63bfd2005-10-25 23:31:05 +000091static int
paul718e3742002-12-13 20:15:29 +000092sockopt_broadcast (int sock)
93{
94 int ret;
95 int on = 1;
96
97 ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
98 if (ret < 0)
99 {
100 zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
101 return -1;
102 }
103 return 0;
104}
105
pauldc63bfd2005-10-25 23:31:05 +0000106static int
paul718e3742002-12-13 20:15:29 +0000107rip_route_rte (struct rip_info *rinfo)
108{
109 return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE);
110}
111
pauldc63bfd2005-10-25 23:31:05 +0000112static struct rip_info *
paul718e3742002-12-13 20:15:29 +0000113rip_info_new ()
114{
115 struct rip_info *new;
116
117 new = XMALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
118 memset (new, 0, sizeof (struct rip_info));
119 return new;
120}
121
122void
123rip_info_free (struct rip_info *rinfo)
124{
125 XFREE (MTYPE_RIP_INFO, rinfo);
126}
127
128/* RIP route garbage collect timer. */
pauldc63bfd2005-10-25 23:31:05 +0000129static int
paul718e3742002-12-13 20:15:29 +0000130rip_garbage_collect (struct thread *t)
131{
132 struct rip_info *rinfo;
133 struct route_node *rp;
134
135 rinfo = THREAD_ARG (t);
136 rinfo->t_garbage_collect = NULL;
137
138 /* Off timeout timer. */
139 RIP_TIMER_OFF (rinfo->t_timeout);
140
141 /* Get route_node pointer. */
142 rp = rinfo->rp;
143
144 /* Unlock route_node. */
145 rp->info = NULL;
146 route_unlock_node (rp);
147
148 /* Free RIP routing information. */
149 rip_info_free (rinfo);
150
151 return 0;
152}
153
154/* Timeout RIP routes. */
pauldc63bfd2005-10-25 23:31:05 +0000155static int
paul718e3742002-12-13 20:15:29 +0000156rip_timeout (struct thread *t)
157{
158 struct rip_info *rinfo;
159 struct route_node *rn;
160
161 rinfo = THREAD_ARG (t);
162 rinfo->t_timeout = NULL;
163
164 rn = rinfo->rp;
165
166 /* - The garbage-collection timer is set for 120 seconds. */
167 RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
168 rip->garbage_time);
169
170 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
171 rinfo->metric);
172 /* - The metric for the route is set to 16 (infinity). This causes
173 the route to be removed from service. */
174 rinfo->metric = RIP_METRIC_INFINITY;
175 rinfo->flags &= ~RIP_RTF_FIB;
176
177 /* - The route change flag is to indicate that this entry has been
178 changed. */
179 rinfo->flags |= RIP_RTF_CHANGED;
180
181 /* - The output process is signalled to trigger a response. */
182 rip_event (RIP_TRIGGERED_UPDATE, 0);
183
184 return 0;
185}
186
pauldc63bfd2005-10-25 23:31:05 +0000187static void
paul718e3742002-12-13 20:15:29 +0000188rip_timeout_update (struct rip_info *rinfo)
189{
190 if (rinfo->metric != RIP_METRIC_INFINITY)
191 {
192 RIP_TIMER_OFF (rinfo->t_timeout);
193 RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
194 }
195}
196
pauldc63bfd2005-10-25 23:31:05 +0000197static int
paul718e3742002-12-13 20:15:29 +0000198rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
199{
200 struct distribute *dist;
201 struct access_list *alist;
202 struct prefix_list *plist;
203
204 /* Input distribute-list filtering. */
205 if (ri->list[RIP_FILTER_IN])
206 {
207 if (access_list_apply (ri->list[RIP_FILTER_IN],
208 (struct prefix *) p) == FILTER_DENY)
209 {
210 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000211 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000212 inet_ntoa (p->prefix), p->prefixlen);
213 return -1;
214 }
215 }
216 if (ri->prefix[RIP_FILTER_IN])
217 {
218 if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
219 (struct prefix *) p) == PREFIX_DENY)
220 {
221 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000222 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000223 inet_ntoa (p->prefix), p->prefixlen);
224 return -1;
225 }
226 }
227
228 /* All interface filter check. */
229 dist = distribute_lookup (NULL);
230 if (dist)
231 {
232 if (dist->list[DISTRIBUTE_IN])
233 {
234 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
235
236 if (alist)
237 {
238 if (access_list_apply (alist,
239 (struct prefix *) p) == FILTER_DENY)
240 {
241 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000242 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000243 inet_ntoa (p->prefix), p->prefixlen);
244 return -1;
245 }
246 }
247 }
248 if (dist->prefix[DISTRIBUTE_IN])
249 {
250 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
251
252 if (plist)
253 {
254 if (prefix_list_apply (plist,
255 (struct prefix *) p) == PREFIX_DENY)
256 {
257 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000258 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000259 inet_ntoa (p->prefix), p->prefixlen);
260 return -1;
261 }
262 }
263 }
264 }
265 return 0;
266}
267
pauldc63bfd2005-10-25 23:31:05 +0000268static int
paul718e3742002-12-13 20:15:29 +0000269rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
270{
271 struct distribute *dist;
272 struct access_list *alist;
273 struct prefix_list *plist;
274
275 if (ri->list[RIP_FILTER_OUT])
276 {
277 if (access_list_apply (ri->list[RIP_FILTER_OUT],
278 (struct prefix *) p) == FILTER_DENY)
279 {
280 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000281 zlog_debug ("%s/%d is filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000282 inet_ntoa (p->prefix), p->prefixlen);
283 return -1;
284 }
285 }
286 if (ri->prefix[RIP_FILTER_OUT])
287 {
288 if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
289 (struct prefix *) p) == PREFIX_DENY)
290 {
291 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000292 zlog_debug ("%s/%d is filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000293 inet_ntoa (p->prefix), p->prefixlen);
294 return -1;
295 }
296 }
297
298 /* All interface filter check. */
299 dist = distribute_lookup (NULL);
300 if (dist)
301 {
302 if (dist->list[DISTRIBUTE_OUT])
303 {
304 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
305
306 if (alist)
307 {
308 if (access_list_apply (alist,
309 (struct prefix *) p) == FILTER_DENY)
310 {
311 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000312 zlog_debug ("%s/%d filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000313 inet_ntoa (p->prefix), p->prefixlen);
314 return -1;
315 }
316 }
317 }
318 if (dist->prefix[DISTRIBUTE_OUT])
319 {
320 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
321
322 if (plist)
323 {
324 if (prefix_list_apply (plist,
325 (struct prefix *) p) == PREFIX_DENY)
326 {
327 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000328 zlog_debug ("%s/%d filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000329 inet_ntoa (p->prefix), p->prefixlen);
330 return -1;
331 }
332 }
333 }
334 }
335 return 0;
336}
337
338/* Check nexthop address validity. */
339static int
340rip_nexthop_check (struct in_addr *addr)
341{
hasso52dc7ee2004-09-23 19:18:23 +0000342 struct listnode *node;
343 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000344 struct interface *ifp;
345 struct connected *ifc;
346 struct prefix *p;
347
348 /* If nexthop address matches local configured address then it is
349 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000350 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000351 {
paul1eb8ef22005-04-07 07:30:20 +0000352 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000353 {
paul718e3742002-12-13 20:15:29 +0000354 p = ifc->address;
355
356 if (p->family == AF_INET
357 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
358 return -1;
359 }
360 }
361 return 0;
362}
363
364/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000365static void
paul718e3742002-12-13 20:15:29 +0000366rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000367 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000368{
369 int ret;
370 struct prefix_ipv4 p;
371 struct route_node *rp;
paulb94f9db2004-05-01 20:45:38 +0000372 struct rip_info *rinfo, rinfotmp;
paul718e3742002-12-13 20:15:29 +0000373 struct rip_interface *ri;
374 struct in_addr *nexthop;
375 u_char oldmetric;
376 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000377 int route_reuse = 0;
378 unsigned char old_dist, new_dist;
paul718e3742002-12-13 20:15:29 +0000379
380 /* Make prefix structure. */
381 memset (&p, 0, sizeof (struct prefix_ipv4));
382 p.family = AF_INET;
383 p.prefix = rte->prefix;
384 p.prefixlen = ip_masklen (rte->mask);
385
386 /* Make sure mask is applied. */
387 apply_mask_ipv4 (&p);
388
389 /* Apply input filters. */
390 ri = ifp->info;
391
392 ret = rip_incoming_filter (&p, ri);
393 if (ret < 0)
394 return;
395
hasso16705132003-05-25 14:49:19 +0000396 /* Modify entry according to the interface routemap. */
397 if (ri->routemap[RIP_FILTER_IN])
398 {
399 int ret;
400 struct rip_info newinfo;
401
402 memset (&newinfo, 0, sizeof (newinfo));
403 newinfo.type = ZEBRA_ROUTE_RIP;
404 newinfo.sub_type = RIP_ROUTE_RTE;
paula87552c2004-05-03 20:00:17 +0000405 newinfo.nexthop = rte->nexthop;
406 newinfo.from = from->sin_addr;
407 newinfo.ifindex = ifp->ifindex;
hasso16705132003-05-25 14:49:19 +0000408 newinfo.metric = rte->metric;
409 newinfo.metric_out = rte->metric; /* XXX */
paula87552c2004-05-03 20:00:17 +0000410 newinfo.tag = ntohs (rte->tag); /* XXX */
hasso16705132003-05-25 14:49:19 +0000411
412 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000413 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
414 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000415
416 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000417 {
418 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000419 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000420 inet_ntoa (p.prefix), p.prefixlen);
421 return;
422 }
hasso16705132003-05-25 14:49:19 +0000423
424 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000425 rte->nexthop = newinfo.nexthop_out;
426 rte->tag = htons (newinfo.tag_out); /* XXX */
427 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000428 }
429
paul718e3742002-12-13 20:15:29 +0000430 /* Once the entry has been validated, update the metric by
431 adding the cost of the network on wich the message
432 arrived. If the result is greater than infinity, use infinity
433 (RFC2453 Sec. 3.9.2) */
434 /* Zebra ripd can handle offset-list in. */
435 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
436
437 /* If offset-list does not modify the metric use interface's
438 metric. */
paula87552c2004-05-03 20:00:17 +0000439 if (!ret)
paul718e3742002-12-13 20:15:29 +0000440 rte->metric += ifp->metric;
441
442 if (rte->metric > RIP_METRIC_INFINITY)
443 rte->metric = RIP_METRIC_INFINITY;
444
445 /* Set nexthop pointer. */
446 if (rte->nexthop.s_addr == 0)
447 nexthop = &from->sin_addr;
448 else
449 nexthop = &rte->nexthop;
450
hasso16705132003-05-25 14:49:19 +0000451 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000452 if (rip_nexthop_check (nexthop) < 0)
453 {
454 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000455 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000456 return;
457 }
458
459 /* Get index for the prefix. */
460 rp = route_node_get (rip->table, (struct prefix *) &p);
461
462 /* Check to see whether there is already RIP route on the table. */
463 rinfo = rp->info;
464
465 if (rinfo)
466 {
paul718e3742002-12-13 20:15:29 +0000467 /* Local static route. */
468 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000469 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
470 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
471 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000472 {
473 route_unlock_node (rp);
474 return;
475 }
476
477 /* Redistributed route check. */
478 if (rinfo->type != ZEBRA_ROUTE_RIP
479 && rinfo->metric != RIP_METRIC_INFINITY)
480 {
481 /* Fill in a minimaly temporary rip_info structure, for a future
482 rip_distance_apply() use) */
483 memset (&rinfotmp, 0, sizeof (rinfotmp));
484 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
485 rinfotmp.rp = rinfo->rp;
486 new_dist = rip_distance_apply (&rinfotmp);
487 new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
488 old_dist = rinfo->distance;
489 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
490 /* If imported route does not have STRICT precedence,
491 mark it as a ghost */
492 if (new_dist > old_dist
493 || rte->metric == RIP_METRIC_INFINITY)
494 {
495 route_unlock_node (rp);
496 return;
497 }
498 else
499 {
500 RIP_TIMER_OFF (rinfo->t_timeout);
501 RIP_TIMER_OFF (rinfo->t_garbage_collect);
502
503 rp->info = NULL;
504 if (rip_route_rte (rinfo))
505 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
506 &rinfo->nexthop, rinfo->metric);
507 rip_info_free (rinfo);
508 rinfo = NULL;
509 route_reuse = 1;
510 }
511 }
paul718e3742002-12-13 20:15:29 +0000512 }
paula87552c2004-05-03 20:00:17 +0000513
514 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000515 {
516 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000517 for the destination prefix. If there is no such route, add
518 this route to the routing table, unless the metric is
519 infinity (there is no point in adding a route which
520 unusable). */
paul718e3742002-12-13 20:15:29 +0000521 if (rte->metric != RIP_METRIC_INFINITY)
paula87552c2004-05-03 20:00:17 +0000522 {
523 rinfo = rip_info_new ();
paul718e3742002-12-13 20:15:29 +0000524
paula87552c2004-05-03 20:00:17 +0000525 /* - Setting the destination prefix and length to those in
526 the RTE. */
527 rinfo->rp = rp;
paul718e3742002-12-13 20:15:29 +0000528
paula87552c2004-05-03 20:00:17 +0000529 /* - Setting the metric to the newly calculated metric (as
530 described above). */
531 rinfo->metric = rte->metric;
532 rinfo->tag = ntohs (rte->tag);
paul718e3742002-12-13 20:15:29 +0000533
paula87552c2004-05-03 20:00:17 +0000534 /* - Set the next hop address to be the address of the router
535 from which the datagram came or the next hop address
536 specified by a next hop RTE. */
537 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
538 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
539 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000540
paula87552c2004-05-03 20:00:17 +0000541 /* - Initialize the timeout for the route. If the
542 garbage-collection timer is running for this route, stop it
543 (see section 2.3 for a discussion of the timers). */
544 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000545
paula87552c2004-05-03 20:00:17 +0000546 /* - Set the route change flag. */
547 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +0000548
paula87552c2004-05-03 20:00:17 +0000549 /* - Signal the output process to trigger an update (see section
550 2.5). */
551 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000552
paula87552c2004-05-03 20:00:17 +0000553 /* Finally, route goes into the kernel. */
554 rinfo->type = ZEBRA_ROUTE_RIP;
555 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000556
paula87552c2004-05-03 20:00:17 +0000557 /* Set distance value. */
558 rinfo->distance = rip_distance_apply (rinfo);
559
560 rp->info = rinfo;
561 rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
562 rinfo->distance);
563 rinfo->flags |= RIP_RTF_FIB;
564 }
vincentfbf5d032005-09-29 11:25:50 +0000565
566 /* Unlock temporary lock, i.e. same behaviour */
567 if (route_reuse)
568 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +0000569 }
570 else
571 {
572 /* Route is there but we are not sure the route is RIP or not. */
573 rinfo = rp->info;
paula87552c2004-05-03 20:00:17 +0000574
paul718e3742002-12-13 20:15:29 +0000575 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000576 to the address of the router from which the datagram came.
577 If this datagram is from the same router as the existing
578 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000579 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000580 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000581
582 if (same)
paula87552c2004-05-03 20:00:17 +0000583 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000584
paulb94f9db2004-05-01 20:45:38 +0000585
586 /* Fill in a minimaly temporary rip_info structure, for a future
587 rip_distance_apply() use) */
paula87552c2004-05-03 20:00:17 +0000588 memset (&rinfotmp, 0, sizeof (rinfotmp));
paulb94f9db2004-05-01 20:45:38 +0000589 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
paula87552c2004-05-03 20:00:17 +0000590 rinfotmp.rp = rinfo->rp;
paulb94f9db2004-05-01 20:45:38 +0000591
592
paul718e3742002-12-13 20:15:29 +0000593 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000594 router as the existing route, and the new metric is different
595 than the old one; or, if the new metric is lower than the old
596 one, or if the tag has been changed; or if there is a route
597 with a lower administrave distance; or an update of the
598 distance on the actual route; do the following actions: */
599 if ((same && rinfo->metric != rte->metric)
600 || (rte->metric < rinfo->metric)
601 || ((same)
602 && (rinfo->metric == rte->metric)
603 && ntohs (rte->tag) != rinfo->tag)
604 || (rinfo->distance > rip_distance_apply (&rinfotmp))
605 || ((rinfo->distance != rip_distance_apply (rinfo)) && same))
606 {
607 /* - Adopt the route from the datagram. That is, put the
608 new metric in, and adjust the next hop address (if
609 necessary). */
610 oldmetric = rinfo->metric;
611 rinfo->metric = rte->metric;
612 rinfo->tag = ntohs (rte->tag);
613 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
614 rinfo->ifindex = ifp->ifindex;
615 rinfo->distance = rip_distance_apply (rinfo);
paul718e3742002-12-13 20:15:29 +0000616
paula87552c2004-05-03 20:00:17 +0000617 /* Should a new route to this network be established
618 while the garbage-collection timer is running, the
619 new route will replace the one that is about to be
620 deleted. In this case the garbage-collection timer
621 must be cleared. */
paul718e3742002-12-13 20:15:29 +0000622
paula87552c2004-05-03 20:00:17 +0000623 if (oldmetric == RIP_METRIC_INFINITY &&
624 rinfo->metric < RIP_METRIC_INFINITY)
625 {
626 rinfo->type = ZEBRA_ROUTE_RIP;
627 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000628
paula87552c2004-05-03 20:00:17 +0000629 RIP_TIMER_OFF (rinfo->t_garbage_collect);
paul718e3742002-12-13 20:15:29 +0000630
paula87552c2004-05-03 20:00:17 +0000631 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
632 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000633
paula87552c2004-05-03 20:00:17 +0000634 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
635 rinfo->distance);
636 rinfo->flags |= RIP_RTF_FIB;
637 }
paul718e3742002-12-13 20:15:29 +0000638
paula87552c2004-05-03 20:00:17 +0000639 /* Update nexthop and/or metric value. */
640 if (oldmetric != RIP_METRIC_INFINITY)
641 {
642 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
643 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
644 rinfo->distance);
645 rinfo->flags |= RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000646
paula87552c2004-05-03 20:00:17 +0000647 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
648 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
649 }
paul718e3742002-12-13 20:15:29 +0000650
paula87552c2004-05-03 20:00:17 +0000651 /* - Set the route change flag and signal the output process
652 to trigger an update. */
653 rinfo->flags |= RIP_RTF_CHANGED;
654 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000655
paula87552c2004-05-03 20:00:17 +0000656 /* - If the new metric is infinity, start the deletion
657 process (described above); */
658 if (rinfo->metric == RIP_METRIC_INFINITY)
659 {
660 /* If the new metric is infinity, the deletion process
661 begins for the route, which is no longer used for
662 routing packets. Note that the deletion process is
663 started only when the metric is first set to
664 infinity. If the metric was already infinity, then a
665 new deletion process is not started. */
666 if (oldmetric != RIP_METRIC_INFINITY)
667 {
668 /* - The garbage-collection timer is set for 120 seconds. */
669 RIP_TIMER_ON (rinfo->t_garbage_collect,
670 rip_garbage_collect, rip->garbage_time);
671 RIP_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +0000672
paula87552c2004-05-03 20:00:17 +0000673 /* - The metric for the route is set to 16
674 (infinity). This causes the route to be removed
675 from service. */
676 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
677 rinfo->flags &= ~RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000678
paula87552c2004-05-03 20:00:17 +0000679 /* - The route change flag is to indicate that this
680 entry has been changed. */
681 /* - The output process is signalled to trigger a
paul718e3742002-12-13 20:15:29 +0000682 response. */
paula87552c2004-05-03 20:00:17 +0000683 ; /* Above processes are already done previously. */
684 }
685 }
686 else
687 {
688 /* otherwise, re-initialize the timeout. */
689 rip_timeout_update (rinfo);
690 }
691 }
paul718e3742002-12-13 20:15:29 +0000692 /* Unlock tempolary lock of the route. */
693 route_unlock_node (rp);
694 }
695}
696
697/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000698static void
hasso8a676be2004-10-08 06:36:38 +0000699rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000700{
701 caddr_t lim;
702 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000703 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000704 char pbuf[BUFSIZ], nbuf[BUFSIZ];
705 u_char netmask = 0;
706 u_char *p;
707
708 /* Set command string. */
709 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
710 command_str = lookup (rip_msg, packet->command);
711 else
712 command_str = "unknown";
713
714 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000715 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000716 sndrcv, command_str, packet->version, size);
717
718 /* Dump each routing table entry. */
719 rte = packet->rte;
720
721 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
722 {
723 if (packet->version == RIPv2)
724 {
725 netmask = ip_masklen (rte->mask);
726
paulca5e5162004-06-06 22:06:33 +0000727 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000728 {
paulca5e5162004-06-06 22:06:33 +0000729 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000730 {
731 p = (u_char *)&rte->prefix;
732
ajs5d6c3772004-12-08 19:24:06 +0000733 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000734 ntohs (rte->family), ntohs (rte->tag), p);
735 }
paulca5e5162004-06-06 22:06:33 +0000736 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000737 {
738 struct rip_md5_info *md5;
739
740 md5 = (struct rip_md5_info *) &packet->rte;
741
ajs5d6c3772004-12-08 19:24:06 +0000742 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000743 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000744 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000745 " Auth Data len %d",
746 ntohs (md5->packet_len), md5->keyid,
747 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000748 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000749 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000750 }
paulca5e5162004-06-06 22:06:33 +0000751 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000752 {
753 p = (u_char *)&rte->prefix;
754
ajs5d6c3772004-12-08 19:24:06 +0000755 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000756 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000757 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000758 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000759 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
760 p[7], p[9], p[10], p[11], p[12], p[13],
761 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000762 }
763 else
764 {
ajs5d6c3772004-12-08 19:24:06 +0000765 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000766 ntohs (rte->family), ntohs (rte->tag));
767 }
768 }
769 else
ajs5d6c3772004-12-08 19:24:06 +0000770 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000771 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
772 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
773 BUFSIZ), ntohs (rte->family),
774 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000775 }
776 else
777 {
ajs5d6c3772004-12-08 19:24:06 +0000778 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000779 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
780 ntohs (rte->family), ntohs (rte->tag),
781 (u_long)ntohl (rte->metric));
782 }
783 }
784}
785
786/* Check if the destination address is valid (unicast; not net 0
787 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
788 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000789static int
paul718e3742002-12-13 20:15:29 +0000790rip_destination_check (struct in_addr addr)
791{
792 u_int32_t destination;
793
794 /* Convert to host byte order. */
795 destination = ntohl (addr.s_addr);
796
797 if (IPV4_NET127 (destination))
798 return 0;
799
800 /* Net 0 may match to the default route. */
801 if (IPV4_NET0 (destination) && destination != 0)
802 return 0;
803
804 /* Unicast address must belong to class A, B, C. */
805 if (IN_CLASSA (destination))
806 return 1;
807 if (IN_CLASSB (destination))
808 return 1;
809 if (IN_CLASSC (destination))
810 return 1;
811
812 return 0;
813}
814
815/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000816static int
paul718e3742002-12-13 20:15:29 +0000817rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
818 struct interface *ifp)
819{
820 struct rip_interface *ri;
821 char *auth_str;
822
823 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000824 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000825 inet_ntoa (from->sin_addr));
826
827 ri = ifp->info;
828
829 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000830 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000831 return 0;
832
833 /* Simple password authentication. */
834 if (ri->auth_str)
835 {
836 auth_str = (char *) &rte->prefix;
837
838 if (strncmp (auth_str, ri->auth_str, 16) == 0)
839 return 1;
840 }
841 if (ri->key_chain)
842 {
843 struct keychain *keychain;
844 struct key *key;
845
846 keychain = keychain_lookup (ri->key_chain);
847 if (keychain == NULL)
848 return 0;
849
850 key = key_match_for_accept (keychain, (char *) &rte->prefix);
851 if (key)
852 return 1;
853 }
854 return 0;
855}
856
857/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000858static int
paul718e3742002-12-13 20:15:29 +0000859rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000860 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000861{
862 struct rip_interface *ri;
863 struct rip_md5_info *md5;
864 struct rip_md5_data *md5data;
865 struct keychain *keychain;
866 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000867 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000868 u_char digest[RIP_AUTH_MD5_SIZE];
869 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000870 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000871
872 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000873 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000874 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000875
876 ri = ifp->info;
877 md5 = (struct rip_md5_info *) &packet->rte;
878
879 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000880 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000881 return 0;
882
paulca5e5162004-06-06 22:06:33 +0000883 /* If the authentication length is less than 16, then it must be wrong for
884 * any interpretation of rfc2082. Some implementations also interpret
885 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000886 */
paulca5e5162004-06-06 22:06:33 +0000887 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
888 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000889 {
890 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000891 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000892 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000893 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000894 }
paul718e3742002-12-13 20:15:29 +0000895
paulca5e5162004-06-06 22:06:33 +0000896 /* grab and verify check packet length */
897 packet_len = ntohs (md5->packet_len);
898
899 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
900 {
901 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000902 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000903 "greater than received length %d!",
904 md5->packet_len, length);
905 return 0;
906 }
907
908 /* retrieve authentication data */
909 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000910
911 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000912
paul718e3742002-12-13 20:15:29 +0000913 if (ri->key_chain)
914 {
915 keychain = keychain_lookup (ri->key_chain);
916 if (keychain == NULL)
917 return 0;
918
919 key = key_lookup_for_accept (keychain, md5->keyid);
920 if (key == NULL)
921 return 0;
922
paul98fd1e62006-01-17 17:26:25 +0000923 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000924 }
paul98fd1e62006-01-17 17:26:25 +0000925 else if (ri->auth_str)
926 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000927
928 if (! auth_str)
929 return 0;
paul98fd1e62006-01-17 17:26:25 +0000930
paul718e3742002-12-13 20:15:29 +0000931 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000932 memset (&ctx, 0, sizeof(ctx));
933 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000934 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
935 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000936 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000937
938 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000939 return packet_len;
940 else
941 return 0;
942}
943
paulb14ee002005-02-04 23:42:41 +0000944/* Pick correct auth string for sends, prepare auth_str buffer for use.
945 * (left justified and padded).
946 *
947 * presumes one of ri or key is valid, and that the auth strings they point
948 * to are nul terminated. If neither are present, auth_str will be fully
949 * zero padded.
950 *
951 */
952static void
953rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
954 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +0000955{
paulb14ee002005-02-04 23:42:41 +0000956 assert (ri || key);
paul718e3742002-12-13 20:15:29 +0000957
paulb14ee002005-02-04 23:42:41 +0000958 memset (auth_str, 0, len);
959 if (key && key->string)
960 strncpy (auth_str, key->string, len);
961 else if (ri->auth_str)
962 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +0000963
paulb14ee002005-02-04 23:42:41 +0000964 return;
965}
paul718e3742002-12-13 20:15:29 +0000966
paulb14ee002005-02-04 23:42:41 +0000967/* Write RIPv2 simple password authentication information
968 *
969 * auth_str is presumed to be 2 bytes and correctly prepared
970 * (left justified and zero padded).
971 */
972static void
973rip_auth_simple_write (struct stream *s, char *auth_str, int len)
974{
975 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +0000976
paulb14ee002005-02-04 23:42:41 +0000977 stream_putw (s, RIP_FAMILY_AUTH);
978 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
979 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
980
981 return;
982}
983
984/* write RIPv2 MD5 "authentication header"
985 * (uses the auth key data field)
986 *
987 * Digest offset field is set to 0.
988 *
989 * returns: offset of the digest offset field, which must be set when
990 * length to the auth-data MD5 digest is known.
991 */
992static size_t
993rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
994 struct key *key)
995{
paul98fd1e62006-01-17 17:26:25 +0000996 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +0000997
998 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +0000999
1000 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +00001001 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +00001002 stream_putw (s, RIP_AUTH_MD5);
1003
paulb14ee002005-02-04 23:42:41 +00001004 /* MD5 AH digest offset field.
1005 *
1006 * Set to placeholder value here, to true value when RIP-2 Packet length
1007 * is known. Actual value is set in .....().
1008 */
paul98fd1e62006-01-17 17:26:25 +00001009 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001010 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001011
1012 /* Key ID. */
1013 if (key)
1014 stream_putc (s, key->index % 256);
1015 else
1016 stream_putc (s, 1);
1017
paulca5e5162004-06-06 22:06:33 +00001018 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1019 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1020 * to be configurable.
1021 */
1022 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001023
1024 /* Sequence Number (non-decreasing). */
1025 /* RFC2080: The value used in the sequence number is
1026 arbitrary, but two suggestions are the time of the
1027 message's creation or a simple message counter. */
1028 stream_putl (s, time (NULL));
1029
1030 /* Reserved field must be zero. */
1031 stream_putl (s, 0);
1032 stream_putl (s, 0);
1033
paul98fd1e62006-01-17 17:26:25 +00001034 return doff;
paulb14ee002005-02-04 23:42:41 +00001035}
paul718e3742002-12-13 20:15:29 +00001036
paulb14ee002005-02-04 23:42:41 +00001037/* If authentication is in used, write the appropriate header
1038 * returns stream offset to which length must later be written
1039 * or 0 if this is not required
1040 */
1041static size_t
1042rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1043 struct key *key, char *auth_str, int len)
1044{
1045 assert (ri->auth_type != RIP_NO_AUTH);
1046
1047 switch (ri->auth_type)
1048 {
1049 case RIP_AUTH_SIMPLE_PASSWORD:
1050 rip_auth_prepare_str_send (ri, key, auth_str, len);
1051 rip_auth_simple_write (s, auth_str, len);
1052 return 0;
1053 case RIP_AUTH_MD5:
1054 return rip_auth_md5_ah_write (s, ri, key);
1055 }
1056 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001057 return 0;
paulb14ee002005-02-04 23:42:41 +00001058}
1059
1060/* Write RIPv2 MD5 authentication data trailer */
1061static void
1062rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1063 char *auth_str, int authlen)
1064{
1065 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001066 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001067 unsigned char digest[RIP_AUTH_MD5_SIZE];
1068
1069 /* Make it sure this interface is configured as MD5
1070 authentication. */
1071 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1072 assert (doff > 0);
1073
1074 /* Get packet length. */
1075 len = stream_get_endp(s);
1076
1077 /* Check packet length. */
1078 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1079 {
1080 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1081 return;
1082 }
1083
1084 /* Set the digest offset length in the header */
1085 stream_putw_at (s, doff, len);
1086
paul718e3742002-12-13 20:15:29 +00001087 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001088 stream_putw (s, RIP_FAMILY_AUTH);
1089 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001090
1091 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001092 memset(&ctx, 0, sizeof(ctx));
1093 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001094 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001095 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1096 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001097
1098 /* Copy the digest to the packet. */
1099 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1100}
1101
1102/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001103static void
paul718e3742002-12-13 20:15:29 +00001104rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001105 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001106{
1107 caddr_t lim;
1108 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001109 struct prefix_ipv4 ifaddr;
1110 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001111 int subnetted;
paul718e3742002-12-13 20:15:29 +00001112
paul727d1042002-12-13 20:50:29 +00001113 /* We don't know yet. */
1114 subnetted = -1;
1115
paul718e3742002-12-13 20:15:29 +00001116 /* The Response must be ignored if it is not from the RIP
1117 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001118 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001119 {
1120 zlog_info ("response doesn't come from RIP port: %d",
1121 from->sin_port);
1122 rip_peer_bad_packet (from);
1123 return;
1124 }
1125
1126 /* The datagram's IPv4 source address should be checked to see
1127 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001128 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1129 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001130 {
1131 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1132 inet_ntoa (from->sin_addr));
1133 rip_peer_bad_packet (from);
1134 return;
1135 }
1136
1137 /* It is also worth checking to see whether the response is from one
1138 of the router's own addresses. */
1139
1140 ; /* Alredy done in rip_read () */
1141
1142 /* Update RIP peer. */
1143 rip_peer_update (from, packet->version);
1144
1145 /* Set RTE pointer. */
1146 rte = packet->rte;
1147
1148 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1149 {
1150 /* RIPv2 authentication check. */
1151 /* If the Address Family Identifier of the first (and only the
1152 first) entry in the message is 0xFFFF, then the remainder of
1153 the entry contains the authentication. */
1154 /* If the packet gets here it means authentication enabled */
1155 /* Check is done in rip_read(). So, just skipping it */
1156 if (packet->version == RIPv2 &&
1157 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001158 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001159 continue;
1160
paulca5e5162004-06-06 22:06:33 +00001161 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001162 {
1163 /* Address family check. RIP only supports AF_INET. */
1164 zlog_info ("Unsupported family %d from %s.",
1165 ntohs (rte->family), inet_ntoa (from->sin_addr));
1166 continue;
1167 }
1168
1169 /* - is the destination address valid (e.g., unicast; not net 0
1170 or 127) */
1171 if (! rip_destination_check (rte->prefix))
1172 {
1173 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1174 rip_peer_bad_route (from);
1175 continue;
1176 }
1177
1178 /* Convert metric value to host byte order. */
1179 rte->metric = ntohl (rte->metric);
1180
1181 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1182 if (! (rte->metric >= 1 && rte->metric <= 16))
1183 {
1184 zlog_info ("Route's metric is not in the 1-16 range.");
1185 rip_peer_bad_route (from);
1186 continue;
1187 }
1188
1189 /* RIPv1 does not have nexthop value. */
1190 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1191 {
1192 zlog_info ("RIPv1 packet with nexthop value %s",
1193 inet_ntoa (rte->nexthop));
1194 rip_peer_bad_route (from);
1195 continue;
1196 }
1197
1198 /* That is, if the provided information is ignored, a possibly
1199 sub-optimal, but absolutely valid, route may be taken. If
1200 the received Next Hop is not directly reachable, it should be
1201 treated as 0.0.0.0. */
1202 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1203 {
1204 u_int32_t addrval;
1205
1206 /* Multicast address check. */
1207 addrval = ntohl (rte->nexthop.s_addr);
1208 if (IN_CLASSD (addrval))
1209 {
1210 zlog_info ("Nexthop %s is multicast address, skip this rte",
1211 inet_ntoa (rte->nexthop));
1212 continue;
1213 }
1214
1215 if (! if_lookup_address (rte->nexthop))
1216 {
1217 struct route_node *rn;
1218 struct rip_info *rinfo;
1219
1220 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1221
1222 if (rn)
1223 {
1224 rinfo = rn->info;
1225
1226 if (rinfo->type == ZEBRA_ROUTE_RIP
1227 && rinfo->sub_type == RIP_ROUTE_RTE)
1228 {
1229 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001230 zlog_debug ("Next hop %s is on RIP network. Set nexthop to the packet's originator", inet_ntoa (rte->nexthop));
paul718e3742002-12-13 20:15:29 +00001231 rte->nexthop = rinfo->from;
1232 }
1233 else
1234 {
1235 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001236 zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
paul718e3742002-12-13 20:15:29 +00001237 rte->nexthop.s_addr = 0;
1238 }
1239
1240 route_unlock_node (rn);
1241 }
1242 else
1243 {
1244 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001245 zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
paul718e3742002-12-13 20:15:29 +00001246 rte->nexthop.s_addr = 0;
1247 }
1248
1249 }
1250 }
1251
1252 /* For RIPv1, there won't be a valid netmask.
1253
1254 This is a best guess at the masks. If everyone was using old
1255 Ciscos before the 'ip subnet zero' option, it would be almost
1256 right too :-)
1257
1258 Cisco summarize ripv1 advertisments to the classful boundary
1259 (/16 for class B's) except when the RIP packet does to inside
1260 the classful network in question. */
1261
1262 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1263 || (packet->version == RIPv2
1264 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1265 {
1266 u_int32_t destination;
1267
paul727d1042002-12-13 20:50:29 +00001268 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001269 {
1270 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1271 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1272 apply_classful_mask_ipv4 (&ifaddrclass);
1273 subnetted = 0;
1274 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1275 subnetted = 1;
1276 }
paul727d1042002-12-13 20:50:29 +00001277
paul718e3742002-12-13 20:15:29 +00001278 destination = ntohl (rte->prefix.s_addr);
1279
paul727d1042002-12-13 20:50:29 +00001280 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001281 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001282 else if (IN_CLASSB (destination))
1283 masklen2ip (16, &rte->mask);
1284 else if (IN_CLASSC (destination))
1285 masklen2ip (24, &rte->mask);
1286
1287 if (subnetted == 1)
1288 masklen2ip (ifaddrclass.prefixlen,
1289 (struct in_addr *) &destination);
1290 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1291 ifaddrclass.prefix.s_addr))
1292 {
1293 masklen2ip (ifaddr.prefixlen, &rte->mask);
1294 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1295 masklen2ip (32, &rte->mask);
1296 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001297 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001298 }
1299 else
1300 {
1301 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1302 continue;
1303 }
1304
1305 if (IS_RIP_DEBUG_EVENT)
1306 {
ajs5d6c3772004-12-08 19:24:06 +00001307 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1308 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001309 }
1310 }
1311
1312 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1313 ignore the entry. */
1314 if ((packet->version == RIPv2)
1315 && (rte->mask.s_addr != 0)
1316 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1317 {
1318 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1319 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1320 rip_peer_bad_route (from);
1321 continue;
1322 }
1323
1324 /* Default route's netmask is ignored. */
1325 if (packet->version == RIPv2
1326 && (rte->prefix.s_addr == 0)
1327 && (rte->mask.s_addr != 0))
1328 {
1329 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001330 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001331 rte->mask.s_addr = 0;
1332 }
1333
1334 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001335 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001336 }
1337}
1338
paula4e987e2005-06-03 17:46:49 +00001339/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001340static int
paul2c61ae32005-08-16 15:22:14 +00001341rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001342{
1343 int ret;
1344 int sock;
1345 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001346
paul2c61ae32005-08-16 15:22:14 +00001347 memset (&addr, 0, sizeof (struct sockaddr_in));
1348
1349 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001350 {
paulf69bd9d2005-06-03 18:01:50 +00001351 addr.sin_family = AF_INET;
1352 addr.sin_addr.s_addr = INADDR_ANY;
paul2c61ae32005-08-16 15:22:14 +00001353#ifdef HAVE_SINLEN
1354 addr.sin_len = sizeof (struct sockaddr_in);
1355#endif /* HAVE_SINLEN */
jardin38d3c162005-10-19 19:29:59 +00001356 } else {
1357 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001358 }
1359
paul2c61ae32005-08-16 15:22:14 +00001360 /* sending port must always be the RIP port */
1361 addr.sin_port = htons (RIP_PORT_DEFAULT);
1362
paula4e987e2005-06-03 17:46:49 +00001363 /* Make datagram socket. */
1364 sock = socket (AF_INET, SOCK_DGRAM, 0);
1365 if (sock < 0)
1366 {
1367 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1368 exit (1);
1369 }
1370
1371 sockopt_broadcast (sock);
1372 sockopt_reuseaddr (sock);
1373 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001374#ifdef RIP_RECVMSG
1375 setsockopt_pktinfo (sock);
1376#endif /* RIP_RECVMSG */
1377
1378 if (ripd_privs.change (ZPRIVS_RAISE))
1379 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001380 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1381 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1382
paula4e987e2005-06-03 17:46:49 +00001383 {
1384 int save_errno = errno;
1385 if (ripd_privs.change (ZPRIVS_LOWER))
1386 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001387
1388 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1389 sock, inet_ntoa(addr.sin_addr),
1390 (int) ntohs(addr.sin_port),
1391 safe_strerror(save_errno));
1392
paulf69bd9d2005-06-03 18:01:50 +00001393 close (sock);
paula4e987e2005-06-03 17:46:49 +00001394 return ret;
1395 }
paulf69bd9d2005-06-03 18:01:50 +00001396
paula4e987e2005-06-03 17:46:49 +00001397 if (ripd_privs.change (ZPRIVS_LOWER))
1398 zlog_err ("rip_create_socket: could not lower privs");
1399
1400 return sock;
1401}
1402
paulc49ad8f2004-10-22 10:27:28 +00001403/* RIP packet send to destination address, on interface denoted by
1404 * by connected argument. NULL to argument denotes destination should be
1405 * should be RIP multicast group
1406 */
pauldc63bfd2005-10-25 23:31:05 +00001407static int
paulc49ad8f2004-10-22 10:27:28 +00001408rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1409 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001410{
paul931cd542004-01-23 15:31:42 +00001411 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001412 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001413
1414 assert (ifc != NULL);
1415
paul931cd542004-01-23 15:31:42 +00001416 if (IS_RIP_DEBUG_PACKET)
1417 {
paulf69bd9d2005-06-03 18:01:50 +00001418#define ADDRESS_SIZE 20
1419 char dst[ADDRESS_SIZE];
1420 dst[ADDRESS_SIZE - 1] = '\0';
1421
paul931cd542004-01-23 15:31:42 +00001422 if (to)
1423 {
paulf69bd9d2005-06-03 18:01:50 +00001424 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001425 }
1426 else
1427 {
1428 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001429 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001430 }
paulf69bd9d2005-06-03 18:01:50 +00001431#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001432 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001433 inet_ntoa(ifc->address->u.prefix4),
1434 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001435 }
paulf69bd9d2005-06-03 18:01:50 +00001436
paulc49ad8f2004-10-22 10:27:28 +00001437 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001438 {
1439 /*
1440 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1441 * with multiple addresses on the same subnet: the first address
1442 * on the subnet is configured "primary", and all subsequent addresses
1443 * on that subnet are treated as "secondary" addresses.
1444 * In order to avoid routing-table bloat on other rip listeners,
1445 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1446 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1447 * flag is set, we would end up sending a packet for a "secondary"
1448 * source address on non-linux systems.
1449 */
1450 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001451 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001452 return 0;
1453 }
1454
paul718e3742002-12-13 20:15:29 +00001455 /* Make destination address. */
1456 memset (&sin, 0, sizeof (struct sockaddr_in));
1457 sin.sin_family = AF_INET;
1458#ifdef HAVE_SIN_LEN
1459 sin.sin_len = sizeof (struct sockaddr_in);
1460#endif /* HAVE_SIN_LEN */
1461
1462 /* When destination is specified, use it's port and address. */
1463 if (to)
1464 {
paul718e3742002-12-13 20:15:29 +00001465 sin.sin_port = to->sin_port;
1466 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001467 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001468 }
1469 else
1470 {
paul2c61ae32005-08-16 15:22:14 +00001471 struct sockaddr_in from;
1472
paul718e3742002-12-13 20:15:29 +00001473 sin.sin_port = htons (RIP_PORT_DEFAULT);
1474 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001475
1476 /* multicast send should bind to local interface address */
1477 from.sin_family = AF_INET;
1478 from.sin_port = htons (RIP_PORT_DEFAULT);
1479 from.sin_addr = ifc->address->u.prefix4;
1480#ifdef HAVE_SIN_LEN
1481 from.sin_len = sizeof (struct sockaddr_in);
1482#endif /* HAVE_SIN_LEN */
1483
paul931cd542004-01-23 15:31:42 +00001484 /*
1485 * we have to open a new socket for each packet because this
1486 * is the most portable way to bind to a different source
1487 * ipv4 address for each packet.
1488 */
paul2c61ae32005-08-16 15:22:14 +00001489 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001490 {
paulf69bd9d2005-06-03 18:01:50 +00001491 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001492 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001493 }
paulc49ad8f2004-10-22 10:27:28 +00001494 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001495 }
1496
paul931cd542004-01-23 15:31:42 +00001497 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001498 sizeof (struct sockaddr_in));
1499
1500 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001501 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001502 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001503
1504 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001505 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001506
paul931cd542004-01-23 15:31:42 +00001507 if (!to)
1508 close(send_sock);
1509
paul718e3742002-12-13 20:15:29 +00001510 return ret;
1511}
1512
1513/* Add redistributed route to RIP table. */
1514void
1515rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001516 unsigned int ifindex, struct in_addr *nexthop,
1517 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001518{
1519 int ret;
1520 struct route_node *rp;
1521 struct rip_info *rinfo;
1522
1523 /* Redistribute route */
1524 ret = rip_destination_check (p->prefix);
1525 if (! ret)
1526 return;
1527
1528 rp = route_node_get (rip->table, (struct prefix *) p);
1529
1530 rinfo = rp->info;
1531
1532 if (rinfo)
1533 {
1534 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1535 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1536 && rinfo->metric != RIP_METRIC_INFINITY)
1537 {
1538 route_unlock_node (rp);
1539 return;
1540 }
1541
1542 /* Manually configured RIP route check. */
1543 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001544 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1545 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001546 {
hasso16705132003-05-25 14:49:19 +00001547 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1548 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001549 {
1550 route_unlock_node (rp);
1551 return;
1552 }
1553 }
1554
1555 RIP_TIMER_OFF (rinfo->t_timeout);
1556 RIP_TIMER_OFF (rinfo->t_garbage_collect);
1557
1558 if (rip_route_rte (rinfo))
1559 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
1560 rinfo->metric);
1561 rp->info = NULL;
1562 rip_info_free (rinfo);
1563
1564 route_unlock_node (rp);
1565 }
1566
1567 rinfo = rip_info_new ();
1568
1569 rinfo->type = type;
1570 rinfo->sub_type = sub_type;
1571 rinfo->ifindex = ifindex;
1572 rinfo->metric = 1;
vincentfbf5d032005-09-29 11:25:50 +00001573 rinfo->external_metric = metric;
1574 rinfo->distance = distance;
paul718e3742002-12-13 20:15:29 +00001575 rinfo->rp = rp;
1576
1577 if (nexthop)
1578 rinfo->nexthop = *nexthop;
1579
1580 rinfo->flags |= RIP_RTF_FIB;
1581 rp->info = rinfo;
1582
1583 rinfo->flags |= RIP_RTF_CHANGED;
1584
hasso16705132003-05-25 14:49:19 +00001585 if (IS_RIP_DEBUG_EVENT) {
1586 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001587 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001588 inet_ntoa(p->prefix), p->prefixlen,
1589 ifindex2ifname(ifindex));
1590 else
ajs5d6c3772004-12-08 19:24:06 +00001591 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001592 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1593 ifindex2ifname(ifindex));
1594 }
1595
1596
paul718e3742002-12-13 20:15:29 +00001597 rip_event (RIP_TRIGGERED_UPDATE, 0);
1598}
1599
1600/* Delete redistributed route from RIP table. */
1601void
1602rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1603 unsigned int ifindex)
1604{
1605 int ret;
1606 struct route_node *rp;
1607 struct rip_info *rinfo;
1608
1609 ret = rip_destination_check (p->prefix);
1610 if (! ret)
1611 return;
1612
1613 rp = route_node_lookup (rip->table, (struct prefix *) p);
1614 if (rp)
1615 {
1616 rinfo = rp->info;
1617
1618 if (rinfo != NULL
1619 && rinfo->type == type
1620 && rinfo->sub_type == sub_type
1621 && rinfo->ifindex == ifindex)
1622 {
1623 /* Perform poisoned reverse. */
1624 rinfo->metric = RIP_METRIC_INFINITY;
1625 RIP_TIMER_ON (rinfo->t_garbage_collect,
1626 rip_garbage_collect, rip->garbage_time);
1627 RIP_TIMER_OFF (rinfo->t_timeout);
1628 rinfo->flags |= RIP_RTF_CHANGED;
1629
hasso16705132003-05-25 14:49:19 +00001630 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001631 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso16705132003-05-25 14:49:19 +00001632 inet_ntoa(p->prefix), p->prefixlen,
1633 ifindex2ifname(ifindex));
1634
paul718e3742002-12-13 20:15:29 +00001635 rip_event (RIP_TRIGGERED_UPDATE, 0);
1636 }
1637 }
1638}
1639
1640/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001641static void
paul718e3742002-12-13 20:15:29 +00001642rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001643 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001644{
1645 caddr_t lim;
1646 struct rte *rte;
1647 struct prefix_ipv4 p;
1648 struct route_node *rp;
1649 struct rip_info *rinfo;
1650 struct rip_interface *ri;
1651
hasso16705132003-05-25 14:49:19 +00001652 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001653 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001654 return;
1655
hasso429a0f82004-02-22 23:42:22 +00001656 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001657 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001658 if (! ri->running)
1659 return;
paul718e3742002-12-13 20:15:29 +00001660
1661 /* When passive interface is specified, suppress responses */
1662 if (ri->passive)
1663 return;
paulc49ad8f2004-10-22 10:27:28 +00001664
paul718e3742002-12-13 20:15:29 +00001665 /* RIP peer update. */
1666 rip_peer_update (from, packet->version);
1667
1668 lim = ((caddr_t) packet) + size;
1669 rte = packet->rte;
1670
1671 /* The Request is processed entry by entry. If there are no
1672 entries, no response is given. */
1673 if (lim == (caddr_t) rte)
1674 return;
1675
1676 /* There is one special case. If there is exactly one entry in the
1677 request, and it has an address family identifier of zero and a
1678 metric of infinity (i.e., 16), then this is a request to send the
1679 entire routing table. */
1680 if (lim == ((caddr_t) (rte + 1)) &&
1681 ntohs (rte->family) == 0 &&
1682 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1683 {
paulcc1131a2003-10-15 23:20:17 +00001684 struct prefix_ipv4 saddr;
1685
1686 /* saddr will be used for determining which routes to split-horizon.
1687 Since the source address we'll pick will be on the same subnet as the
1688 destination, for the purpose of split-horizoning, we'll
1689 pretend that "from" is our source address. */
1690 saddr.family = AF_INET;
1691 saddr.prefixlen = IPV4_MAX_BITLEN;
1692 saddr.prefix = from->sin_addr;
1693
paul718e3742002-12-13 20:15:29 +00001694 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001695 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001696 }
1697 else
1698 {
1699 /* Examine the list of RTEs in the Request one by one. For each
1700 entry, look up the destination in the router's routing
1701 database and, if there is a route, put that route's metric in
1702 the metric field of the RTE. If there is no explicit route
1703 to the specified destination, put infinity in the metric
1704 field. Once all the entries have been filled in, change the
1705 command from Request to Response and send the datagram back
1706 to the requestor. */
1707 p.family = AF_INET;
1708
1709 for (; ((caddr_t) rte) < lim; rte++)
1710 {
1711 p.prefix = rte->prefix;
1712 p.prefixlen = ip_masklen (rte->mask);
1713 apply_mask_ipv4 (&p);
1714
1715 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1716 if (rp)
1717 {
1718 rinfo = rp->info;
1719 rte->metric = htonl (rinfo->metric);
1720 route_unlock_node (rp);
1721 }
1722 else
1723 rte->metric = htonl (RIP_METRIC_INFINITY);
1724 }
1725 packet->command = RIP_RESPONSE;
1726
paulc49ad8f2004-10-22 10:27:28 +00001727 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001728 }
1729 rip_global_queries++;
1730}
1731
1732#if RIP_RECVMSG
1733/* Set IPv6 packet info to the socket. */
1734static int
1735setsockopt_pktinfo (int sock)
1736{
1737 int ret;
1738 int val = 1;
1739
1740 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1741 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001742 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001743 return ret;
1744}
1745
1746/* Read RIP packet by recvmsg function. */
1747int
1748rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1749 int *ifindex)
1750{
1751 int ret;
1752 struct msghdr msg;
1753 struct iovec iov;
1754 struct cmsghdr *ptr;
1755 char adata[1024];
1756
1757 msg.msg_name = (void *) from;
1758 msg.msg_namelen = sizeof (struct sockaddr_in);
1759 msg.msg_iov = &iov;
1760 msg.msg_iovlen = 1;
1761 msg.msg_control = (void *) adata;
1762 msg.msg_controllen = sizeof adata;
1763 iov.iov_base = buf;
1764 iov.iov_len = size;
1765
1766 ret = recvmsg (sock, &msg, 0);
1767 if (ret < 0)
1768 return ret;
1769
ajsb99760a2005-01-04 16:24:43 +00001770 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001771 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1772 {
1773 struct in_pktinfo *pktinfo;
1774 int i;
1775
1776 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1777 i = pktinfo->ipi_ifindex;
1778 }
1779 return ret;
1780}
1781
1782/* RIP packet read function. */
1783int
1784rip_read_new (struct thread *t)
1785{
1786 int ret;
1787 int sock;
1788 char buf[RIP_PACKET_MAXSIZ];
1789 struct sockaddr_in from;
1790 unsigned int ifindex;
1791
1792 /* Fetch socket then register myself. */
1793 sock = THREAD_FD (t);
1794 rip_event (RIP_READ, sock);
1795
1796 /* Read RIP packet. */
1797 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1798 if (ret < 0)
1799 {
ajs6099b3b2004-11-20 02:06:59 +00001800 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001801 return ret;
1802 }
1803
1804 return ret;
1805}
1806#endif /* RIP_RECVMSG */
1807
1808/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001809static int
paul718e3742002-12-13 20:15:29 +00001810rip_read (struct thread *t)
1811{
1812 int sock;
1813 int ret;
1814 int rtenum;
1815 union rip_buf rip_buf;
1816 struct rip_packet *packet;
1817 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001818 int len;
1819 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001820 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001821 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001822 struct rip_interface *ri;
1823
1824 /* Fetch socket then register myself. */
1825 sock = THREAD_FD (t);
1826 rip->t_read = NULL;
1827
1828 /* Add myself to tne next event */
1829 rip_event (RIP_READ, sock);
1830
1831 /* RIPd manages only IPv4. */
1832 memset (&from, 0, sizeof (struct sockaddr_in));
1833 fromlen = sizeof (struct sockaddr_in);
1834
1835 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1836 (struct sockaddr *) &from, &fromlen);
1837 if (len < 0)
1838 {
ajs6099b3b2004-11-20 02:06:59 +00001839 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001840 return len;
1841 }
1842
1843 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001844 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001845 {
1846 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001847 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001848 return -1;
1849 }
1850
1851 /* Which interface is this packet comes from. */
1852 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001853
paul718e3742002-12-13 20:15:29 +00001854 /* RIP packet received */
1855 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001856 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001857 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1858 ifp ? ifp->name : "unknown");
1859
1860 /* If this packet come from unknown interface, ignore it. */
1861 if (ifp == NULL)
1862 {
ajs766a0ca2004-12-15 14:55:51 +00001863 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1864 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001865 return -1;
1866 }
1867
1868 ifc = connected_lookup_address (ifp, from.sin_addr);
1869
1870 if (ifc == NULL)
1871 {
ajs766a0ca2004-12-15 14:55:51 +00001872 zlog_info ("rip_read: cannot find connected address for packet from %s "
1873 "port %d on interface %s",
1874 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001875 return -1;
1876 }
1877
1878 /* Packet length check. */
1879 if (len < RIP_PACKET_MINSIZ)
1880 {
1881 zlog_warn ("packet size %d is smaller than minimum size %d",
1882 len, RIP_PACKET_MINSIZ);
1883 rip_peer_bad_packet (&from);
1884 return len;
1885 }
1886 if (len > RIP_PACKET_MAXSIZ)
1887 {
1888 zlog_warn ("packet size %d is larger than max size %d",
1889 len, RIP_PACKET_MAXSIZ);
1890 rip_peer_bad_packet (&from);
1891 return len;
1892 }
1893
1894 /* Packet alignment check. */
1895 if ((len - RIP_PACKET_MINSIZ) % 20)
1896 {
1897 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1898 rip_peer_bad_packet (&from);
1899 return len;
1900 }
1901
1902 /* Set RTE number. */
1903 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1904
1905 /* For easy to handle. */
1906 packet = &rip_buf.rip_packet;
1907
1908 /* RIP version check. */
1909 if (packet->version == 0)
1910 {
1911 zlog_info ("version 0 with command %d received.", packet->command);
1912 rip_peer_bad_packet (&from);
1913 return -1;
1914 }
1915
1916 /* Dump RIP packet. */
1917 if (IS_RIP_DEBUG_RECV)
1918 rip_packet_dump (packet, len, "RECV");
1919
1920 /* RIP version adjust. This code should rethink now. RFC1058 says
1921 that "Version 1 implementations are to ignore this extra data and
1922 process only the fields specified in this document.". So RIPv3
1923 packet should be treated as RIPv1 ignoring must be zero field. */
1924 if (packet->version > RIPv2)
1925 packet->version = RIPv2;
1926
1927 /* Is RIP running or is this RIP neighbor ?*/
1928 ri = ifp->info;
1929 if (! ri->running && ! rip_neighbor_lookup (&from))
1930 {
1931 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001932 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001933 rip_peer_bad_packet (&from);
1934 return -1;
1935 }
1936
1937 /* RIP Version check. */
1938 if (packet->command == RIP_RESPONSE)
1939 {
paulf38a4712003-06-07 01:10:00 +00001940 int vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1941 rip->version_recv : ri->ri_receive);
paul718e3742002-12-13 20:15:29 +00001942 if (packet->version == RIPv1)
paulf38a4712003-06-07 01:10:00 +00001943 if (! (vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001944 {
1945 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001946 zlog_debug (" packet's v%d doesn't fit to if version spec",
paul718e3742002-12-13 20:15:29 +00001947 packet->version);
1948 rip_peer_bad_packet (&from);
1949 return -1;
1950 }
1951 if (packet->version == RIPv2)
paulf38a4712003-06-07 01:10:00 +00001952 if (! (vrecv & RIPv2))
paul718e3742002-12-13 20:15:29 +00001953 {
1954 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001955 zlog_debug (" packet's v%d doesn't fit to if version spec",
paul718e3742002-12-13 20:15:29 +00001956 packet->version);
1957 rip_peer_bad_packet (&from);
1958 return -1;
1959 }
paul718e3742002-12-13 20:15:29 +00001960 }
1961
1962 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1963 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1964 accepted; authenticated RIP-2 messages shall be discarded. */
1965
1966 if ((ri->auth_type == RIP_NO_AUTH)
1967 && rtenum
paulca5e5162004-06-06 22:06:33 +00001968 && (packet->version == RIPv2)
1969 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001970 {
1971 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001972 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001973 packet->version);
1974 rip_peer_bad_packet (&from);
1975 return -1;
1976 }
1977
1978 /* If the router is configured to authenticate RIP-2 messages, then
1979 RIP-1 messages and RIP-2 messages which pass authentication
1980 testing shall be accepted; unauthenticated and failed
1981 authentication RIP-2 messages shall be discarded. For maximum
1982 security, RIP-1 messages should be ignored when authentication is
1983 in use (see section 4.1); otherwise, the routing information from
1984 authenticated messages will be propagated by RIP-1 routers in an
1985 unauthenticated manner. */
1986
1987 if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +00001988 || ri->auth_type == RIP_AUTH_MD5) && rtenum)
paul718e3742002-12-13 20:15:29 +00001989 {
1990 /* We follow maximum security. */
paulca5e5162004-06-06 22:06:33 +00001991 if (packet->version == RIPv1
1992 && packet->rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001993 {
1994 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001995 zlog_debug
paulca5e5162004-06-06 22:06:33 +00001996 ("packet RIPv%d is dropped because authentication enabled",
1997 packet->version);
paul718e3742002-12-13 20:15:29 +00001998 rip_peer_bad_packet (&from);
1999 return -1;
2000 }
2001
2002 /* Check RIPv2 authentication. */
2003 if (packet->version == RIPv2)
2004 {
paulca5e5162004-06-06 22:06:33 +00002005 if (packet->rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00002006 {
paulca5e5162004-06-06 22:06:33 +00002007 if (packet->rte->tag == htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +00002008 {
2009 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2010 if (! ret)
2011 {
2012 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002013 zlog_debug
paulca5e5162004-06-06 22:06:33 +00002014 ("RIPv2 simple password authentication failed");
paul718e3742002-12-13 20:15:29 +00002015 rip_peer_bad_packet (&from);
2016 return -1;
2017 }
2018 else
2019 {
2020 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002021 zlog_debug
paulca5e5162004-06-06 22:06:33 +00002022 ("RIPv2 simple password authentication success");
paul718e3742002-12-13 20:15:29 +00002023 }
2024 }
paulca5e5162004-06-06 22:06:33 +00002025 else if (packet->rte->tag == htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +00002026 {
paulca5e5162004-06-06 22:06:33 +00002027 ret = rip_auth_md5 (packet, &from, len, ifp);
paul718e3742002-12-13 20:15:29 +00002028 if (! ret)
2029 {
2030 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002031 zlog_debug ("RIPv2 MD5 authentication failed");
paul718e3742002-12-13 20:15:29 +00002032 rip_peer_bad_packet (&from);
2033 return -1;
2034 }
2035 else
2036 {
2037 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002038 zlog_debug ("RIPv2 MD5 authentication success");
paul718e3742002-12-13 20:15:29 +00002039 }
2040 /* Reset RIP packet length to trim MD5 data. */
2041 len = ret;
2042 }
2043 else
2044 {
2045 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002046 zlog_debug ("Unknown authentication type %d",
paul718e3742002-12-13 20:15:29 +00002047 ntohs (packet->rte->tag));
2048 rip_peer_bad_packet (&from);
2049 return -1;
2050 }
2051 }
2052 else
2053 {
2054 /* There is no authentication in the packet. */
2055 if (ri->auth_str || ri->key_chain)
2056 {
2057 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002058 zlog_debug
paulca5e5162004-06-06 22:06:33 +00002059 ("RIPv2 authentication failed: no authentication in packet");
paul718e3742002-12-13 20:15:29 +00002060 rip_peer_bad_packet (&from);
2061 return -1;
2062 }
2063 }
2064 }
2065 }
2066
2067 /* Process each command. */
2068 switch (packet->command)
2069 {
2070 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002071 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002072 break;
2073 case RIP_REQUEST:
2074 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002075 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002076 break;
2077 case RIP_TRACEON:
2078 case RIP_TRACEOFF:
2079 zlog_info ("Obsolete command %s received, please sent it to routed",
2080 lookup (rip_msg, packet->command));
2081 rip_peer_bad_packet (&from);
2082 break;
2083 case RIP_POLL_ENTRY:
2084 zlog_info ("Obsolete command %s received",
2085 lookup (rip_msg, packet->command));
2086 rip_peer_bad_packet (&from);
2087 break;
2088 default:
2089 zlog_info ("Unknown RIP command %d received", packet->command);
2090 rip_peer_bad_packet (&from);
2091 break;
2092 }
2093
2094 return len;
2095}
2096
paul718e3742002-12-13 20:15:29 +00002097/* Write routing table entry to the stream and return next index of
2098 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002099static int
paul718e3742002-12-13 20:15:29 +00002100rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002101 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002102{
2103 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002104
2105 /* Write routing table entry. */
2106 if (version == RIPv1)
2107 {
2108 stream_putw (s, AF_INET);
2109 stream_putw (s, 0);
2110 stream_put_ipv4 (s, p->prefix.s_addr);
2111 stream_put_ipv4 (s, 0);
2112 stream_put_ipv4 (s, 0);
2113 stream_putl (s, rinfo->metric_out);
2114 }
2115 else
2116 {
2117 masklen2ip (p->prefixlen, &mask);
2118
2119 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002120 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002121 stream_put_ipv4 (s, p->prefix.s_addr);
2122 stream_put_ipv4 (s, mask.s_addr);
2123 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2124 stream_putl (s, rinfo->metric_out);
2125 }
2126
2127 return ++num;
2128}
2129
2130/* Send update to the ifp or spcified neighbor. */
2131void
paulc49ad8f2004-10-22 10:27:28 +00002132rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2133 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002134{
2135 int ret;
2136 struct stream *s;
2137 struct route_node *rp;
2138 struct rip_info *rinfo;
2139 struct rip_interface *ri;
2140 struct prefix_ipv4 *p;
2141 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002142 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002143 struct key *key = NULL;
2144 /* this might need to made dynamic if RIP ever supported auth methods
2145 with larger key string sizes */
2146 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002147 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002148 int num = 0;
paul718e3742002-12-13 20:15:29 +00002149 int rtemax;
paul01d09082003-06-08 21:22:18 +00002150 int subnetted = 0;
paul718e3742002-12-13 20:15:29 +00002151
2152 /* Logging output event. */
2153 if (IS_RIP_DEBUG_EVENT)
2154 {
2155 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002156 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002157 else
ajs5d6c3772004-12-08 19:24:06 +00002158 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002159 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002160 }
2161
2162 /* Set output stream. */
2163 s = rip->obuf;
2164
2165 /* Reset stream and RTE counter. */
2166 stream_reset (s);
paul718e3742002-12-13 20:15:29 +00002167 rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
2168
2169 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002170 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002171
2172 /* If output interface is in simple password authentication mode, we
2173 need space for authentication data. */
2174 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2175 rtemax -= 1;
2176
2177 /* If output interface is in MD5 authentication mode, we need space
2178 for authentication header and data. */
2179 if (ri->auth_type == RIP_AUTH_MD5)
2180 rtemax -= 2;
2181
2182 /* If output interface is in simple password authentication mode
2183 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002184 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002185 {
2186 if (ri->key_chain)
2187 {
2188 struct keychain *keychain;
2189
2190 keychain = keychain_lookup (ri->key_chain);
2191 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002192 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002193 }
paulb14ee002005-02-04 23:42:41 +00002194 /* to be passed to auth functions later */
2195 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002196 }
2197
paul727d1042002-12-13 20:50:29 +00002198 if (version == RIPv1)
2199 {
paulc49ad8f2004-10-22 10:27:28 +00002200 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002201 apply_classful_mask_ipv4 (&ifaddrclass);
2202 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002203 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002204 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002205 }
2206
paul718e3742002-12-13 20:15:29 +00002207 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2208 if ((rinfo = rp->info) != NULL)
2209 {
paul727d1042002-12-13 20:50:29 +00002210 /* For RIPv1, if we are subnetted, output subnets in our network */
2211 /* that have the same mask as the output "interface". For other */
2212 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002213
2214 if (version == RIPv1)
2215 {
paul727d1042002-12-13 20:50:29 +00002216 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002217
2218 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002219 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002220 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002221
paul727d1042002-12-13 20:50:29 +00002222 if (subnetted &&
2223 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2224 {
paulc49ad8f2004-10-22 10:27:28 +00002225 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002226 (rp->p.prefixlen != 32))
2227 continue;
2228 }
2229 else
2230 {
2231 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2232 apply_classful_mask_ipv4(&classfull);
2233 if (rp->p.u.prefix4.s_addr != 0 &&
2234 classfull.prefixlen != rp->p.prefixlen)
2235 continue;
2236 }
paul718e3742002-12-13 20:15:29 +00002237 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002238 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002239 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002240 }
2241 else
2242 p = (struct prefix_ipv4 *) &rp->p;
2243
2244 /* Apply output filters. */
2245 ret = rip_outgoing_filter (p, ri);
2246 if (ret < 0)
2247 continue;
2248
2249 /* Changed route only output. */
2250 if (route_type == rip_changed_route &&
2251 (! (rinfo->flags & RIP_RTF_CHANGED)))
2252 continue;
2253
2254 /* Split horizon. */
2255 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002256 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002257 {
paul42d14d92003-11-17 09:15:18 +00002258 /*
2259 * We perform split horizon for RIP and connected route.
2260 * For rip routes, we want to suppress the route if we would
2261 * end up sending the route back on the interface that we
2262 * learned it from, with a higher metric. For connected routes,
2263 * we suppress the route if the prefix is a subset of the
2264 * source address that we are going to use for the packet
2265 * (in order to handle the case when multiple subnets are
2266 * configured on the same interface).
2267 */
2268 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002269 rinfo->ifindex == ifc->ifp->ifindex)
paul42d14d92003-11-17 09:15:18 +00002270 continue;
2271 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002272 prefix_match((struct prefix *)p, ifc->address))
paul718e3742002-12-13 20:15:29 +00002273 continue;
2274 }
2275
2276 /* Preparation for route-map. */
2277 rinfo->metric_set = 0;
2278 rinfo->nexthop_out.s_addr = 0;
2279 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002280 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002281 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002282
hasso16705132003-05-25 14:49:19 +00002283 /* In order to avoid some local loops,
2284 * if the RIP route has a nexthop via this interface, keep the nexthop,
2285 * otherwise set it to 0. The nexthop should not be propagated
2286 * beyond the local broadcast/multicast area in order
2287 * to avoid an IGP multi-level recursive look-up.
2288 * see (4.4)
2289 */
paulc49ad8f2004-10-22 10:27:28 +00002290 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002291 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002292
2293 /* Interface route-map */
2294 if (ri->routemap[RIP_FILTER_OUT])
2295 {
2296 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2297 (struct prefix *) p, RMAP_RIP,
2298 rinfo);
2299
2300 if (ret == RMAP_DENYMATCH)
2301 {
2302 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002303 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002304 inet_ntoa (p->prefix), p->prefixlen);
2305 continue;
2306 }
2307 }
paul718e3742002-12-13 20:15:29 +00002308
hasso16705132003-05-25 14:49:19 +00002309 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002310 if (rip->route_map[rinfo->type].name
2311 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2312 {
2313 ret = route_map_apply (rip->route_map[rinfo->type].map,
2314 (struct prefix *)p, RMAP_RIP, rinfo);
2315
2316 if (ret == RMAP_DENYMATCH)
2317 {
2318 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002319 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002320 inet_ntoa (p->prefix), p->prefixlen);
2321 continue;
2322 }
2323 }
2324
2325 /* When route-map does not set metric. */
2326 if (! rinfo->metric_set)
2327 {
2328 /* If redistribute metric is set. */
2329 if (rip->route_map[rinfo->type].metric_config
2330 && rinfo->metric != RIP_METRIC_INFINITY)
2331 {
2332 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2333 }
2334 else
2335 {
2336 /* If the route is not connected or localy generated
2337 one, use default-metric value*/
2338 if (rinfo->type != ZEBRA_ROUTE_RIP
2339 && rinfo->type != ZEBRA_ROUTE_CONNECT
2340 && rinfo->metric != RIP_METRIC_INFINITY)
2341 rinfo->metric_out = rip->default_metric;
2342 }
2343 }
2344
2345 /* Apply offset-list */
2346 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002347 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002348
2349 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2350 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002351
2352 /* Perform split-horizon with poisoned reverse
2353 * for RIP and connected routes.
2354 **/
2355 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002356 /*
2357 * We perform split horizon for RIP and connected route.
2358 * For rip routes, we want to suppress the route if we would
2359 * end up sending the route back on the interface that we
2360 * learned it from, with a higher metric. For connected routes,
2361 * we suppress the route if the prefix is a subset of the
2362 * source address that we are going to use for the packet
2363 * (in order to handle the case when multiple subnets are
2364 * configured on the same interface).
2365 */
2366 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002367 rinfo->ifindex == ifc->ifp->ifindex)
hasso16705132003-05-25 14:49:19 +00002368 rinfo->metric_out = RIP_METRIC_INFINITY;
paul42d14d92003-11-17 09:15:18 +00002369 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002370 prefix_match((struct prefix *)p, ifc->address))
paul42d14d92003-11-17 09:15:18 +00002371 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002372 }
paulb14ee002005-02-04 23:42:41 +00002373
2374 /* Prepare preamble, auth headers, if needs be */
2375 if (num == 0)
2376 {
2377 stream_putc (s, RIP_RESPONSE);
2378 stream_putc (s, version);
2379 stream_putw (s, 0);
2380
paul0cb8a012005-05-29 11:27:24 +00002381 /* auth header for !v1 && !no_auth */
2382 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002383 doff = rip_auth_header_write (s, ri, key, auth_str,
2384 RIP_AUTH_SIMPLE_SIZE);
2385 }
2386
paul718e3742002-12-13 20:15:29 +00002387 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002388 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002389 if (num == rtemax)
2390 {
2391 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002392 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002393
2394 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002395 to, ifc);
paul718e3742002-12-13 20:15:29 +00002396
2397 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2398 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2399 stream_get_endp(s), "SEND");
2400 num = 0;
2401 stream_reset (s);
2402 }
2403 }
2404
2405 /* Flush unwritten RTE. */
2406 if (num != 0)
2407 {
2408 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002409 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002410
paulc49ad8f2004-10-22 10:27:28 +00002411 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002412
2413 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2414 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2415 stream_get_endp (s), "SEND");
2416 num = 0;
2417 stream_reset (s);
2418 }
2419
2420 /* Statistics updates. */
2421 ri->sent_updates++;
2422}
2423
2424/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002425static void
paulc49ad8f2004-10-22 10:27:28 +00002426rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002427{
paul718e3742002-12-13 20:15:29 +00002428 struct sockaddr_in to;
2429
2430 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002431 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002432 {
2433 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002434 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002435
paulc49ad8f2004-10-22 10:27:28 +00002436 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002437 return;
2438 }
paulc49ad8f2004-10-22 10:27:28 +00002439
paul718e3742002-12-13 20:15:29 +00002440 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002441 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002442 {
paulc49ad8f2004-10-22 10:27:28 +00002443 if (ifc->address->family == AF_INET)
2444 {
2445 /* Destination address and port setting. */
2446 memset (&to, 0, sizeof (struct sockaddr_in));
2447 if (ifc->destination)
2448 /* use specified broadcast or point-to-point destination addr */
2449 to.sin_addr = ifc->destination->u.prefix4;
2450 else
2451 /* calculate the appropriate broadcast address */
2452 to.sin_addr.s_addr =
2453 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2454 ifc->address->prefixlen);
2455 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002456
paulc49ad8f2004-10-22 10:27:28 +00002457 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002458 zlog_debug ("%s announce to %s on %s",
paulc49ad8f2004-10-22 10:27:28 +00002459 if_is_pointopoint (ifc->ifp) ? "unicast" : "broadcast",
2460 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002461
paulc49ad8f2004-10-22 10:27:28 +00002462 rip_output_process (ifc, &to, route_type, version);
2463 }
paul718e3742002-12-13 20:15:29 +00002464 }
2465}
2466
2467/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002468static void
paul718e3742002-12-13 20:15:29 +00002469rip_update_process (int route_type)
2470{
paul1eb8ef22005-04-07 07:30:20 +00002471 struct listnode *node;
2472 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002473 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002474 struct interface *ifp;
2475 struct rip_interface *ri;
2476 struct route_node *rp;
2477 struct sockaddr_in to;
2478 struct prefix_ipv4 *p;
2479
2480 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002481 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002482 {
paul718e3742002-12-13 20:15:29 +00002483 if (if_is_loopback (ifp))
2484 continue;
2485
paul2e3b2e42002-12-13 21:03:13 +00002486 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002487 continue;
2488
2489 /* Fetch RIP interface information. */
2490 ri = ifp->info;
2491
2492 /* When passive interface is specified, suppress announce to the
2493 interface. */
2494 if (ri->passive)
2495 continue;
2496
2497 if (ri->running)
2498 {
2499 if (IS_RIP_DEBUG_EVENT)
2500 {
2501 if (ifp->name)
ajs5d6c3772004-12-08 19:24:06 +00002502 zlog_debug ("SEND UPDATE to %s ifindex %d",
paul718e3742002-12-13 20:15:29 +00002503 ifp->name, ifp->ifindex);
2504 else
ajs5d6c3772004-12-08 19:24:06 +00002505 zlog_debug ("SEND UPDATE to _unknown_ ifindex %d",
paul718e3742002-12-13 20:15:29 +00002506 ifp->ifindex);
2507 }
2508
paulcc1131a2003-10-15 23:20:17 +00002509 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002510 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002511 {
2512 struct prefix_ipv4 *ifaddr;
paul931cd542004-01-23 15:31:42 +00002513 int done = 0;
2514 /*
2515 * If there is no version configuration in the interface,
2516 * use rip's version setting.
2517 */
paulf38a4712003-06-07 01:10:00 +00002518 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2519 rip->version_send : ri->ri_send);
paulcc1131a2003-10-15 23:20:17 +00002520
2521 ifaddr = (struct prefix_ipv4 *) connected->address;
2522
2523 if (ifaddr->family != AF_INET)
2524 continue;
2525
paul931cd542004-01-23 15:31:42 +00002526 if ((vsend & RIPv1) && !done)
paulc49ad8f2004-10-22 10:27:28 +00002527 rip_update_interface (connected, RIPv1, route_type);
paul931cd542004-01-23 15:31:42 +00002528 if ((vsend & RIPv2) && if_is_multicast(ifp))
paulc49ad8f2004-10-22 10:27:28 +00002529 rip_update_interface (connected, RIPv2, route_type);
paul931cd542004-01-23 15:31:42 +00002530 done = 1;
2531 if (!(vsend & RIPv2) || !if_is_multicast(ifp))
2532 break;
2533
paulf38a4712003-06-07 01:10:00 +00002534 }
paul718e3742002-12-13 20:15:29 +00002535 }
2536 }
2537
2538 /* RIP send updates to each neighbor. */
2539 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2540 if (rp->info != NULL)
2541 {
2542 p = (struct prefix_ipv4 *) &rp->p;
2543
2544 ifp = if_lookup_address (p->prefix);
2545 if (! ifp)
2546 {
paulc49ad8f2004-10-22 10:27:28 +00002547 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002548 inet_ntoa (p->prefix));
2549 continue;
2550 }
paulc49ad8f2004-10-22 10:27:28 +00002551
2552 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2553 {
2554 zlog_warn ("Neighbor %s doesnt have connected network",
2555 inet_ntoa (p->prefix));
2556 continue;
2557 }
2558
paul718e3742002-12-13 20:15:29 +00002559 /* Set destination address and port */
2560 memset (&to, 0, sizeof (struct sockaddr_in));
2561 to.sin_addr = p->prefix;
2562 to.sin_port = htons (RIP_PORT_DEFAULT);
2563
2564 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002565 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002566 }
2567}
2568
2569/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002570static int
paul718e3742002-12-13 20:15:29 +00002571rip_update (struct thread *t)
2572{
2573 /* Clear timer pointer. */
2574 rip->t_update = NULL;
2575
2576 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002577 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002578
2579 /* Process update output. */
2580 rip_update_process (rip_all_route);
2581
2582 /* Triggered updates may be suppressed if a regular update is due by
2583 the time the triggered update would be sent. */
2584 if (rip->t_triggered_interval)
2585 {
2586 thread_cancel (rip->t_triggered_interval);
2587 rip->t_triggered_interval = NULL;
2588 }
2589 rip->trigger = 0;
2590
2591 /* Register myself. */
2592 rip_event (RIP_UPDATE_EVENT, 0);
2593
2594 return 0;
2595}
2596
2597/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002598static void
paul216565a2005-10-25 23:35:28 +00002599rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002600{
2601 struct route_node *rp;
2602 struct rip_info *rinfo;
2603
2604 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2605 if ((rinfo = rp->info) != NULL)
2606 if (rinfo->flags & RIP_RTF_CHANGED)
2607 rinfo->flags &= ~RIP_RTF_CHANGED;
2608}
2609
2610/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002611static int
paul718e3742002-12-13 20:15:29 +00002612rip_triggered_interval (struct thread *t)
2613{
2614 int rip_triggered_update (struct thread *);
2615
2616 rip->t_triggered_interval = NULL;
2617
2618 if (rip->trigger)
2619 {
2620 rip->trigger = 0;
2621 rip_triggered_update (t);
2622 }
2623 return 0;
2624}
2625
2626/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002627static int
paul718e3742002-12-13 20:15:29 +00002628rip_triggered_update (struct thread *t)
2629{
2630 int interval;
2631
2632 /* Clear thred pointer. */
2633 rip->t_triggered_update = NULL;
2634
2635 /* Cancel interval timer. */
2636 if (rip->t_triggered_interval)
2637 {
2638 thread_cancel (rip->t_triggered_interval);
2639 rip->t_triggered_interval = NULL;
2640 }
2641 rip->trigger = 0;
2642
2643 /* Logging triggered update. */
2644 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002645 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002646
2647 /* Split Horizon processing is done when generating triggered
2648 updates as well as normal updates (see section 2.6). */
2649 rip_update_process (rip_changed_route);
2650
2651 /* Once all of the triggered updates have been generated, the route
2652 change flags should be cleared. */
2653 rip_clear_changed_flag ();
2654
2655 /* After a triggered update is sent, a timer should be set for a
2656 random interval between 1 and 5 seconds. If other changes that
2657 would trigger updates occur before the timer expires, a single
2658 update is triggered when the timer expires. */
2659 interval = (random () % 5) + 1;
2660
2661 rip->t_triggered_interval =
2662 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2663
2664 return 0;
2665}
2666
2667/* Withdraw redistributed route. */
2668void
2669rip_redistribute_withdraw (int type)
2670{
2671 struct route_node *rp;
2672 struct rip_info *rinfo;
2673
2674 if (!rip)
2675 return;
2676
2677 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2678 if ((rinfo = rp->info) != NULL)
2679 {
2680 if (rinfo->type == type
2681 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2682 {
2683 /* Perform poisoned reverse. */
2684 rinfo->metric = RIP_METRIC_INFINITY;
2685 RIP_TIMER_ON (rinfo->t_garbage_collect,
2686 rip_garbage_collect, rip->garbage_time);
2687 RIP_TIMER_OFF (rinfo->t_timeout);
2688 rinfo->flags |= RIP_RTF_CHANGED;
2689
hasso16705132003-05-25 14:49:19 +00002690 if (IS_RIP_DEBUG_EVENT) {
2691 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2692
ajs5d6c3772004-12-08 19:24:06 +00002693 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002694 inet_ntoa(p->prefix), p->prefixlen,
2695 ifindex2ifname(rinfo->ifindex));
2696 }
2697
paul718e3742002-12-13 20:15:29 +00002698 rip_event (RIP_TRIGGERED_UPDATE, 0);
2699 }
2700 }
2701}
2702
2703/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002704static int
2705rip_create (void)
paul718e3742002-12-13 20:15:29 +00002706{
2707 rip = XMALLOC (MTYPE_RIP, sizeof (struct rip));
2708 memset (rip, 0, sizeof (struct rip));
2709
2710 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002711 rip->version_send = RI_RIP_VERSION_2;
2712 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002713 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2714 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2715 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2716 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2717
2718 /* Initialize RIP routig table. */
2719 rip->table = route_table_init ();
2720 rip->route = route_table_init ();
2721 rip->neighbor = route_table_init ();
2722
2723 /* Make output stream. */
2724 rip->obuf = stream_new (1500);
2725
2726 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002727 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002728 if (rip->sock < 0)
2729 return rip->sock;
2730
2731 /* Create read and timer thread. */
2732 rip_event (RIP_READ, rip->sock);
2733 rip_event (RIP_UPDATE_EVENT, 1);
2734
2735 return 0;
2736}
2737
2738/* Sned RIP request to the destination. */
2739int
2740rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002741 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002742{
2743 struct rte *rte;
2744 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002745 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002746
2747 memset (&rip_packet, 0, sizeof (rip_packet));
2748
2749 rip_packet.command = RIP_REQUEST;
2750 rip_packet.version = version;
2751 rte = rip_packet.rte;
2752 rte->metric = htonl (RIP_METRIC_INFINITY);
2753
paul931cd542004-01-23 15:31:42 +00002754 if (connected)
2755 {
2756 /*
2757 * connected is only sent for ripv1 case, or when
2758 * interface does not support multicast. Caller loops
2759 * over each connected address for this case.
2760 */
paul11dde9c2004-05-31 14:00:00 +00002761 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002762 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002763 return -1;
2764 else
2765 return sizeof (rip_packet);
2766 }
2767
paulcc1131a2003-10-15 23:20:17 +00002768 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002769 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002770 {
2771 struct prefix_ipv4 *p;
2772
2773 p = (struct prefix_ipv4 *) connected->address;
2774
2775 if (p->family != AF_INET)
2776 continue;
2777
paul11dde9c2004-05-31 14:00:00 +00002778 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002779 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002780 return -1;
2781 }
2782 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002783}
2784
pauldc63bfd2005-10-25 23:31:05 +00002785static int
paul718e3742002-12-13 20:15:29 +00002786rip_update_jitter (unsigned long time)
2787{
paul239389b2004-05-05 14:09:37 +00002788#define JITTER_BOUND 4
2789 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2790 Given that, we cannot let time be less than JITTER_BOUND seconds.
2791 The RIPv2 RFC says jitter should be small compared to
2792 update_time. We consider 1/JITTER_BOUND to be small.
2793 */
2794
2795 int jitter_input = time;
2796 int jitter;
2797
2798 if (jitter_input < JITTER_BOUND)
2799 jitter_input = JITTER_BOUND;
2800
2801 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2802
2803 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002804}
2805
2806void
2807rip_event (enum rip_event event, int sock)
2808{
2809 int jitter = 0;
2810
2811 switch (event)
2812 {
2813 case RIP_READ:
2814 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2815 break;
2816 case RIP_UPDATE_EVENT:
2817 if (rip->t_update)
2818 {
2819 thread_cancel (rip->t_update);
2820 rip->t_update = NULL;
2821 }
2822 jitter = rip_update_jitter (rip->update_time);
2823 rip->t_update =
2824 thread_add_timer (master, rip_update, NULL,
2825 sock ? 2 : rip->update_time + jitter);
2826 break;
2827 case RIP_TRIGGERED_UPDATE:
2828 if (rip->t_triggered_interval)
2829 rip->trigger = 1;
2830 else if (! rip->t_triggered_update)
2831 rip->t_triggered_update =
2832 thread_add_event (master, rip_triggered_update, NULL, 0);
2833 break;
2834 default:
2835 break;
2836 }
2837}
2838
2839DEFUN (router_rip,
2840 router_rip_cmd,
2841 "router rip",
2842 "Enable a routing process\n"
2843 "Routing Information Protocol (RIP)\n")
2844{
2845 int ret;
2846
2847 /* If rip is not enabled before. */
2848 if (! rip)
2849 {
2850 ret = rip_create ();
2851 if (ret < 0)
2852 {
2853 zlog_info ("Can't create RIP");
2854 return CMD_WARNING;
2855 }
2856 }
2857 vty->node = RIP_NODE;
2858 vty->index = rip;
2859
2860 return CMD_SUCCESS;
2861}
2862
2863DEFUN (no_router_rip,
2864 no_router_rip_cmd,
2865 "no router rip",
2866 NO_STR
2867 "Enable a routing process\n"
2868 "Routing Information Protocol (RIP)\n")
2869{
2870 if (rip)
2871 rip_clean ();
2872 return CMD_SUCCESS;
2873}
2874
2875DEFUN (rip_version,
2876 rip_version_cmd,
2877 "version <1-2>",
2878 "Set routing protocol version\n"
2879 "version\n")
2880{
2881 int version;
2882
2883 version = atoi (argv[0]);
2884 if (version != RIPv1 && version != RIPv2)
2885 {
2886 vty_out (vty, "invalid rip version %d%s", version,
2887 VTY_NEWLINE);
2888 return CMD_WARNING;
2889 }
paulf38a4712003-06-07 01:10:00 +00002890 rip->version_send = version;
2891 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002892
2893 return CMD_SUCCESS;
2894}
2895
2896DEFUN (no_rip_version,
2897 no_rip_version_cmd,
2898 "no version",
2899 NO_STR
2900 "Set routing protocol version\n")
2901{
2902 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002903 rip->version_send = RI_RIP_VERSION_2;
2904 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002905
2906 return CMD_SUCCESS;
2907}
2908
2909ALIAS (no_rip_version,
2910 no_rip_version_val_cmd,
2911 "no version <1-2>",
2912 NO_STR
2913 "Set routing protocol version\n"
2914 "version\n")
2915
2916DEFUN (rip_route,
2917 rip_route_cmd,
2918 "route A.B.C.D/M",
2919 "RIP static route configuration\n"
2920 "IP prefix <network>/<length>\n")
2921{
2922 int ret;
2923 struct prefix_ipv4 p;
2924 struct route_node *node;
2925
2926 ret = str2prefix_ipv4 (argv[0], &p);
2927 if (ret < 0)
2928 {
2929 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2930 return CMD_WARNING;
2931 }
2932 apply_mask_ipv4 (&p);
2933
2934 /* For router rip configuration. */
2935 node = route_node_get (rip->route, (struct prefix *) &p);
2936
2937 if (node->info)
2938 {
2939 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2940 route_unlock_node (node);
2941 return CMD_WARNING;
2942 }
2943
hasso8a676be2004-10-08 06:36:38 +00002944 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002945
vincentfbf5d032005-09-29 11:25:50 +00002946 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002947
2948 return CMD_SUCCESS;
2949}
2950
2951DEFUN (no_rip_route,
2952 no_rip_route_cmd,
2953 "no route A.B.C.D/M",
2954 NO_STR
2955 "RIP static route configuration\n"
2956 "IP prefix <network>/<length>\n")
2957{
2958 int ret;
2959 struct prefix_ipv4 p;
2960 struct route_node *node;
2961
2962 ret = str2prefix_ipv4 (argv[0], &p);
2963 if (ret < 0)
2964 {
2965 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2966 return CMD_WARNING;
2967 }
2968 apply_mask_ipv4 (&p);
2969
2970 /* For router rip configuration. */
2971 node = route_node_lookup (rip->route, (struct prefix *) &p);
2972 if (! node)
2973 {
2974 vty_out (vty, "Can't find route %s.%s", argv[0],
2975 VTY_NEWLINE);
2976 return CMD_WARNING;
2977 }
2978
2979 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2980 route_unlock_node (node);
2981
2982 node->info = NULL;
2983 route_unlock_node (node);
2984
2985 return CMD_SUCCESS;
2986}
2987
pauldc63bfd2005-10-25 23:31:05 +00002988static void
paul216565a2005-10-25 23:35:28 +00002989rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002990{
2991 struct route_node *np;
2992 struct rip_info *rinfo;
2993
2994 for (np = route_top (rip->table); np; np = route_next (np))
2995 if ((rinfo = np->info) != NULL)
2996 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2997 rinfo->metric = rip->default_metric;
2998}
2999
3000DEFUN (rip_default_metric,
3001 rip_default_metric_cmd,
3002 "default-metric <1-16>",
3003 "Set a metric of redistribute routes\n"
3004 "Default metric\n")
3005{
3006 if (rip)
3007 {
3008 rip->default_metric = atoi (argv[0]);
3009 /* rip_update_default_metric (); */
3010 }
3011 return CMD_SUCCESS;
3012}
3013
3014DEFUN (no_rip_default_metric,
3015 no_rip_default_metric_cmd,
3016 "no default-metric",
3017 NO_STR
3018 "Set a metric of redistribute routes\n"
3019 "Default metric\n")
3020{
3021 if (rip)
3022 {
3023 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3024 /* rip_update_default_metric (); */
3025 }
3026 return CMD_SUCCESS;
3027}
3028
3029ALIAS (no_rip_default_metric,
3030 no_rip_default_metric_val_cmd,
3031 "no default-metric <1-16>",
3032 NO_STR
3033 "Set a metric of redistribute routes\n"
3034 "Default metric\n")
3035
3036DEFUN (rip_timers,
3037 rip_timers_cmd,
3038 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3039 "Adjust routing timers\n"
3040 "Basic routing protocol update timers\n"
3041 "Routing table update timer value in second. Default is 30.\n"
3042 "Routing information timeout timer. Default is 180.\n"
3043 "Garbage collection timer. Default is 120.\n")
3044{
3045 unsigned long update;
3046 unsigned long timeout;
3047 unsigned long garbage;
3048 char *endptr = NULL;
3049 unsigned long RIP_TIMER_MAX = 2147483647;
3050 unsigned long RIP_TIMER_MIN = 5;
3051
3052 update = strtoul (argv[0], &endptr, 10);
3053 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3054 {
3055 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3056 return CMD_WARNING;
3057 }
3058
3059 timeout = strtoul (argv[1], &endptr, 10);
3060 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3061 {
3062 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3063 return CMD_WARNING;
3064 }
3065
3066 garbage = strtoul (argv[2], &endptr, 10);
3067 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3068 {
3069 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3070 return CMD_WARNING;
3071 }
3072
3073 /* Set each timer value. */
3074 rip->update_time = update;
3075 rip->timeout_time = timeout;
3076 rip->garbage_time = garbage;
3077
3078 /* Reset update timer thread. */
3079 rip_event (RIP_UPDATE_EVENT, 0);
3080
3081 return CMD_SUCCESS;
3082}
3083
3084DEFUN (no_rip_timers,
3085 no_rip_timers_cmd,
3086 "no timers basic",
3087 NO_STR
3088 "Adjust routing timers\n"
3089 "Basic routing protocol update timers\n")
3090{
3091 /* Set each timer value to the default. */
3092 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3093 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3094 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3095
3096 /* Reset update timer thread. */
3097 rip_event (RIP_UPDATE_EVENT, 0);
3098
3099 return CMD_SUCCESS;
3100}
hasso16705132003-05-25 14:49:19 +00003101
3102ALIAS (no_rip_timers,
3103 no_rip_timers_val_cmd,
3104 "no timers basic <0-65535> <0-65535> <0-65535>",
3105 NO_STR
3106 "Adjust routing timers\n"
3107 "Basic routing protocol update timers\n"
3108 "Routing table update timer value in second. Default is 30.\n"
3109 "Routing information timeout timer. Default is 180.\n"
3110 "Garbage collection timer. Default is 120.\n")
3111
paul718e3742002-12-13 20:15:29 +00003112
3113struct route_table *rip_distance_table;
3114
3115struct rip_distance
3116{
3117 /* Distance value for the IP source prefix. */
3118 u_char distance;
3119
3120 /* Name of the access-list to be matched. */
3121 char *access_list;
3122};
3123
pauldc63bfd2005-10-25 23:31:05 +00003124static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003125rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003126{
3127 struct rip_distance *new;
3128 new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
3129 memset (new, 0, sizeof (struct rip_distance));
3130 return new;
3131}
3132
pauldc63bfd2005-10-25 23:31:05 +00003133static void
paul718e3742002-12-13 20:15:29 +00003134rip_distance_free (struct rip_distance *rdistance)
3135{
3136 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3137}
3138
pauldc63bfd2005-10-25 23:31:05 +00003139static int
hasso98b718a2004-10-11 12:57:57 +00003140rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3141 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003142{
3143 int ret;
3144 struct prefix_ipv4 p;
3145 u_char distance;
3146 struct route_node *rn;
3147 struct rip_distance *rdistance;
3148
3149 ret = str2prefix_ipv4 (ip_str, &p);
3150 if (ret == 0)
3151 {
3152 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3153 return CMD_WARNING;
3154 }
3155
3156 distance = atoi (distance_str);
3157
3158 /* Get RIP distance node. */
3159 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3160 if (rn->info)
3161 {
3162 rdistance = rn->info;
3163 route_unlock_node (rn);
3164 }
3165 else
3166 {
3167 rdistance = rip_distance_new ();
3168 rn->info = rdistance;
3169 }
3170
3171 /* Set distance value. */
3172 rdistance->distance = distance;
3173
3174 /* Reset access-list configuration. */
3175 if (rdistance->access_list)
3176 {
3177 free (rdistance->access_list);
3178 rdistance->access_list = NULL;
3179 }
3180 if (access_list_str)
3181 rdistance->access_list = strdup (access_list_str);
3182
3183 return CMD_SUCCESS;
3184}
3185
pauldc63bfd2005-10-25 23:31:05 +00003186static int
hasso98b718a2004-10-11 12:57:57 +00003187rip_distance_unset (struct vty *vty, const char *distance_str,
3188 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003189{
3190 int ret;
3191 struct prefix_ipv4 p;
3192 u_char distance;
3193 struct route_node *rn;
3194 struct rip_distance *rdistance;
3195
3196 ret = str2prefix_ipv4 (ip_str, &p);
3197 if (ret == 0)
3198 {
3199 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3200 return CMD_WARNING;
3201 }
3202
3203 distance = atoi (distance_str);
3204
3205 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3206 if (! rn)
3207 {
3208 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3209 return CMD_WARNING;
3210 }
3211
3212 rdistance = rn->info;
3213
3214 if (rdistance->access_list)
3215 free (rdistance->access_list);
3216 rip_distance_free (rdistance);
3217
3218 rn->info = NULL;
3219 route_unlock_node (rn);
3220 route_unlock_node (rn);
3221
3222 return CMD_SUCCESS;
3223}
3224
pauldc63bfd2005-10-25 23:31:05 +00003225static void
paul216565a2005-10-25 23:35:28 +00003226rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003227{
3228 struct route_node *rn;
3229 struct rip_distance *rdistance;
3230
3231 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3232 if ((rdistance = rn->info) != NULL)
3233 {
3234 if (rdistance->access_list)
3235 free (rdistance->access_list);
3236 rip_distance_free (rdistance);
3237 rn->info = NULL;
3238 route_unlock_node (rn);
3239 }
3240}
3241
3242/* Apply RIP information to distance method. */
3243u_char
3244rip_distance_apply (struct rip_info *rinfo)
3245{
3246 struct route_node *rn;
3247 struct prefix_ipv4 p;
3248 struct rip_distance *rdistance;
3249 struct access_list *alist;
3250
3251 if (! rip)
3252 return 0;
3253
3254 memset (&p, 0, sizeof (struct prefix_ipv4));
3255 p.family = AF_INET;
3256 p.prefix = rinfo->from;
3257 p.prefixlen = IPV4_MAX_BITLEN;
3258
3259 /* Check source address. */
3260 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3261 if (rn)
3262 {
3263 rdistance = rn->info;
3264 route_unlock_node (rn);
3265
3266 if (rdistance->access_list)
3267 {
3268 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3269 if (alist == NULL)
3270 return 0;
3271 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3272 return 0;
3273
3274 return rdistance->distance;
3275 }
3276 else
3277 return rdistance->distance;
3278 }
3279
3280 if (rip->distance)
3281 return rip->distance;
3282
3283 return 0;
3284}
3285
pauldc63bfd2005-10-25 23:31:05 +00003286static void
paul718e3742002-12-13 20:15:29 +00003287rip_distance_show (struct vty *vty)
3288{
3289 struct route_node *rn;
3290 struct rip_distance *rdistance;
3291 int header = 1;
3292 char buf[BUFSIZ];
3293
3294 vty_out (vty, " Distance: (default is %d)%s",
3295 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3296 VTY_NEWLINE);
3297
3298 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3299 if ((rdistance = rn->info) != NULL)
3300 {
3301 if (header)
3302 {
3303 vty_out (vty, " Address Distance List%s",
3304 VTY_NEWLINE);
3305 header = 0;
3306 }
3307 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3308 vty_out (vty, " %-20s %4d %s%s",
3309 buf, rdistance->distance,
3310 rdistance->access_list ? rdistance->access_list : "",
3311 VTY_NEWLINE);
3312 }
3313}
3314
3315DEFUN (rip_distance,
3316 rip_distance_cmd,
3317 "distance <1-255>",
3318 "Administrative distance\n"
3319 "Distance value\n")
3320{
3321 rip->distance = atoi (argv[0]);
3322 return CMD_SUCCESS;
3323}
3324
3325DEFUN (no_rip_distance,
3326 no_rip_distance_cmd,
3327 "no distance <1-255>",
3328 NO_STR
3329 "Administrative distance\n"
3330 "Distance value\n")
3331{
3332 rip->distance = 0;
3333 return CMD_SUCCESS;
3334}
3335
3336DEFUN (rip_distance_source,
3337 rip_distance_source_cmd,
3338 "distance <1-255> A.B.C.D/M",
3339 "Administrative distance\n"
3340 "Distance value\n"
3341 "IP source prefix\n")
3342{
3343 rip_distance_set (vty, argv[0], argv[1], NULL);
3344 return CMD_SUCCESS;
3345}
3346
3347DEFUN (no_rip_distance_source,
3348 no_rip_distance_source_cmd,
3349 "no distance <1-255> A.B.C.D/M",
3350 NO_STR
3351 "Administrative distance\n"
3352 "Distance value\n"
3353 "IP source prefix\n")
3354{
3355 rip_distance_unset (vty, argv[0], argv[1], NULL);
3356 return CMD_SUCCESS;
3357}
3358
3359DEFUN (rip_distance_source_access_list,
3360 rip_distance_source_access_list_cmd,
3361 "distance <1-255> A.B.C.D/M WORD",
3362 "Administrative distance\n"
3363 "Distance value\n"
3364 "IP source prefix\n"
3365 "Access list name\n")
3366{
3367 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3368 return CMD_SUCCESS;
3369}
3370
3371DEFUN (no_rip_distance_source_access_list,
3372 no_rip_distance_source_access_list_cmd,
3373 "no distance <1-255> A.B.C.D/M WORD",
3374 NO_STR
3375 "Administrative distance\n"
3376 "Distance value\n"
3377 "IP source prefix\n"
3378 "Access list name\n")
3379{
3380 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3381 return CMD_SUCCESS;
3382}
3383
3384/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003385static void
paul718e3742002-12-13 20:15:29 +00003386rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3387{
3388 struct timeval timer_now;
3389 time_t clock;
3390 struct tm *tm;
3391#define TIME_BUF 25
3392 char timebuf [TIME_BUF];
3393 struct thread *thread;
3394
3395 gettimeofday (&timer_now, NULL);
3396
3397 if ((thread = rinfo->t_timeout) != NULL)
3398 {
3399 clock = thread->u.sands.tv_sec - timer_now.tv_sec;
3400 tm = gmtime (&clock);
3401 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3402 vty_out (vty, "%5s", timebuf);
3403 }
3404 else if ((thread = rinfo->t_garbage_collect) != NULL)
3405 {
3406 clock = thread->u.sands.tv_sec - timer_now.tv_sec;
3407 tm = gmtime (&clock);
3408 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3409 vty_out (vty, "%5s", timebuf);
3410 }
3411}
3412
pauldc63bfd2005-10-25 23:31:05 +00003413static const char *
paul718e3742002-12-13 20:15:29 +00003414rip_route_type_print (int sub_type)
3415{
3416 switch (sub_type)
3417 {
3418 case RIP_ROUTE_RTE:
3419 return "n";
3420 case RIP_ROUTE_STATIC:
3421 return "s";
3422 case RIP_ROUTE_DEFAULT:
3423 return "d";
3424 case RIP_ROUTE_REDISTRIBUTE:
3425 return "r";
3426 case RIP_ROUTE_INTERFACE:
3427 return "i";
3428 default:
3429 return "?";
3430 }
3431}
3432
3433DEFUN (show_ip_rip,
3434 show_ip_rip_cmd,
3435 "show ip rip",
3436 SHOW_STR
3437 IP_STR
3438 "Show RIP routes\n")
3439{
3440 struct route_node *np;
3441 struct rip_info *rinfo;
3442
3443 if (! rip)
3444 return CMD_SUCCESS;
3445
hasso16705132003-05-25 14:49:19 +00003446 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3447 "Sub-codes:%s"
3448 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003449 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003450 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003451 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003452
3453 for (np = route_top (rip->table); np; np = route_next (np))
3454 if ((rinfo = np->info) != NULL)
3455 {
3456 int len;
3457
ajsf52d13c2005-10-01 17:38:06 +00003458 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003459 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003460 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003461 rip_route_type_print (rinfo->sub_type),
3462 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3463
hassoa1455d82004-03-03 19:36:24 +00003464 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003465
3466 if (len > 0)
3467 vty_out (vty, "%*s", len, " ");
3468
3469 if (rinfo->nexthop.s_addr)
3470 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3471 rinfo->metric);
3472 else
3473 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3474
3475 /* Route which exist in kernel routing table. */
3476 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3477 (rinfo->sub_type == RIP_ROUTE_RTE))
3478 {
3479 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003480 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003481 rip_vty_out_uptime (vty, rinfo);
3482 }
3483 else if (rinfo->metric == RIP_METRIC_INFINITY)
3484 {
3485 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003486 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003487 rip_vty_out_uptime (vty, rinfo);
3488 }
3489 else
hasso16705132003-05-25 14:49:19 +00003490 {
vincentfbf5d032005-09-29 11:25:50 +00003491 if (rinfo->external_metric)
3492 {
3493 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003494 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003495 rinfo->external_metric);
3496 len = 16 - len;
3497 if (len > 0)
3498 vty_out (vty, "%*s", len, " ");
3499 }
3500 else
3501 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003502 vty_out (vty, "%3d", rinfo->tag);
3503 }
paul718e3742002-12-13 20:15:29 +00003504
3505 vty_out (vty, "%s", VTY_NEWLINE);
3506 }
3507 return CMD_SUCCESS;
3508}
3509
3510/* Return next event time. */
pauldc63bfd2005-10-25 23:31:05 +00003511static int
paul718e3742002-12-13 20:15:29 +00003512rip_next_thread_timer (struct thread *thread)
3513{
3514 struct timeval timer_now;
3515
3516 gettimeofday (&timer_now, NULL);
3517
3518 return thread->u.sands.tv_sec - timer_now.tv_sec;
3519}
3520
hasso16705132003-05-25 14:49:19 +00003521/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3522DEFUN (show_ip_rip_status,
3523 show_ip_rip_status_cmd,
3524 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003525 SHOW_STR
3526 IP_STR
hasso16705132003-05-25 14:49:19 +00003527 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003528 "IP routing protocol process parameters and statistics\n")
3529{
hasso52dc7ee2004-09-23 19:18:23 +00003530 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003531 struct interface *ifp;
3532 struct rip_interface *ri;
3533 extern struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003534 const char *send_version;
3535 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003536
3537 if (! rip)
3538 return CMD_SUCCESS;
3539
3540 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3541 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3542 rip->update_time);
3543 vty_out (vty, " next due in %d seconds%s",
3544 rip_next_thread_timer (rip->t_update),
3545 VTY_NEWLINE);
3546 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3547 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3548 VTY_NEWLINE);
3549
3550 /* Filtering status show. */
3551 config_show_distribute (vty);
3552
3553 /* Default metric information. */
3554 vty_out (vty, " Default redistribution metric is %d%s",
3555 rip->default_metric, VTY_NEWLINE);
3556
3557 /* Redistribute information. */
3558 vty_out (vty, " Redistributing:");
3559 config_write_rip_redistribute (vty, 0);
3560 vty_out (vty, "%s", VTY_NEWLINE);
3561
paulf38a4712003-06-07 01:10:00 +00003562 vty_out (vty, " Default version control: send version %s,",
3563 lookup(ri_version_msg,rip->version_send));
3564 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3565 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3566 else
3567 vty_out (vty, " receive version %s %s",
3568 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003569
3570 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3571
paul1eb8ef22005-04-07 07:30:20 +00003572 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003573 {
paul718e3742002-12-13 20:15:29 +00003574 ri = ifp->info;
3575
3576 if (ri->enable_network || ri->enable_interface)
3577 {
3578 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003579 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003580 else
3581 send_version = lookup (ri_version_msg, ri->ri_send);
3582
3583 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003584 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003585 else
3586 receive_version = lookup (ri_version_msg, ri->ri_receive);
3587
3588 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3589 send_version,
3590 receive_version,
3591 ri->key_chain ? ri->key_chain : "",
3592 VTY_NEWLINE);
3593 }
3594 }
3595
3596 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3597 config_write_rip_network (vty, 0);
3598
paul4aaff3f2003-06-07 01:04:45 +00003599 {
3600 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003601 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003602 {
paul4aaff3f2003-06-07 01:04:45 +00003603 ri = ifp->info;
3604
3605 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3606 {
3607 if (!found_passive)
3608 {
3609 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3610 found_passive = 1;
3611 }
3612 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3613 }
3614 }
3615 }
3616
paul718e3742002-12-13 20:15:29 +00003617 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3618 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3619 rip_peer_display (vty);
3620
3621 rip_distance_show (vty);
3622
3623 return CMD_SUCCESS;
3624}
3625
3626/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003627static int
paul718e3742002-12-13 20:15:29 +00003628config_write_rip (struct vty *vty)
3629{
3630 int write = 0;
3631 struct route_node *rn;
3632 struct rip_distance *rdistance;
3633
3634 if (rip)
3635 {
3636 /* Router RIP statement. */
3637 vty_out (vty, "router rip%s", VTY_NEWLINE);
3638 write++;
3639
3640 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003641 if (rip->version_send != RI_RIP_VERSION_2
3642 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3643 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003644 VTY_NEWLINE);
3645
3646 /* RIP timer configuration. */
3647 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3648 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3649 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3650 vty_out (vty, " timers basic %lu %lu %lu%s",
3651 rip->update_time,
3652 rip->timeout_time,
3653 rip->garbage_time,
3654 VTY_NEWLINE);
3655
3656 /* Default information configuration. */
3657 if (rip->default_information)
3658 {
3659 if (rip->default_information_route_map)
3660 vty_out (vty, " default-information originate route-map %s%s",
3661 rip->default_information_route_map, VTY_NEWLINE);
3662 else
3663 vty_out (vty, " default-information originate%s",
3664 VTY_NEWLINE);
3665 }
3666
3667 /* Redistribute configuration. */
3668 config_write_rip_redistribute (vty, 1);
3669
3670 /* RIP offset-list configuration. */
3671 config_write_rip_offset_list (vty);
3672
3673 /* RIP enabled network and interface configuration. */
3674 config_write_rip_network (vty, 1);
3675
3676 /* RIP default metric configuration */
3677 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3678 vty_out (vty, " default-metric %d%s",
3679 rip->default_metric, VTY_NEWLINE);
3680
3681 /* Distribute configuration. */
3682 write += config_write_distribute (vty);
3683
hasso16705132003-05-25 14:49:19 +00003684 /* Interface routemap configuration */
3685 write += config_write_if_rmap (vty);
3686
paul718e3742002-12-13 20:15:29 +00003687 /* Distance configuration. */
3688 if (rip->distance)
3689 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3690
3691 /* RIP source IP prefix distance configuration. */
3692 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3693 if ((rdistance = rn->info) != NULL)
3694 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3695 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3696 rdistance->access_list ? rdistance->access_list : "",
3697 VTY_NEWLINE);
3698
3699 /* RIP static route configuration. */
3700 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3701 if (rn->info)
3702 vty_out (vty, " route %s/%d%s",
3703 inet_ntoa (rn->p.u.prefix4),
3704 rn->p.prefixlen,
3705 VTY_NEWLINE);
3706
3707 }
3708 return write;
3709}
3710
3711/* RIP node structure. */
3712struct cmd_node rip_node =
3713{
3714 RIP_NODE,
3715 "%s(config-router)# ",
3716 1
3717};
3718
3719/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003720static void
paul718e3742002-12-13 20:15:29 +00003721rip_distribute_update (struct distribute *dist)
3722{
3723 struct interface *ifp;
3724 struct rip_interface *ri;
3725 struct access_list *alist;
3726 struct prefix_list *plist;
3727
3728 if (! dist->ifname)
3729 return;
3730
3731 ifp = if_lookup_by_name (dist->ifname);
3732 if (ifp == NULL)
3733 return;
3734
3735 ri = ifp->info;
3736
3737 if (dist->list[DISTRIBUTE_IN])
3738 {
3739 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3740 if (alist)
3741 ri->list[RIP_FILTER_IN] = alist;
3742 else
3743 ri->list[RIP_FILTER_IN] = NULL;
3744 }
3745 else
3746 ri->list[RIP_FILTER_IN] = NULL;
3747
3748 if (dist->list[DISTRIBUTE_OUT])
3749 {
3750 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3751 if (alist)
3752 ri->list[RIP_FILTER_OUT] = alist;
3753 else
3754 ri->list[RIP_FILTER_OUT] = NULL;
3755 }
3756 else
3757 ri->list[RIP_FILTER_OUT] = NULL;
3758
3759 if (dist->prefix[DISTRIBUTE_IN])
3760 {
3761 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3762 if (plist)
3763 ri->prefix[RIP_FILTER_IN] = plist;
3764 else
3765 ri->prefix[RIP_FILTER_IN] = NULL;
3766 }
3767 else
3768 ri->prefix[RIP_FILTER_IN] = NULL;
3769
3770 if (dist->prefix[DISTRIBUTE_OUT])
3771 {
3772 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3773 if (plist)
3774 ri->prefix[RIP_FILTER_OUT] = plist;
3775 else
3776 ri->prefix[RIP_FILTER_OUT] = NULL;
3777 }
3778 else
3779 ri->prefix[RIP_FILTER_OUT] = NULL;
3780}
3781
3782void
3783rip_distribute_update_interface (struct interface *ifp)
3784{
3785 struct distribute *dist;
3786
3787 dist = distribute_lookup (ifp->name);
3788 if (dist)
3789 rip_distribute_update (dist);
3790}
3791
3792/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003793/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003794static void
paul02ff83c2004-06-11 11:27:03 +00003795rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003796{
3797 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003798 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003799
paul1eb8ef22005-04-07 07:30:20 +00003800 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3801 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003802}
paul11dde9c2004-05-31 14:00:00 +00003803/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003804static void
paul11dde9c2004-05-31 14:00:00 +00003805rip_distribute_update_all_wrapper(struct access_list *notused)
3806{
paul02ff83c2004-06-11 11:27:03 +00003807 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003808}
paul718e3742002-12-13 20:15:29 +00003809
3810/* Delete all added rip route. */
3811void
paul216565a2005-10-25 23:35:28 +00003812rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003813{
3814 int i;
3815 struct route_node *rp;
3816 struct rip_info *rinfo;
3817
3818 if (rip)
3819 {
3820 /* Clear RIP routes */
3821 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3822 if ((rinfo = rp->info) != NULL)
3823 {
3824 if (rinfo->type == ZEBRA_ROUTE_RIP &&
3825 rinfo->sub_type == RIP_ROUTE_RTE)
3826 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
3827 &rinfo->nexthop, rinfo->metric);
3828
3829 RIP_TIMER_OFF (rinfo->t_timeout);
3830 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3831
3832 rp->info = NULL;
3833 route_unlock_node (rp);
3834
3835 rip_info_free (rinfo);
3836 }
3837
3838 /* Cancel RIP related timers. */
3839 RIP_TIMER_OFF (rip->t_update);
3840 RIP_TIMER_OFF (rip->t_triggered_update);
3841 RIP_TIMER_OFF (rip->t_triggered_interval);
3842
3843 /* Cancel read thread. */
3844 if (rip->t_read)
3845 {
3846 thread_cancel (rip->t_read);
3847 rip->t_read = NULL;
3848 }
3849
3850 /* Close RIP socket. */
3851 if (rip->sock >= 0)
3852 {
3853 close (rip->sock);
3854 rip->sock = -1;
3855 }
3856
3857 /* Static RIP route configuration. */
3858 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3859 if (rp->info)
3860 {
3861 rp->info = NULL;
3862 route_unlock_node (rp);
3863 }
3864
3865 /* RIP neighbor configuration. */
3866 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3867 if (rp->info)
3868 {
3869 rp->info = NULL;
3870 route_unlock_node (rp);
3871 }
3872
3873 /* Redistribute related clear. */
3874 if (rip->default_information_route_map)
3875 free (rip->default_information_route_map);
3876
3877 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3878 if (rip->route_map[i].name)
3879 free (rip->route_map[i].name);
3880
3881 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3882 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3883 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3884
3885 XFREE (MTYPE_RIP, rip);
3886 rip = NULL;
3887 }
3888
3889 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003890 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003891 rip_offset_clean ();
3892 rip_interface_clean ();
3893 rip_distance_reset ();
3894 rip_redistribute_clean ();
3895}
3896
3897/* Reset all values to the default settings. */
3898void
paul216565a2005-10-25 23:35:28 +00003899rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003900{
3901 /* Reset global counters. */
3902 rip_global_route_changes = 0;
3903 rip_global_queries = 0;
3904
3905 /* Call ripd related reset functions. */
3906 rip_debug_reset ();
3907 rip_route_map_reset ();
3908
3909 /* Call library reset functions. */
3910 vty_reset ();
3911 access_list_reset ();
3912 prefix_list_reset ();
3913
3914 distribute_list_reset ();
3915
3916 rip_interface_reset ();
3917 rip_distance_reset ();
3918
3919 rip_zclient_reset ();
3920}
3921
pauldc63bfd2005-10-25 23:31:05 +00003922static void
hasso16705132003-05-25 14:49:19 +00003923rip_if_rmap_update (struct if_rmap *if_rmap)
3924{
3925 struct interface *ifp;
3926 struct rip_interface *ri;
3927 struct route_map *rmap;
3928
3929 ifp = if_lookup_by_name (if_rmap->ifname);
3930 if (ifp == NULL)
3931 return;
3932
3933 ri = ifp->info;
3934
3935 if (if_rmap->routemap[IF_RMAP_IN])
3936 {
3937 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3938 if (rmap)
3939 ri->routemap[IF_RMAP_IN] = rmap;
3940 else
3941 ri->routemap[IF_RMAP_IN] = NULL;
3942 }
3943 else
3944 ri->routemap[RIP_FILTER_IN] = NULL;
3945
3946 if (if_rmap->routemap[IF_RMAP_OUT])
3947 {
3948 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3949 if (rmap)
3950 ri->routemap[IF_RMAP_OUT] = rmap;
3951 else
3952 ri->routemap[IF_RMAP_OUT] = NULL;
3953 }
3954 else
3955 ri->routemap[RIP_FILTER_OUT] = NULL;
3956}
3957
3958void
3959rip_if_rmap_update_interface (struct interface *ifp)
3960{
3961 struct if_rmap *if_rmap;
3962
3963 if_rmap = if_rmap_lookup (ifp->name);
3964 if (if_rmap)
3965 rip_if_rmap_update (if_rmap);
3966}
3967
pauldc63bfd2005-10-25 23:31:05 +00003968static void
hasso16705132003-05-25 14:49:19 +00003969rip_routemap_update_redistribute (void)
3970{
3971 int i;
3972
3973 if (rip)
3974 {
3975 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3976 {
3977 if (rip->route_map[i].name)
3978 rip->route_map[i].map =
3979 route_map_lookup_by_name (rip->route_map[i].name);
3980 }
3981 }
3982}
3983
paul11dde9c2004-05-31 14:00:00 +00003984/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003985static void
hasso98b718a2004-10-11 12:57:57 +00003986rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00003987{
3988 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003989 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00003990
paul1eb8ef22005-04-07 07:30:20 +00003991 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3992 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00003993
3994 rip_routemap_update_redistribute ();
3995}
3996
paul718e3742002-12-13 20:15:29 +00003997/* Allocate new rip structure and set default value. */
3998void
pauldc63bfd2005-10-25 23:31:05 +00003999rip_init (void)
paul718e3742002-12-13 20:15:29 +00004000{
4001 /* Randomize for triggered update random(). */
4002 srand (time (NULL));
4003
4004 /* Install top nodes. */
4005 install_node (&rip_node, config_write_rip);
4006
4007 /* Install rip commands. */
4008 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004009 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004010 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004011 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004012 install_element (CONFIG_NODE, &router_rip_cmd);
4013 install_element (CONFIG_NODE, &no_router_rip_cmd);
4014
4015 install_default (RIP_NODE);
4016 install_element (RIP_NODE, &rip_version_cmd);
4017 install_element (RIP_NODE, &no_rip_version_cmd);
4018 install_element (RIP_NODE, &no_rip_version_val_cmd);
4019 install_element (RIP_NODE, &rip_default_metric_cmd);
4020 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4021 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4022 install_element (RIP_NODE, &rip_timers_cmd);
4023 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004024 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004025 install_element (RIP_NODE, &rip_route_cmd);
4026 install_element (RIP_NODE, &no_rip_route_cmd);
4027 install_element (RIP_NODE, &rip_distance_cmd);
4028 install_element (RIP_NODE, &no_rip_distance_cmd);
4029 install_element (RIP_NODE, &rip_distance_source_cmd);
4030 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4031 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4032 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
4033
4034 /* Debug related init. */
4035 rip_debug_init ();
4036
paul718e3742002-12-13 20:15:29 +00004037 /* SNMP init. */
4038#ifdef HAVE_SNMP
4039 rip_snmp_init ();
4040#endif /* HAVE_SNMP */
4041
4042 /* Access list install. */
4043 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004044 access_list_add_hook (rip_distribute_update_all_wrapper);
4045 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004046
4047 /* Prefix list initialize.*/
4048 prefix_list_init ();
4049 prefix_list_add_hook (rip_distribute_update_all);
4050 prefix_list_delete_hook (rip_distribute_update_all);
4051
4052 /* Distribute list install. */
4053 distribute_list_init (RIP_NODE);
4054 distribute_list_add_hook (rip_distribute_update);
4055 distribute_list_delete_hook (rip_distribute_update);
4056
hasso16705132003-05-25 14:49:19 +00004057 /* Route-map */
4058 rip_route_map_init ();
4059 rip_offset_init ();
4060
4061 route_map_add_hook (rip_routemap_update);
4062 route_map_delete_hook (rip_routemap_update);
4063
4064 if_rmap_init (RIP_NODE);
4065 if_rmap_hook_add (rip_if_rmap_update);
4066 if_rmap_hook_delete (rip_if_rmap_update);
4067
paul718e3742002-12-13 20:15:29 +00004068 /* Distance control. */
4069 rip_distance_table = route_table_init ();
4070}