blob: 0e3f877d6bde9dce40e9c27b1d8cb1b08ce98495 [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. */
Stephen Hemminger1423c802008-08-14 17:59:25 +010079static const struct message rip_msg[] =
paul718e3742002-12-13 20:15:29 +000080{
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"},
Stephen Hemminger1423c802008-08-14 17:59:25 +010087 {0, NULL},
paul718e3742002-12-13 20:15:29 +000088};
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 *
Stephen Hemminger393deb92008-08-18 14:13:29 -0700113rip_info_new (void)
paul718e3742002-12-13 20:15:29 +0000114{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700115 return XCALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
paul718e3742002-12-13 20:15:29 +0000116}
117
118void
119rip_info_free (struct rip_info *rinfo)
120{
121 XFREE (MTYPE_RIP_INFO, rinfo);
122}
123
124/* RIP route garbage collect timer. */
pauldc63bfd2005-10-25 23:31:05 +0000125static int
paul718e3742002-12-13 20:15:29 +0000126rip_garbage_collect (struct thread *t)
127{
128 struct rip_info *rinfo;
129 struct route_node *rp;
130
131 rinfo = THREAD_ARG (t);
132 rinfo->t_garbage_collect = NULL;
133
134 /* Off timeout timer. */
135 RIP_TIMER_OFF (rinfo->t_timeout);
136
137 /* Get route_node pointer. */
138 rp = rinfo->rp;
139
140 /* Unlock route_node. */
141 rp->info = NULL;
142 route_unlock_node (rp);
143
144 /* Free RIP routing information. */
145 rip_info_free (rinfo);
146
147 return 0;
148}
149
150/* Timeout RIP routes. */
pauldc63bfd2005-10-25 23:31:05 +0000151static int
paul718e3742002-12-13 20:15:29 +0000152rip_timeout (struct thread *t)
153{
154 struct rip_info *rinfo;
155 struct route_node *rn;
156
157 rinfo = THREAD_ARG (t);
158 rinfo->t_timeout = NULL;
159
160 rn = rinfo->rp;
161
162 /* - The garbage-collection timer is set for 120 seconds. */
163 RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
164 rip->garbage_time);
165
166 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
167 rinfo->metric);
168 /* - The metric for the route is set to 16 (infinity). This causes
169 the route to be removed from service. */
170 rinfo->metric = RIP_METRIC_INFINITY;
171 rinfo->flags &= ~RIP_RTF_FIB;
172
173 /* - The route change flag is to indicate that this entry has been
174 changed. */
175 rinfo->flags |= RIP_RTF_CHANGED;
176
177 /* - The output process is signalled to trigger a response. */
178 rip_event (RIP_TRIGGERED_UPDATE, 0);
179
180 return 0;
181}
182
pauldc63bfd2005-10-25 23:31:05 +0000183static void
paul718e3742002-12-13 20:15:29 +0000184rip_timeout_update (struct rip_info *rinfo)
185{
186 if (rinfo->metric != RIP_METRIC_INFINITY)
187 {
188 RIP_TIMER_OFF (rinfo->t_timeout);
189 RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
190 }
191}
192
pauldc63bfd2005-10-25 23:31:05 +0000193static int
paul718e3742002-12-13 20:15:29 +0000194rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
195{
196 struct distribute *dist;
197 struct access_list *alist;
198 struct prefix_list *plist;
199
200 /* Input distribute-list filtering. */
201 if (ri->list[RIP_FILTER_IN])
202 {
203 if (access_list_apply (ri->list[RIP_FILTER_IN],
204 (struct prefix *) p) == FILTER_DENY)
205 {
206 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000207 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000208 inet_ntoa (p->prefix), p->prefixlen);
209 return -1;
210 }
211 }
212 if (ri->prefix[RIP_FILTER_IN])
213 {
214 if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
215 (struct prefix *) p) == PREFIX_DENY)
216 {
217 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000218 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000219 inet_ntoa (p->prefix), p->prefixlen);
220 return -1;
221 }
222 }
223
224 /* All interface filter check. */
225 dist = distribute_lookup (NULL);
226 if (dist)
227 {
228 if (dist->list[DISTRIBUTE_IN])
229 {
230 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
231
232 if (alist)
233 {
234 if (access_list_apply (alist,
235 (struct prefix *) p) == FILTER_DENY)
236 {
237 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000238 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000239 inet_ntoa (p->prefix), p->prefixlen);
240 return -1;
241 }
242 }
243 }
244 if (dist->prefix[DISTRIBUTE_IN])
245 {
246 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
247
248 if (plist)
249 {
250 if (prefix_list_apply (plist,
251 (struct prefix *) p) == PREFIX_DENY)
252 {
253 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000254 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000255 inet_ntoa (p->prefix), p->prefixlen);
256 return -1;
257 }
258 }
259 }
260 }
261 return 0;
262}
263
pauldc63bfd2005-10-25 23:31:05 +0000264static int
paul718e3742002-12-13 20:15:29 +0000265rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
266{
267 struct distribute *dist;
268 struct access_list *alist;
269 struct prefix_list *plist;
270
271 if (ri->list[RIP_FILTER_OUT])
272 {
273 if (access_list_apply (ri->list[RIP_FILTER_OUT],
274 (struct prefix *) p) == FILTER_DENY)
275 {
276 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000277 zlog_debug ("%s/%d is filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000278 inet_ntoa (p->prefix), p->prefixlen);
279 return -1;
280 }
281 }
282 if (ri->prefix[RIP_FILTER_OUT])
283 {
284 if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
285 (struct prefix *) p) == PREFIX_DENY)
286 {
287 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000288 zlog_debug ("%s/%d is filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000289 inet_ntoa (p->prefix), p->prefixlen);
290 return -1;
291 }
292 }
293
294 /* All interface filter check. */
295 dist = distribute_lookup (NULL);
296 if (dist)
297 {
298 if (dist->list[DISTRIBUTE_OUT])
299 {
300 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
301
302 if (alist)
303 {
304 if (access_list_apply (alist,
305 (struct prefix *) p) == FILTER_DENY)
306 {
307 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000308 zlog_debug ("%s/%d filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000309 inet_ntoa (p->prefix), p->prefixlen);
310 return -1;
311 }
312 }
313 }
314 if (dist->prefix[DISTRIBUTE_OUT])
315 {
316 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
317
318 if (plist)
319 {
320 if (prefix_list_apply (plist,
321 (struct prefix *) p) == PREFIX_DENY)
322 {
323 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000324 zlog_debug ("%s/%d filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000325 inet_ntoa (p->prefix), p->prefixlen);
326 return -1;
327 }
328 }
329 }
330 }
331 return 0;
332}
333
334/* Check nexthop address validity. */
335static int
336rip_nexthop_check (struct in_addr *addr)
337{
hasso52dc7ee2004-09-23 19:18:23 +0000338 struct listnode *node;
339 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000340 struct interface *ifp;
341 struct connected *ifc;
342 struct prefix *p;
343
344 /* If nexthop address matches local configured address then it is
345 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000346 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000347 {
paul1eb8ef22005-04-07 07:30:20 +0000348 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000349 {
paul718e3742002-12-13 20:15:29 +0000350 p = ifc->address;
351
352 if (p->family == AF_INET
353 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
354 return -1;
355 }
356 }
357 return 0;
358}
359
360/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000361static void
paul718e3742002-12-13 20:15:29 +0000362rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000363 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000364{
365 int ret;
366 struct prefix_ipv4 p;
367 struct route_node *rp;
paulb94f9db2004-05-01 20:45:38 +0000368 struct rip_info *rinfo, rinfotmp;
paul718e3742002-12-13 20:15:29 +0000369 struct rip_interface *ri;
370 struct in_addr *nexthop;
371 u_char oldmetric;
372 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000373 int route_reuse = 0;
374 unsigned char old_dist, new_dist;
paul718e3742002-12-13 20:15:29 +0000375
376 /* Make prefix structure. */
377 memset (&p, 0, sizeof (struct prefix_ipv4));
378 p.family = AF_INET;
379 p.prefix = rte->prefix;
380 p.prefixlen = ip_masklen (rte->mask);
381
382 /* Make sure mask is applied. */
383 apply_mask_ipv4 (&p);
384
385 /* Apply input filters. */
386 ri = ifp->info;
387
388 ret = rip_incoming_filter (&p, ri);
389 if (ret < 0)
390 return;
391
hasso16705132003-05-25 14:49:19 +0000392 /* Modify entry according to the interface routemap. */
393 if (ri->routemap[RIP_FILTER_IN])
394 {
395 int ret;
396 struct rip_info newinfo;
397
398 memset (&newinfo, 0, sizeof (newinfo));
399 newinfo.type = ZEBRA_ROUTE_RIP;
400 newinfo.sub_type = RIP_ROUTE_RTE;
paula87552c2004-05-03 20:00:17 +0000401 newinfo.nexthop = rte->nexthop;
402 newinfo.from = from->sin_addr;
403 newinfo.ifindex = ifp->ifindex;
hasso16705132003-05-25 14:49:19 +0000404 newinfo.metric = rte->metric;
405 newinfo.metric_out = rte->metric; /* XXX */
paula87552c2004-05-03 20:00:17 +0000406 newinfo.tag = ntohs (rte->tag); /* XXX */
hasso16705132003-05-25 14:49:19 +0000407
408 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000409 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
410 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000411
412 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000413 {
414 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000415 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000416 inet_ntoa (p.prefix), p.prefixlen);
417 return;
418 }
hasso16705132003-05-25 14:49:19 +0000419
420 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000421 rte->nexthop = newinfo.nexthop_out;
422 rte->tag = htons (newinfo.tag_out); /* XXX */
423 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000424 }
425
paul718e3742002-12-13 20:15:29 +0000426 /* Once the entry has been validated, update the metric by
427 adding the cost of the network on wich the message
428 arrived. If the result is greater than infinity, use infinity
429 (RFC2453 Sec. 3.9.2) */
430 /* Zebra ripd can handle offset-list in. */
431 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
432
433 /* If offset-list does not modify the metric use interface's
434 metric. */
paula87552c2004-05-03 20:00:17 +0000435 if (!ret)
paul718e3742002-12-13 20:15:29 +0000436 rte->metric += ifp->metric;
437
438 if (rte->metric > RIP_METRIC_INFINITY)
439 rte->metric = RIP_METRIC_INFINITY;
440
441 /* Set nexthop pointer. */
442 if (rte->nexthop.s_addr == 0)
443 nexthop = &from->sin_addr;
444 else
445 nexthop = &rte->nexthop;
446
hasso16705132003-05-25 14:49:19 +0000447 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000448 if (rip_nexthop_check (nexthop) < 0)
449 {
450 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000451 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000452 return;
453 }
454
455 /* Get index for the prefix. */
456 rp = route_node_get (rip->table, (struct prefix *) &p);
457
458 /* Check to see whether there is already RIP route on the table. */
459 rinfo = rp->info;
460
461 if (rinfo)
462 {
paul718e3742002-12-13 20:15:29 +0000463 /* Local static route. */
464 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000465 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
466 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
467 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000468 {
469 route_unlock_node (rp);
470 return;
471 }
472
473 /* Redistributed route check. */
474 if (rinfo->type != ZEBRA_ROUTE_RIP
475 && rinfo->metric != RIP_METRIC_INFINITY)
476 {
477 /* Fill in a minimaly temporary rip_info structure, for a future
478 rip_distance_apply() use) */
479 memset (&rinfotmp, 0, sizeof (rinfotmp));
480 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
481 rinfotmp.rp = rinfo->rp;
482 new_dist = rip_distance_apply (&rinfotmp);
483 new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
484 old_dist = rinfo->distance;
vincent7a383332006-01-30 18:12:42 +0000485 /* Only connected routes may have a valid NULL distance */
486 if (rinfo->type != ZEBRA_ROUTE_CONNECT)
487 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000488 /* If imported route does not have STRICT precedence,
489 mark it as a ghost */
490 if (new_dist > old_dist
491 || rte->metric == RIP_METRIC_INFINITY)
492 {
493 route_unlock_node (rp);
494 return;
495 }
496 else
497 {
498 RIP_TIMER_OFF (rinfo->t_timeout);
499 RIP_TIMER_OFF (rinfo->t_garbage_collect);
500
501 rp->info = NULL;
502 if (rip_route_rte (rinfo))
503 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
504 &rinfo->nexthop, rinfo->metric);
505 rip_info_free (rinfo);
506 rinfo = NULL;
507 route_reuse = 1;
508 }
509 }
paul718e3742002-12-13 20:15:29 +0000510 }
paula87552c2004-05-03 20:00:17 +0000511
512 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000513 {
514 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000515 for the destination prefix. If there is no such route, add
516 this route to the routing table, unless the metric is
517 infinity (there is no point in adding a route which
518 unusable). */
paul718e3742002-12-13 20:15:29 +0000519 if (rte->metric != RIP_METRIC_INFINITY)
paula87552c2004-05-03 20:00:17 +0000520 {
521 rinfo = rip_info_new ();
paul718e3742002-12-13 20:15:29 +0000522
paula87552c2004-05-03 20:00:17 +0000523 /* - Setting the destination prefix and length to those in
524 the RTE. */
525 rinfo->rp = rp;
paul718e3742002-12-13 20:15:29 +0000526
paula87552c2004-05-03 20:00:17 +0000527 /* - Setting the metric to the newly calculated metric (as
528 described above). */
529 rinfo->metric = rte->metric;
530 rinfo->tag = ntohs (rte->tag);
paul718e3742002-12-13 20:15:29 +0000531
paula87552c2004-05-03 20:00:17 +0000532 /* - Set the next hop address to be the address of the router
533 from which the datagram came or the next hop address
534 specified by a next hop RTE. */
535 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
536 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
537 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000538
paula87552c2004-05-03 20:00:17 +0000539 /* - Initialize the timeout for the route. If the
540 garbage-collection timer is running for this route, stop it
541 (see section 2.3 for a discussion of the timers). */
542 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000543
paula87552c2004-05-03 20:00:17 +0000544 /* - Set the route change flag. */
545 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +0000546
paula87552c2004-05-03 20:00:17 +0000547 /* - Signal the output process to trigger an update (see section
548 2.5). */
549 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000550
paula87552c2004-05-03 20:00:17 +0000551 /* Finally, route goes into the kernel. */
552 rinfo->type = ZEBRA_ROUTE_RIP;
553 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000554
paula87552c2004-05-03 20:00:17 +0000555 /* Set distance value. */
556 rinfo->distance = rip_distance_apply (rinfo);
557
558 rp->info = rinfo;
559 rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
560 rinfo->distance);
561 rinfo->flags |= RIP_RTF_FIB;
562 }
vincentfbf5d032005-09-29 11:25:50 +0000563
564 /* Unlock temporary lock, i.e. same behaviour */
565 if (route_reuse)
566 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +0000567 }
568 else
569 {
570 /* Route is there but we are not sure the route is RIP or not. */
571 rinfo = rp->info;
paula87552c2004-05-03 20:00:17 +0000572
paul718e3742002-12-13 20:15:29 +0000573 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000574 to the address of the router from which the datagram came.
575 If this datagram is from the same router as the existing
576 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000577 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000578 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000579
580 if (same)
paula87552c2004-05-03 20:00:17 +0000581 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000582
paulb94f9db2004-05-01 20:45:38 +0000583
584 /* Fill in a minimaly temporary rip_info structure, for a future
585 rip_distance_apply() use) */
paula87552c2004-05-03 20:00:17 +0000586 memset (&rinfotmp, 0, sizeof (rinfotmp));
paulb94f9db2004-05-01 20:45:38 +0000587 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
paula87552c2004-05-03 20:00:17 +0000588 rinfotmp.rp = rinfo->rp;
paulb94f9db2004-05-01 20:45:38 +0000589
590
paul718e3742002-12-13 20:15:29 +0000591 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000592 router as the existing route, and the new metric is different
593 than the old one; or, if the new metric is lower than the old
594 one, or if the tag has been changed; or if there is a route
595 with a lower administrave distance; or an update of the
596 distance on the actual route; do the following actions: */
597 if ((same && rinfo->metric != rte->metric)
598 || (rte->metric < rinfo->metric)
599 || ((same)
600 && (rinfo->metric == rte->metric)
601 && ntohs (rte->tag) != rinfo->tag)
602 || (rinfo->distance > rip_distance_apply (&rinfotmp))
603 || ((rinfo->distance != rip_distance_apply (rinfo)) && same))
604 {
605 /* - Adopt the route from the datagram. That is, put the
606 new metric in, and adjust the next hop address (if
607 necessary). */
608 oldmetric = rinfo->metric;
609 rinfo->metric = rte->metric;
610 rinfo->tag = ntohs (rte->tag);
611 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
612 rinfo->ifindex = ifp->ifindex;
613 rinfo->distance = rip_distance_apply (rinfo);
paul718e3742002-12-13 20:15:29 +0000614
paula87552c2004-05-03 20:00:17 +0000615 /* Should a new route to this network be established
616 while the garbage-collection timer is running, the
617 new route will replace the one that is about to be
618 deleted. In this case the garbage-collection timer
619 must be cleared. */
paul718e3742002-12-13 20:15:29 +0000620
paula87552c2004-05-03 20:00:17 +0000621 if (oldmetric == RIP_METRIC_INFINITY &&
622 rinfo->metric < RIP_METRIC_INFINITY)
623 {
624 rinfo->type = ZEBRA_ROUTE_RIP;
625 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000626
paula87552c2004-05-03 20:00:17 +0000627 RIP_TIMER_OFF (rinfo->t_garbage_collect);
paul718e3742002-12-13 20:15:29 +0000628
paula87552c2004-05-03 20:00:17 +0000629 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
630 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000631
paula87552c2004-05-03 20:00:17 +0000632 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
633 rinfo->distance);
634 rinfo->flags |= RIP_RTF_FIB;
635 }
paul718e3742002-12-13 20:15:29 +0000636
paula87552c2004-05-03 20:00:17 +0000637 /* Update nexthop and/or metric value. */
638 if (oldmetric != RIP_METRIC_INFINITY)
639 {
640 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
641 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
642 rinfo->distance);
643 rinfo->flags |= RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000644
paula87552c2004-05-03 20:00:17 +0000645 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
646 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
647 }
paul718e3742002-12-13 20:15:29 +0000648
paula87552c2004-05-03 20:00:17 +0000649 /* - Set the route change flag and signal the output process
650 to trigger an update. */
651 rinfo->flags |= RIP_RTF_CHANGED;
652 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000653
paula87552c2004-05-03 20:00:17 +0000654 /* - If the new metric is infinity, start the deletion
655 process (described above); */
656 if (rinfo->metric == RIP_METRIC_INFINITY)
657 {
658 /* If the new metric is infinity, the deletion process
659 begins for the route, which is no longer used for
660 routing packets. Note that the deletion process is
661 started only when the metric is first set to
662 infinity. If the metric was already infinity, then a
663 new deletion process is not started. */
664 if (oldmetric != RIP_METRIC_INFINITY)
665 {
666 /* - The garbage-collection timer is set for 120 seconds. */
667 RIP_TIMER_ON (rinfo->t_garbage_collect,
668 rip_garbage_collect, rip->garbage_time);
669 RIP_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +0000670
paula87552c2004-05-03 20:00:17 +0000671 /* - The metric for the route is set to 16
672 (infinity). This causes the route to be removed
673 from service. */
674 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
675 rinfo->flags &= ~RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000676
paula87552c2004-05-03 20:00:17 +0000677 /* - The route change flag is to indicate that this
678 entry has been changed. */
679 /* - The output process is signalled to trigger a
paul718e3742002-12-13 20:15:29 +0000680 response. */
paula87552c2004-05-03 20:00:17 +0000681 ; /* Above processes are already done previously. */
682 }
683 }
684 else
685 {
686 /* otherwise, re-initialize the timeout. */
687 rip_timeout_update (rinfo);
688 }
689 }
paul718e3742002-12-13 20:15:29 +0000690 /* Unlock tempolary lock of the route. */
691 route_unlock_node (rp);
692 }
693}
694
695/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000696static void
hasso8a676be2004-10-08 06:36:38 +0000697rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000698{
699 caddr_t lim;
700 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000701 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000702 char pbuf[BUFSIZ], nbuf[BUFSIZ];
703 u_char netmask = 0;
704 u_char *p;
705
706 /* Set command string. */
707 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
708 command_str = lookup (rip_msg, packet->command);
709 else
710 command_str = "unknown";
711
712 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000713 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000714 sndrcv, command_str, packet->version, size);
715
716 /* Dump each routing table entry. */
717 rte = packet->rte;
718
719 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
720 {
721 if (packet->version == RIPv2)
722 {
723 netmask = ip_masklen (rte->mask);
724
paulca5e5162004-06-06 22:06:33 +0000725 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000726 {
paulca5e5162004-06-06 22:06:33 +0000727 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000728 {
729 p = (u_char *)&rte->prefix;
730
ajs5d6c3772004-12-08 19:24:06 +0000731 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000732 ntohs (rte->family), ntohs (rte->tag), p);
733 }
paulca5e5162004-06-06 22:06:33 +0000734 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000735 {
736 struct rip_md5_info *md5;
737
738 md5 = (struct rip_md5_info *) &packet->rte;
739
ajs5d6c3772004-12-08 19:24:06 +0000740 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000741 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000742 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000743 " Auth Data len %d",
744 ntohs (md5->packet_len), md5->keyid,
745 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000746 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000747 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000748 }
paulca5e5162004-06-06 22:06:33 +0000749 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000750 {
751 p = (u_char *)&rte->prefix;
752
ajs5d6c3772004-12-08 19:24:06 +0000753 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000754 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000755 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000756 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000757 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
758 p[7], p[9], p[10], p[11], p[12], p[13],
759 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000760 }
761 else
762 {
ajs5d6c3772004-12-08 19:24:06 +0000763 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000764 ntohs (rte->family), ntohs (rte->tag));
765 }
766 }
767 else
ajs5d6c3772004-12-08 19:24:06 +0000768 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000769 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
770 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
771 BUFSIZ), ntohs (rte->family),
772 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000773 }
774 else
775 {
ajs5d6c3772004-12-08 19:24:06 +0000776 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000777 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
778 ntohs (rte->family), ntohs (rte->tag),
779 (u_long)ntohl (rte->metric));
780 }
781 }
782}
783
784/* Check if the destination address is valid (unicast; not net 0
785 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
786 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000787static int
paul718e3742002-12-13 20:15:29 +0000788rip_destination_check (struct in_addr addr)
789{
790 u_int32_t destination;
791
792 /* Convert to host byte order. */
793 destination = ntohl (addr.s_addr);
794
795 if (IPV4_NET127 (destination))
796 return 0;
797
798 /* Net 0 may match to the default route. */
799 if (IPV4_NET0 (destination) && destination != 0)
800 return 0;
801
802 /* Unicast address must belong to class A, B, C. */
803 if (IN_CLASSA (destination))
804 return 1;
805 if (IN_CLASSB (destination))
806 return 1;
807 if (IN_CLASSC (destination))
808 return 1;
809
810 return 0;
811}
812
813/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000814static int
paul718e3742002-12-13 20:15:29 +0000815rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
816 struct interface *ifp)
817{
818 struct rip_interface *ri;
819 char *auth_str;
820
821 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000822 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000823 inet_ntoa (from->sin_addr));
824
825 ri = ifp->info;
826
827 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000828 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000829 return 0;
830
831 /* Simple password authentication. */
832 if (ri->auth_str)
833 {
834 auth_str = (char *) &rte->prefix;
835
836 if (strncmp (auth_str, ri->auth_str, 16) == 0)
837 return 1;
838 }
839 if (ri->key_chain)
840 {
841 struct keychain *keychain;
842 struct key *key;
843
844 keychain = keychain_lookup (ri->key_chain);
845 if (keychain == NULL)
846 return 0;
847
848 key = key_match_for_accept (keychain, (char *) &rte->prefix);
849 if (key)
850 return 1;
851 }
852 return 0;
853}
854
855/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000856static int
paul718e3742002-12-13 20:15:29 +0000857rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000858 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000859{
860 struct rip_interface *ri;
861 struct rip_md5_info *md5;
862 struct rip_md5_data *md5data;
863 struct keychain *keychain;
864 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000865 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000866 u_char digest[RIP_AUTH_MD5_SIZE];
867 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000868 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000869
870 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000871 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000872 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000873
874 ri = ifp->info;
875 md5 = (struct rip_md5_info *) &packet->rte;
876
877 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000878 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000879 return 0;
880
paulca5e5162004-06-06 22:06:33 +0000881 /* If the authentication length is less than 16, then it must be wrong for
882 * any interpretation of rfc2082. Some implementations also interpret
883 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000884 */
paulca5e5162004-06-06 22:06:33 +0000885 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
886 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000887 {
888 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000889 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000890 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000891 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000892 }
paul718e3742002-12-13 20:15:29 +0000893
paulca5e5162004-06-06 22:06:33 +0000894 /* grab and verify check packet length */
895 packet_len = ntohs (md5->packet_len);
896
897 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
898 {
899 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000900 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000901 "greater than received length %d!",
902 md5->packet_len, length);
903 return 0;
904 }
905
906 /* retrieve authentication data */
907 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000908
909 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000910
paul718e3742002-12-13 20:15:29 +0000911 if (ri->key_chain)
912 {
913 keychain = keychain_lookup (ri->key_chain);
914 if (keychain == NULL)
915 return 0;
916
917 key = key_lookup_for_accept (keychain, md5->keyid);
918 if (key == NULL)
919 return 0;
920
paul98fd1e62006-01-17 17:26:25 +0000921 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000922 }
paul98fd1e62006-01-17 17:26:25 +0000923 else if (ri->auth_str)
924 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000925
Paul Jakmafa93b162008-05-29 19:03:08 +0000926 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000927 return 0;
paul98fd1e62006-01-17 17:26:25 +0000928
paul718e3742002-12-13 20:15:29 +0000929 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000930 memset (&ctx, 0, sizeof(ctx));
931 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000932 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
933 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000934 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000935
936 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000937 return packet_len;
938 else
939 return 0;
940}
941
paulb14ee002005-02-04 23:42:41 +0000942/* Pick correct auth string for sends, prepare auth_str buffer for use.
943 * (left justified and padded).
944 *
945 * presumes one of ri or key is valid, and that the auth strings they point
946 * to are nul terminated. If neither are present, auth_str will be fully
947 * zero padded.
948 *
949 */
950static void
951rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
952 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +0000953{
paulb14ee002005-02-04 23:42:41 +0000954 assert (ri || key);
paul718e3742002-12-13 20:15:29 +0000955
paulb14ee002005-02-04 23:42:41 +0000956 memset (auth_str, 0, len);
957 if (key && key->string)
958 strncpy (auth_str, key->string, len);
959 else if (ri->auth_str)
960 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +0000961
paulb14ee002005-02-04 23:42:41 +0000962 return;
963}
paul718e3742002-12-13 20:15:29 +0000964
paulb14ee002005-02-04 23:42:41 +0000965/* Write RIPv2 simple password authentication information
966 *
967 * auth_str is presumed to be 2 bytes and correctly prepared
968 * (left justified and zero padded).
969 */
970static void
971rip_auth_simple_write (struct stream *s, char *auth_str, int len)
972{
973 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +0000974
paulb14ee002005-02-04 23:42:41 +0000975 stream_putw (s, RIP_FAMILY_AUTH);
976 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
977 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
978
979 return;
980}
981
982/* write RIPv2 MD5 "authentication header"
983 * (uses the auth key data field)
984 *
985 * Digest offset field is set to 0.
986 *
987 * returns: offset of the digest offset field, which must be set when
988 * length to the auth-data MD5 digest is known.
989 */
990static size_t
991rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
992 struct key *key)
993{
paul98fd1e62006-01-17 17:26:25 +0000994 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +0000995
996 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +0000997
998 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +0000999 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +00001000 stream_putw (s, RIP_AUTH_MD5);
1001
paulb14ee002005-02-04 23:42:41 +00001002 /* MD5 AH digest offset field.
1003 *
1004 * Set to placeholder value here, to true value when RIP-2 Packet length
1005 * is known. Actual value is set in .....().
1006 */
paul98fd1e62006-01-17 17:26:25 +00001007 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001008 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001009
1010 /* Key ID. */
1011 if (key)
1012 stream_putc (s, key->index % 256);
1013 else
1014 stream_putc (s, 1);
1015
paulca5e5162004-06-06 22:06:33 +00001016 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1017 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1018 * to be configurable.
1019 */
1020 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001021
1022 /* Sequence Number (non-decreasing). */
1023 /* RFC2080: The value used in the sequence number is
1024 arbitrary, but two suggestions are the time of the
1025 message's creation or a simple message counter. */
1026 stream_putl (s, time (NULL));
1027
1028 /* Reserved field must be zero. */
1029 stream_putl (s, 0);
1030 stream_putl (s, 0);
1031
paul98fd1e62006-01-17 17:26:25 +00001032 return doff;
paulb14ee002005-02-04 23:42:41 +00001033}
paul718e3742002-12-13 20:15:29 +00001034
paulb14ee002005-02-04 23:42:41 +00001035/* If authentication is in used, write the appropriate header
1036 * returns stream offset to which length must later be written
1037 * or 0 if this is not required
1038 */
1039static size_t
1040rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1041 struct key *key, char *auth_str, int len)
1042{
1043 assert (ri->auth_type != RIP_NO_AUTH);
1044
1045 switch (ri->auth_type)
1046 {
1047 case RIP_AUTH_SIMPLE_PASSWORD:
1048 rip_auth_prepare_str_send (ri, key, auth_str, len);
1049 rip_auth_simple_write (s, auth_str, len);
1050 return 0;
1051 case RIP_AUTH_MD5:
1052 return rip_auth_md5_ah_write (s, ri, key);
1053 }
1054 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001055 return 0;
paulb14ee002005-02-04 23:42:41 +00001056}
1057
1058/* Write RIPv2 MD5 authentication data trailer */
1059static void
1060rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1061 char *auth_str, int authlen)
1062{
1063 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001064 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001065 unsigned char digest[RIP_AUTH_MD5_SIZE];
1066
1067 /* Make it sure this interface is configured as MD5
1068 authentication. */
1069 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1070 assert (doff > 0);
1071
1072 /* Get packet length. */
1073 len = stream_get_endp(s);
1074
1075 /* Check packet length. */
1076 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1077 {
1078 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1079 return;
1080 }
1081
1082 /* Set the digest offset length in the header */
1083 stream_putw_at (s, doff, len);
1084
paul718e3742002-12-13 20:15:29 +00001085 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001086 stream_putw (s, RIP_FAMILY_AUTH);
1087 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001088
1089 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001090 memset(&ctx, 0, sizeof(ctx));
1091 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001092 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001093 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1094 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001095
1096 /* Copy the digest to the packet. */
1097 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1098}
1099
1100/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001101static void
paul718e3742002-12-13 20:15:29 +00001102rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001103 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001104{
1105 caddr_t lim;
1106 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001107 struct prefix_ipv4 ifaddr;
1108 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001109 int subnetted;
paul718e3742002-12-13 20:15:29 +00001110
paul727d1042002-12-13 20:50:29 +00001111 /* We don't know yet. */
1112 subnetted = -1;
1113
paul718e3742002-12-13 20:15:29 +00001114 /* The Response must be ignored if it is not from the RIP
1115 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001116 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001117 {
1118 zlog_info ("response doesn't come from RIP port: %d",
1119 from->sin_port);
1120 rip_peer_bad_packet (from);
1121 return;
1122 }
1123
1124 /* The datagram's IPv4 source address should be checked to see
1125 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001126 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1127 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001128 {
1129 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1130 inet_ntoa (from->sin_addr));
1131 rip_peer_bad_packet (from);
1132 return;
1133 }
1134
1135 /* It is also worth checking to see whether the response is from one
1136 of the router's own addresses. */
1137
1138 ; /* Alredy done in rip_read () */
1139
1140 /* Update RIP peer. */
1141 rip_peer_update (from, packet->version);
1142
1143 /* Set RTE pointer. */
1144 rte = packet->rte;
1145
1146 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1147 {
1148 /* RIPv2 authentication check. */
1149 /* If the Address Family Identifier of the first (and only the
1150 first) entry in the message is 0xFFFF, then the remainder of
1151 the entry contains the authentication. */
1152 /* If the packet gets here it means authentication enabled */
1153 /* Check is done in rip_read(). So, just skipping it */
1154 if (packet->version == RIPv2 &&
1155 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001156 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001157 continue;
1158
paulca5e5162004-06-06 22:06:33 +00001159 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001160 {
1161 /* Address family check. RIP only supports AF_INET. */
1162 zlog_info ("Unsupported family %d from %s.",
1163 ntohs (rte->family), inet_ntoa (from->sin_addr));
1164 continue;
1165 }
1166
1167 /* - is the destination address valid (e.g., unicast; not net 0
1168 or 127) */
1169 if (! rip_destination_check (rte->prefix))
1170 {
1171 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1172 rip_peer_bad_route (from);
1173 continue;
1174 }
1175
1176 /* Convert metric value to host byte order. */
1177 rte->metric = ntohl (rte->metric);
1178
1179 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1180 if (! (rte->metric >= 1 && rte->metric <= 16))
1181 {
1182 zlog_info ("Route's metric is not in the 1-16 range.");
1183 rip_peer_bad_route (from);
1184 continue;
1185 }
1186
1187 /* RIPv1 does not have nexthop value. */
1188 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1189 {
1190 zlog_info ("RIPv1 packet with nexthop value %s",
1191 inet_ntoa (rte->nexthop));
1192 rip_peer_bad_route (from);
1193 continue;
1194 }
1195
1196 /* That is, if the provided information is ignored, a possibly
1197 sub-optimal, but absolutely valid, route may be taken. If
1198 the received Next Hop is not directly reachable, it should be
1199 treated as 0.0.0.0. */
1200 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1201 {
1202 u_int32_t addrval;
1203
1204 /* Multicast address check. */
1205 addrval = ntohl (rte->nexthop.s_addr);
1206 if (IN_CLASSD (addrval))
1207 {
1208 zlog_info ("Nexthop %s is multicast address, skip this rte",
1209 inet_ntoa (rte->nexthop));
1210 continue;
1211 }
1212
1213 if (! if_lookup_address (rte->nexthop))
1214 {
1215 struct route_node *rn;
1216 struct rip_info *rinfo;
1217
1218 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1219
1220 if (rn)
1221 {
1222 rinfo = rn->info;
1223
1224 if (rinfo->type == ZEBRA_ROUTE_RIP
1225 && rinfo->sub_type == RIP_ROUTE_RTE)
1226 {
1227 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001228 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 +00001229 rte->nexthop = rinfo->from;
1230 }
1231 else
1232 {
1233 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001234 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 +00001235 rte->nexthop.s_addr = 0;
1236 }
1237
1238 route_unlock_node (rn);
1239 }
1240 else
1241 {
1242 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001243 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 +00001244 rte->nexthop.s_addr = 0;
1245 }
1246
1247 }
1248 }
1249
1250 /* For RIPv1, there won't be a valid netmask.
1251
1252 This is a best guess at the masks. If everyone was using old
1253 Ciscos before the 'ip subnet zero' option, it would be almost
1254 right too :-)
1255
1256 Cisco summarize ripv1 advertisments to the classful boundary
1257 (/16 for class B's) except when the RIP packet does to inside
1258 the classful network in question. */
1259
1260 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1261 || (packet->version == RIPv2
1262 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1263 {
1264 u_int32_t destination;
1265
paul727d1042002-12-13 20:50:29 +00001266 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001267 {
1268 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1269 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1270 apply_classful_mask_ipv4 (&ifaddrclass);
1271 subnetted = 0;
1272 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1273 subnetted = 1;
1274 }
paul727d1042002-12-13 20:50:29 +00001275
paul718e3742002-12-13 20:15:29 +00001276 destination = ntohl (rte->prefix.s_addr);
1277
paul727d1042002-12-13 20:50:29 +00001278 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001279 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001280 else if (IN_CLASSB (destination))
1281 masklen2ip (16, &rte->mask);
1282 else if (IN_CLASSC (destination))
1283 masklen2ip (24, &rte->mask);
1284
1285 if (subnetted == 1)
1286 masklen2ip (ifaddrclass.prefixlen,
1287 (struct in_addr *) &destination);
1288 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1289 ifaddrclass.prefix.s_addr))
1290 {
1291 masklen2ip (ifaddr.prefixlen, &rte->mask);
1292 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1293 masklen2ip (32, &rte->mask);
1294 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001295 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001296 }
1297 else
1298 {
1299 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1300 continue;
1301 }
1302
1303 if (IS_RIP_DEBUG_EVENT)
1304 {
ajs5d6c3772004-12-08 19:24:06 +00001305 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1306 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001307 }
1308 }
1309
1310 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1311 ignore the entry. */
1312 if ((packet->version == RIPv2)
1313 && (rte->mask.s_addr != 0)
1314 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1315 {
1316 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1317 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1318 rip_peer_bad_route (from);
1319 continue;
1320 }
1321
1322 /* Default route's netmask is ignored. */
1323 if (packet->version == RIPv2
1324 && (rte->prefix.s_addr == 0)
1325 && (rte->mask.s_addr != 0))
1326 {
1327 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001328 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001329 rte->mask.s_addr = 0;
1330 }
1331
1332 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001333 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001334 }
1335}
1336
paula4e987e2005-06-03 17:46:49 +00001337/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001338static int
paul2c61ae32005-08-16 15:22:14 +00001339rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001340{
1341 int ret;
1342 int sock;
1343 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001344
paul2c61ae32005-08-16 15:22:14 +00001345 memset (&addr, 0, sizeof (struct sockaddr_in));
1346
1347 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001348 {
paulf69bd9d2005-06-03 18:01:50 +00001349 addr.sin_family = AF_INET;
1350 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001351#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001352 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001353#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001354 } else {
1355 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001356 }
1357
paul2c61ae32005-08-16 15:22:14 +00001358 /* sending port must always be the RIP port */
1359 addr.sin_port = htons (RIP_PORT_DEFAULT);
1360
paula4e987e2005-06-03 17:46:49 +00001361 /* Make datagram socket. */
1362 sock = socket (AF_INET, SOCK_DGRAM, 0);
1363 if (sock < 0)
1364 {
1365 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1366 exit (1);
1367 }
1368
1369 sockopt_broadcast (sock);
1370 sockopt_reuseaddr (sock);
1371 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001372#ifdef RIP_RECVMSG
1373 setsockopt_pktinfo (sock);
1374#endif /* RIP_RECVMSG */
1375
1376 if (ripd_privs.change (ZPRIVS_RAISE))
1377 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001378 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1379 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1380
paula4e987e2005-06-03 17:46:49 +00001381 {
1382 int save_errno = errno;
1383 if (ripd_privs.change (ZPRIVS_LOWER))
1384 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001385
1386 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1387 sock, inet_ntoa(addr.sin_addr),
1388 (int) ntohs(addr.sin_port),
1389 safe_strerror(save_errno));
1390
paulf69bd9d2005-06-03 18:01:50 +00001391 close (sock);
paula4e987e2005-06-03 17:46:49 +00001392 return ret;
1393 }
paulf69bd9d2005-06-03 18:01:50 +00001394
paula4e987e2005-06-03 17:46:49 +00001395 if (ripd_privs.change (ZPRIVS_LOWER))
1396 zlog_err ("rip_create_socket: could not lower privs");
1397
1398 return sock;
1399}
1400
paulc49ad8f2004-10-22 10:27:28 +00001401/* RIP packet send to destination address, on interface denoted by
1402 * by connected argument. NULL to argument denotes destination should be
1403 * should be RIP multicast group
1404 */
pauldc63bfd2005-10-25 23:31:05 +00001405static int
paulc49ad8f2004-10-22 10:27:28 +00001406rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1407 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001408{
paul931cd542004-01-23 15:31:42 +00001409 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001410 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001411
1412 assert (ifc != NULL);
1413
paul931cd542004-01-23 15:31:42 +00001414 if (IS_RIP_DEBUG_PACKET)
1415 {
paulf69bd9d2005-06-03 18:01:50 +00001416#define ADDRESS_SIZE 20
1417 char dst[ADDRESS_SIZE];
1418 dst[ADDRESS_SIZE - 1] = '\0';
1419
paul931cd542004-01-23 15:31:42 +00001420 if (to)
1421 {
paulf69bd9d2005-06-03 18:01:50 +00001422 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001423 }
1424 else
1425 {
1426 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001427 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001428 }
paulf69bd9d2005-06-03 18:01:50 +00001429#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001430 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001431 inet_ntoa(ifc->address->u.prefix4),
1432 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001433 }
paulf69bd9d2005-06-03 18:01:50 +00001434
paulc49ad8f2004-10-22 10:27:28 +00001435 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001436 {
1437 /*
1438 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1439 * with multiple addresses on the same subnet: the first address
1440 * on the subnet is configured "primary", and all subsequent addresses
1441 * on that subnet are treated as "secondary" addresses.
1442 * In order to avoid routing-table bloat on other rip listeners,
1443 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1444 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1445 * flag is set, we would end up sending a packet for a "secondary"
1446 * source address on non-linux systems.
1447 */
1448 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001449 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001450 return 0;
1451 }
1452
paul718e3742002-12-13 20:15:29 +00001453 /* Make destination address. */
1454 memset (&sin, 0, sizeof (struct sockaddr_in));
1455 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001456#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001457 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001458#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001459
1460 /* When destination is specified, use it's port and address. */
1461 if (to)
1462 {
paul718e3742002-12-13 20:15:29 +00001463 sin.sin_port = to->sin_port;
1464 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001465 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001466 }
1467 else
1468 {
paul2c61ae32005-08-16 15:22:14 +00001469 struct sockaddr_in from;
1470
paul718e3742002-12-13 20:15:29 +00001471 sin.sin_port = htons (RIP_PORT_DEFAULT);
1472 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001473
1474 /* multicast send should bind to local interface address */
1475 from.sin_family = AF_INET;
1476 from.sin_port = htons (RIP_PORT_DEFAULT);
1477 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001478#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001479 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001480#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001481
paul931cd542004-01-23 15:31:42 +00001482 /*
1483 * we have to open a new socket for each packet because this
1484 * is the most portable way to bind to a different source
1485 * ipv4 address for each packet.
1486 */
paul2c61ae32005-08-16 15:22:14 +00001487 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001488 {
paulf69bd9d2005-06-03 18:01:50 +00001489 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001490 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001491 }
paulc49ad8f2004-10-22 10:27:28 +00001492 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001493 }
1494
paul931cd542004-01-23 15:31:42 +00001495 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001496 sizeof (struct sockaddr_in));
1497
1498 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001499 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001500 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001501
1502 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001503 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001504
paul931cd542004-01-23 15:31:42 +00001505 if (!to)
1506 close(send_sock);
1507
paul718e3742002-12-13 20:15:29 +00001508 return ret;
1509}
1510
1511/* Add redistributed route to RIP table. */
1512void
1513rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001514 unsigned int ifindex, struct in_addr *nexthop,
1515 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001516{
1517 int ret;
1518 struct route_node *rp;
1519 struct rip_info *rinfo;
1520
1521 /* Redistribute route */
1522 ret = rip_destination_check (p->prefix);
1523 if (! ret)
1524 return;
1525
1526 rp = route_node_get (rip->table, (struct prefix *) p);
1527
1528 rinfo = rp->info;
1529
1530 if (rinfo)
1531 {
1532 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1533 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1534 && rinfo->metric != RIP_METRIC_INFINITY)
1535 {
1536 route_unlock_node (rp);
1537 return;
1538 }
1539
1540 /* Manually configured RIP route check. */
1541 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001542 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1543 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001544 {
hasso16705132003-05-25 14:49:19 +00001545 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1546 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001547 {
1548 route_unlock_node (rp);
1549 return;
1550 }
1551 }
1552
1553 RIP_TIMER_OFF (rinfo->t_timeout);
1554 RIP_TIMER_OFF (rinfo->t_garbage_collect);
1555
1556 if (rip_route_rte (rinfo))
1557 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
1558 rinfo->metric);
1559 rp->info = NULL;
1560 rip_info_free (rinfo);
1561
1562 route_unlock_node (rp);
1563 }
1564
1565 rinfo = rip_info_new ();
1566
1567 rinfo->type = type;
1568 rinfo->sub_type = sub_type;
1569 rinfo->ifindex = ifindex;
1570 rinfo->metric = 1;
vincentfbf5d032005-09-29 11:25:50 +00001571 rinfo->external_metric = metric;
1572 rinfo->distance = distance;
paul718e3742002-12-13 20:15:29 +00001573 rinfo->rp = rp;
1574
1575 if (nexthop)
1576 rinfo->nexthop = *nexthop;
1577
1578 rinfo->flags |= RIP_RTF_FIB;
1579 rp->info = rinfo;
1580
1581 rinfo->flags |= RIP_RTF_CHANGED;
1582
hasso16705132003-05-25 14:49:19 +00001583 if (IS_RIP_DEBUG_EVENT) {
1584 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001585 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001586 inet_ntoa(p->prefix), p->prefixlen,
1587 ifindex2ifname(ifindex));
1588 else
ajs5d6c3772004-12-08 19:24:06 +00001589 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001590 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1591 ifindex2ifname(ifindex));
1592 }
1593
1594
paul718e3742002-12-13 20:15:29 +00001595 rip_event (RIP_TRIGGERED_UPDATE, 0);
1596}
1597
1598/* Delete redistributed route from RIP table. */
1599void
1600rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1601 unsigned int ifindex)
1602{
1603 int ret;
1604 struct route_node *rp;
1605 struct rip_info *rinfo;
1606
1607 ret = rip_destination_check (p->prefix);
1608 if (! ret)
1609 return;
1610
1611 rp = route_node_lookup (rip->table, (struct prefix *) p);
1612 if (rp)
1613 {
1614 rinfo = rp->info;
1615
1616 if (rinfo != NULL
1617 && rinfo->type == type
1618 && rinfo->sub_type == sub_type
1619 && rinfo->ifindex == ifindex)
1620 {
1621 /* Perform poisoned reverse. */
1622 rinfo->metric = RIP_METRIC_INFINITY;
1623 RIP_TIMER_ON (rinfo->t_garbage_collect,
1624 rip_garbage_collect, rip->garbage_time);
1625 RIP_TIMER_OFF (rinfo->t_timeout);
1626 rinfo->flags |= RIP_RTF_CHANGED;
1627
hasso16705132003-05-25 14:49:19 +00001628 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001629 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso16705132003-05-25 14:49:19 +00001630 inet_ntoa(p->prefix), p->prefixlen,
1631 ifindex2ifname(ifindex));
1632
paul718e3742002-12-13 20:15:29 +00001633 rip_event (RIP_TRIGGERED_UPDATE, 0);
1634 }
1635 }
1636}
1637
1638/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001639static void
paul718e3742002-12-13 20:15:29 +00001640rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001641 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001642{
1643 caddr_t lim;
1644 struct rte *rte;
1645 struct prefix_ipv4 p;
1646 struct route_node *rp;
1647 struct rip_info *rinfo;
1648 struct rip_interface *ri;
1649
hasso16705132003-05-25 14:49:19 +00001650 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001651 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001652 return;
1653
hasso429a0f82004-02-22 23:42:22 +00001654 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001655 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001656 if (! ri->running)
1657 return;
paul718e3742002-12-13 20:15:29 +00001658
1659 /* When passive interface is specified, suppress responses */
1660 if (ri->passive)
1661 return;
paulc49ad8f2004-10-22 10:27:28 +00001662
paul718e3742002-12-13 20:15:29 +00001663 /* RIP peer update. */
1664 rip_peer_update (from, packet->version);
1665
1666 lim = ((caddr_t) packet) + size;
1667 rte = packet->rte;
1668
1669 /* The Request is processed entry by entry. If there are no
1670 entries, no response is given. */
1671 if (lim == (caddr_t) rte)
1672 return;
1673
1674 /* There is one special case. If there is exactly one entry in the
1675 request, and it has an address family identifier of zero and a
1676 metric of infinity (i.e., 16), then this is a request to send the
1677 entire routing table. */
1678 if (lim == ((caddr_t) (rte + 1)) &&
1679 ntohs (rte->family) == 0 &&
1680 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1681 {
paulcc1131a2003-10-15 23:20:17 +00001682 struct prefix_ipv4 saddr;
1683
1684 /* saddr will be used for determining which routes to split-horizon.
1685 Since the source address we'll pick will be on the same subnet as the
1686 destination, for the purpose of split-horizoning, we'll
1687 pretend that "from" is our source address. */
1688 saddr.family = AF_INET;
1689 saddr.prefixlen = IPV4_MAX_BITLEN;
1690 saddr.prefix = from->sin_addr;
1691
paul718e3742002-12-13 20:15:29 +00001692 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001693 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001694 }
1695 else
1696 {
1697 /* Examine the list of RTEs in the Request one by one. For each
1698 entry, look up the destination in the router's routing
1699 database and, if there is a route, put that route's metric in
1700 the metric field of the RTE. If there is no explicit route
1701 to the specified destination, put infinity in the metric
1702 field. Once all the entries have been filled in, change the
1703 command from Request to Response and send the datagram back
1704 to the requestor. */
1705 p.family = AF_INET;
1706
1707 for (; ((caddr_t) rte) < lim; rte++)
1708 {
1709 p.prefix = rte->prefix;
1710 p.prefixlen = ip_masklen (rte->mask);
1711 apply_mask_ipv4 (&p);
1712
1713 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1714 if (rp)
1715 {
1716 rinfo = rp->info;
1717 rte->metric = htonl (rinfo->metric);
1718 route_unlock_node (rp);
1719 }
1720 else
1721 rte->metric = htonl (RIP_METRIC_INFINITY);
1722 }
1723 packet->command = RIP_RESPONSE;
1724
paulc49ad8f2004-10-22 10:27:28 +00001725 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001726 }
1727 rip_global_queries++;
1728}
1729
1730#if RIP_RECVMSG
1731/* Set IPv6 packet info to the socket. */
1732static int
1733setsockopt_pktinfo (int sock)
1734{
1735 int ret;
1736 int val = 1;
1737
1738 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1739 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001740 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001741 return ret;
1742}
1743
1744/* Read RIP packet by recvmsg function. */
1745int
1746rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1747 int *ifindex)
1748{
1749 int ret;
1750 struct msghdr msg;
1751 struct iovec iov;
1752 struct cmsghdr *ptr;
1753 char adata[1024];
1754
1755 msg.msg_name = (void *) from;
1756 msg.msg_namelen = sizeof (struct sockaddr_in);
1757 msg.msg_iov = &iov;
1758 msg.msg_iovlen = 1;
1759 msg.msg_control = (void *) adata;
1760 msg.msg_controllen = sizeof adata;
1761 iov.iov_base = buf;
1762 iov.iov_len = size;
1763
1764 ret = recvmsg (sock, &msg, 0);
1765 if (ret < 0)
1766 return ret;
1767
ajsb99760a2005-01-04 16:24:43 +00001768 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001769 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1770 {
1771 struct in_pktinfo *pktinfo;
1772 int i;
1773
1774 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1775 i = pktinfo->ipi_ifindex;
1776 }
1777 return ret;
1778}
1779
1780/* RIP packet read function. */
1781int
1782rip_read_new (struct thread *t)
1783{
1784 int ret;
1785 int sock;
1786 char buf[RIP_PACKET_MAXSIZ];
1787 struct sockaddr_in from;
1788 unsigned int ifindex;
1789
1790 /* Fetch socket then register myself. */
1791 sock = THREAD_FD (t);
1792 rip_event (RIP_READ, sock);
1793
1794 /* Read RIP packet. */
1795 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1796 if (ret < 0)
1797 {
ajs6099b3b2004-11-20 02:06:59 +00001798 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001799 return ret;
1800 }
1801
1802 return ret;
1803}
1804#endif /* RIP_RECVMSG */
1805
1806/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001807static int
paul718e3742002-12-13 20:15:29 +00001808rip_read (struct thread *t)
1809{
1810 int sock;
1811 int ret;
1812 int rtenum;
1813 union rip_buf rip_buf;
1814 struct rip_packet *packet;
1815 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001816 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001817 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001818 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001819 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001820 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001821 struct rip_interface *ri;
1822
1823 /* Fetch socket then register myself. */
1824 sock = THREAD_FD (t);
1825 rip->t_read = NULL;
1826
1827 /* Add myself to tne next event */
1828 rip_event (RIP_READ, sock);
1829
1830 /* RIPd manages only IPv4. */
1831 memset (&from, 0, sizeof (struct sockaddr_in));
1832 fromlen = sizeof (struct sockaddr_in);
1833
1834 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1835 (struct sockaddr *) &from, &fromlen);
1836 if (len < 0)
1837 {
ajs6099b3b2004-11-20 02:06:59 +00001838 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001839 return len;
1840 }
1841
1842 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001843 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001844 {
1845 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001846 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001847 return -1;
1848 }
1849
1850 /* Which interface is this packet comes from. */
1851 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001852
paul718e3742002-12-13 20:15:29 +00001853 /* RIP packet received */
1854 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001855 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001856 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1857 ifp ? ifp->name : "unknown");
1858
1859 /* If this packet come from unknown interface, ignore it. */
1860 if (ifp == NULL)
1861 {
ajs766a0ca2004-12-15 14:55:51 +00001862 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1863 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001864 return -1;
1865 }
1866
1867 ifc = connected_lookup_address (ifp, from.sin_addr);
1868
1869 if (ifc == NULL)
1870 {
ajs766a0ca2004-12-15 14:55:51 +00001871 zlog_info ("rip_read: cannot find connected address for packet from %s "
1872 "port %d on interface %s",
1873 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001874 return -1;
1875 }
1876
1877 /* Packet length check. */
1878 if (len < RIP_PACKET_MINSIZ)
1879 {
1880 zlog_warn ("packet size %d is smaller than minimum size %d",
1881 len, RIP_PACKET_MINSIZ);
1882 rip_peer_bad_packet (&from);
1883 return len;
1884 }
1885 if (len > RIP_PACKET_MAXSIZ)
1886 {
1887 zlog_warn ("packet size %d is larger than max size %d",
1888 len, RIP_PACKET_MAXSIZ);
1889 rip_peer_bad_packet (&from);
1890 return len;
1891 }
1892
1893 /* Packet alignment check. */
1894 if ((len - RIP_PACKET_MINSIZ) % 20)
1895 {
1896 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1897 rip_peer_bad_packet (&from);
1898 return len;
1899 }
1900
1901 /* Set RTE number. */
1902 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1903
1904 /* For easy to handle. */
1905 packet = &rip_buf.rip_packet;
1906
1907 /* RIP version check. */
1908 if (packet->version == 0)
1909 {
1910 zlog_info ("version 0 with command %d received.", packet->command);
1911 rip_peer_bad_packet (&from);
1912 return -1;
1913 }
1914
1915 /* Dump RIP packet. */
1916 if (IS_RIP_DEBUG_RECV)
1917 rip_packet_dump (packet, len, "RECV");
1918
1919 /* RIP version adjust. This code should rethink now. RFC1058 says
1920 that "Version 1 implementations are to ignore this extra data and
1921 process only the fields specified in this document.". So RIPv3
1922 packet should be treated as RIPv1 ignoring must be zero field. */
1923 if (packet->version > RIPv2)
1924 packet->version = RIPv2;
1925
1926 /* Is RIP running or is this RIP neighbor ?*/
1927 ri = ifp->info;
1928 if (! ri->running && ! rip_neighbor_lookup (&from))
1929 {
1930 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001931 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001932 rip_peer_bad_packet (&from);
1933 return -1;
1934 }
1935
Paul Jakma15a2b082006-05-04 07:36:34 +00001936 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001937 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1938 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001939 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001940 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001941 if (IS_RIP_DEBUG_PACKET)
1942 zlog_debug (" packet's v%d doesn't fit to if version spec",
1943 packet->version);
1944 rip_peer_bad_packet (&from);
1945 return -1;
paul718e3742002-12-13 20:15:29 +00001946 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001947 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1948 {
1949 if (IS_RIP_DEBUG_PACKET)
1950 zlog_debug (" packet's v%d doesn't fit to if version spec",
1951 packet->version);
1952 rip_peer_bad_packet (&from);
1953 return -1;
1954 }
1955
paul718e3742002-12-13 20:15:29 +00001956 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1957 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1958 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001959 if ((ri->auth_type == RIP_NO_AUTH)
1960 && rtenum
paulca5e5162004-06-06 22:06:33 +00001961 && (packet->version == RIPv2)
1962 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001963 {
1964 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001965 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001966 packet->version);
1967 rip_peer_bad_packet (&from);
1968 return -1;
1969 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001970
1971 /* RFC:
1972 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001973 RIP-1 messages and RIP-2 messages which pass authentication
1974 testing shall be accepted; unauthenticated and failed
1975 authentication RIP-2 messages shall be discarded. For maximum
1976 security, RIP-1 messages should be ignored when authentication is
1977 in use (see section 4.1); otherwise, the routing information from
1978 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001979 unauthenticated manner.
1980 */
1981 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1982 * always reply regardless of authentication settings, because:
1983 *
1984 * - if there other authorised routers on-link, the REQUESTor can
1985 * passively obtain the routing updates anyway
1986 * - if there are no other authorised routers on-link, RIP can
1987 * easily be disabled for the link to prevent giving out information
1988 * on state of this routers RIP routing table..
1989 *
1990 * I.e. if RIPv1 has any place anymore these days, it's as a very
1991 * simple way to distribute routing information (e.g. to embedded
1992 * hosts / appliances) and the ability to give out RIPv1
1993 * routing-information freely, while still requiring RIPv2
1994 * authentication for any RESPONSEs might be vaguely useful.
1995 */
1996 if (ri->auth_type != RIP_NO_AUTH
1997 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00001998 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001999 /* Discard RIPv1 messages other than REQUESTs */
2000 if (packet->command != RIP_REQUEST)
2001 {
2002 if (IS_RIP_DEBUG_PACKET)
2003 zlog_debug ("RIPv1" " dropped because authentication enabled");
2004 rip_peer_bad_packet (&from);
2005 return -1;
2006 }
2007 }
2008 else if (ri->auth_type != RIP_NO_AUTH)
2009 {
2010 const char *auth_desc;
2011
2012 if (rtenum == 0)
2013 {
2014 /* There definitely is no authentication in the packet. */
2015 if (IS_RIP_DEBUG_PACKET)
2016 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2017 rip_peer_bad_packet (&from);
2018 return -1;
2019 }
2020
2021 /* First RTE must be an Authentication Family RTE */
2022 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2023 {
2024 if (IS_RIP_DEBUG_PACKET)
2025 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002026 rip_peer_bad_packet (&from);
2027 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002028 }
2029
paul718e3742002-12-13 20:15:29 +00002030 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002031 switch (ntohs(packet->rte->tag))
2032 {
2033 case RIP_AUTH_SIMPLE_PASSWORD:
2034 auth_desc = "simple";
2035 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2036 break;
2037
2038 case RIP_AUTH_MD5:
2039 auth_desc = "MD5";
2040 ret = rip_auth_md5 (packet, &from, len, ifp);
2041 /* Reset RIP packet length to trim MD5 data. */
2042 len = ret;
2043 break;
2044
2045 default:
2046 ret = 0;
2047 auth_desc = "unknown type";
2048 if (IS_RIP_DEBUG_PACKET)
2049 zlog_debug ("RIPv2 Unknown authentication type %d",
2050 ntohs (packet->rte->tag));
2051 }
2052
2053 if (ret)
2054 {
2055 if (IS_RIP_DEBUG_PACKET)
2056 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2057 }
2058 else
2059 {
2060 if (IS_RIP_DEBUG_PACKET)
2061 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2062 rip_peer_bad_packet (&from);
2063 return -1;
2064 }
paul718e3742002-12-13 20:15:29 +00002065 }
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)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002448 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002449 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002450 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002451 /* 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);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002455 else
2456 /* do not know where to send the packet */
2457 return;
paulc49ad8f2004-10-22 10:27:28 +00002458 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002459
paulc49ad8f2004-10-22 10:27:28 +00002460 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002461 zlog_debug("%s announce to %s on %s",
2462 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2463 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002464
paulc49ad8f2004-10-22 10:27:28 +00002465 rip_output_process (ifc, &to, route_type, version);
2466 }
paul718e3742002-12-13 20:15:29 +00002467 }
2468}
2469
2470/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002471static void
paul718e3742002-12-13 20:15:29 +00002472rip_update_process (int route_type)
2473{
paul1eb8ef22005-04-07 07:30:20 +00002474 struct listnode *node;
2475 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002476 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002477 struct interface *ifp;
2478 struct rip_interface *ri;
2479 struct route_node *rp;
2480 struct sockaddr_in to;
2481 struct prefix_ipv4 *p;
2482
2483 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002484 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002485 {
paul718e3742002-12-13 20:15:29 +00002486 if (if_is_loopback (ifp))
2487 continue;
2488
paul2e3b2e42002-12-13 21:03:13 +00002489 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002490 continue;
2491
2492 /* Fetch RIP interface information. */
2493 ri = ifp->info;
2494
2495 /* When passive interface is specified, suppress announce to the
2496 interface. */
2497 if (ri->passive)
2498 continue;
2499
2500 if (ri->running)
2501 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002502 /*
2503 * If there is no version configuration in the interface,
2504 * use rip's version setting.
2505 */
2506 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2507 rip->version_send : ri->ri_send);
2508
paul718e3742002-12-13 20:15:29 +00002509 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002510 zlog_debug("SEND UPDATE to %s ifindex %d",
2511 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002512
paulcc1131a2003-10-15 23:20:17 +00002513 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002514 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002515 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002516 if (connected->address->family == AF_INET)
2517 {
2518 if (vsend & RIPv1)
2519 rip_update_interface (connected, RIPv1, route_type);
2520 if ((vsend & RIPv2) && if_is_multicast(ifp))
2521 rip_update_interface (connected, RIPv2, route_type);
2522 }
2523 }
paul718e3742002-12-13 20:15:29 +00002524 }
2525 }
2526
2527 /* RIP send updates to each neighbor. */
2528 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2529 if (rp->info != NULL)
2530 {
2531 p = (struct prefix_ipv4 *) &rp->p;
2532
2533 ifp = if_lookup_address (p->prefix);
2534 if (! ifp)
2535 {
paulc49ad8f2004-10-22 10:27:28 +00002536 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002537 inet_ntoa (p->prefix));
2538 continue;
2539 }
paulc49ad8f2004-10-22 10:27:28 +00002540
2541 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2542 {
2543 zlog_warn ("Neighbor %s doesnt have connected network",
2544 inet_ntoa (p->prefix));
2545 continue;
2546 }
2547
paul718e3742002-12-13 20:15:29 +00002548 /* Set destination address and port */
2549 memset (&to, 0, sizeof (struct sockaddr_in));
2550 to.sin_addr = p->prefix;
2551 to.sin_port = htons (RIP_PORT_DEFAULT);
2552
2553 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002554 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002555 }
2556}
2557
2558/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002559static int
paul718e3742002-12-13 20:15:29 +00002560rip_update (struct thread *t)
2561{
2562 /* Clear timer pointer. */
2563 rip->t_update = NULL;
2564
2565 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002566 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002567
2568 /* Process update output. */
2569 rip_update_process (rip_all_route);
2570
2571 /* Triggered updates may be suppressed if a regular update is due by
2572 the time the triggered update would be sent. */
2573 if (rip->t_triggered_interval)
2574 {
2575 thread_cancel (rip->t_triggered_interval);
2576 rip->t_triggered_interval = NULL;
2577 }
2578 rip->trigger = 0;
2579
2580 /* Register myself. */
2581 rip_event (RIP_UPDATE_EVENT, 0);
2582
2583 return 0;
2584}
2585
2586/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002587static void
paul216565a2005-10-25 23:35:28 +00002588rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002589{
2590 struct route_node *rp;
2591 struct rip_info *rinfo;
2592
2593 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2594 if ((rinfo = rp->info) != NULL)
2595 if (rinfo->flags & RIP_RTF_CHANGED)
2596 rinfo->flags &= ~RIP_RTF_CHANGED;
2597}
2598
2599/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002600static int
paul718e3742002-12-13 20:15:29 +00002601rip_triggered_interval (struct thread *t)
2602{
2603 int rip_triggered_update (struct thread *);
2604
2605 rip->t_triggered_interval = NULL;
2606
2607 if (rip->trigger)
2608 {
2609 rip->trigger = 0;
2610 rip_triggered_update (t);
2611 }
2612 return 0;
2613}
2614
2615/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002616static int
paul718e3742002-12-13 20:15:29 +00002617rip_triggered_update (struct thread *t)
2618{
2619 int interval;
2620
2621 /* Clear thred pointer. */
2622 rip->t_triggered_update = NULL;
2623
2624 /* Cancel interval timer. */
2625 if (rip->t_triggered_interval)
2626 {
2627 thread_cancel (rip->t_triggered_interval);
2628 rip->t_triggered_interval = NULL;
2629 }
2630 rip->trigger = 0;
2631
2632 /* Logging triggered update. */
2633 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002634 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002635
2636 /* Split Horizon processing is done when generating triggered
2637 updates as well as normal updates (see section 2.6). */
2638 rip_update_process (rip_changed_route);
2639
2640 /* Once all of the triggered updates have been generated, the route
2641 change flags should be cleared. */
2642 rip_clear_changed_flag ();
2643
2644 /* After a triggered update is sent, a timer should be set for a
2645 random interval between 1 and 5 seconds. If other changes that
2646 would trigger updates occur before the timer expires, a single
2647 update is triggered when the timer expires. */
2648 interval = (random () % 5) + 1;
2649
2650 rip->t_triggered_interval =
2651 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2652
2653 return 0;
2654}
2655
2656/* Withdraw redistributed route. */
2657void
2658rip_redistribute_withdraw (int type)
2659{
2660 struct route_node *rp;
2661 struct rip_info *rinfo;
2662
2663 if (!rip)
2664 return;
2665
2666 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2667 if ((rinfo = rp->info) != NULL)
2668 {
2669 if (rinfo->type == type
2670 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2671 {
2672 /* Perform poisoned reverse. */
2673 rinfo->metric = RIP_METRIC_INFINITY;
2674 RIP_TIMER_ON (rinfo->t_garbage_collect,
2675 rip_garbage_collect, rip->garbage_time);
2676 RIP_TIMER_OFF (rinfo->t_timeout);
2677 rinfo->flags |= RIP_RTF_CHANGED;
2678
hasso16705132003-05-25 14:49:19 +00002679 if (IS_RIP_DEBUG_EVENT) {
2680 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2681
ajs5d6c3772004-12-08 19:24:06 +00002682 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002683 inet_ntoa(p->prefix), p->prefixlen,
2684 ifindex2ifname(rinfo->ifindex));
2685 }
2686
paul718e3742002-12-13 20:15:29 +00002687 rip_event (RIP_TRIGGERED_UPDATE, 0);
2688 }
2689 }
2690}
2691
2692/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002693static int
2694rip_create (void)
paul718e3742002-12-13 20:15:29 +00002695{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002696 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002697
2698 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002699 rip->version_send = RI_RIP_VERSION_2;
2700 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002701 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2702 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2703 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2704 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2705
2706 /* Initialize RIP routig table. */
2707 rip->table = route_table_init ();
2708 rip->route = route_table_init ();
2709 rip->neighbor = route_table_init ();
2710
2711 /* Make output stream. */
2712 rip->obuf = stream_new (1500);
2713
2714 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002715 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002716 if (rip->sock < 0)
2717 return rip->sock;
2718
2719 /* Create read and timer thread. */
2720 rip_event (RIP_READ, rip->sock);
2721 rip_event (RIP_UPDATE_EVENT, 1);
2722
2723 return 0;
2724}
2725
2726/* Sned RIP request to the destination. */
2727int
2728rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002729 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002730{
2731 struct rte *rte;
2732 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002733 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002734
2735 memset (&rip_packet, 0, sizeof (rip_packet));
2736
2737 rip_packet.command = RIP_REQUEST;
2738 rip_packet.version = version;
2739 rte = rip_packet.rte;
2740 rte->metric = htonl (RIP_METRIC_INFINITY);
2741
paul931cd542004-01-23 15:31:42 +00002742 if (connected)
2743 {
2744 /*
2745 * connected is only sent for ripv1 case, or when
2746 * interface does not support multicast. Caller loops
2747 * over each connected address for this case.
2748 */
paul11dde9c2004-05-31 14:00:00 +00002749 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002750 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002751 return -1;
2752 else
2753 return sizeof (rip_packet);
2754 }
2755
paulcc1131a2003-10-15 23:20:17 +00002756 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002757 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002758 {
2759 struct prefix_ipv4 *p;
2760
2761 p = (struct prefix_ipv4 *) connected->address;
2762
2763 if (p->family != AF_INET)
2764 continue;
2765
paul11dde9c2004-05-31 14:00:00 +00002766 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002767 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002768 return -1;
2769 }
2770 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002771}
2772
pauldc63bfd2005-10-25 23:31:05 +00002773static int
paul718e3742002-12-13 20:15:29 +00002774rip_update_jitter (unsigned long time)
2775{
paul239389b2004-05-05 14:09:37 +00002776#define JITTER_BOUND 4
2777 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2778 Given that, we cannot let time be less than JITTER_BOUND seconds.
2779 The RIPv2 RFC says jitter should be small compared to
2780 update_time. We consider 1/JITTER_BOUND to be small.
2781 */
2782
2783 int jitter_input = time;
2784 int jitter;
2785
2786 if (jitter_input < JITTER_BOUND)
2787 jitter_input = JITTER_BOUND;
2788
2789 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2790
2791 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002792}
2793
2794void
2795rip_event (enum rip_event event, int sock)
2796{
2797 int jitter = 0;
2798
2799 switch (event)
2800 {
2801 case RIP_READ:
2802 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2803 break;
2804 case RIP_UPDATE_EVENT:
2805 if (rip->t_update)
2806 {
2807 thread_cancel (rip->t_update);
2808 rip->t_update = NULL;
2809 }
2810 jitter = rip_update_jitter (rip->update_time);
2811 rip->t_update =
2812 thread_add_timer (master, rip_update, NULL,
2813 sock ? 2 : rip->update_time + jitter);
2814 break;
2815 case RIP_TRIGGERED_UPDATE:
2816 if (rip->t_triggered_interval)
2817 rip->trigger = 1;
2818 else if (! rip->t_triggered_update)
2819 rip->t_triggered_update =
2820 thread_add_event (master, rip_triggered_update, NULL, 0);
2821 break;
2822 default:
2823 break;
2824 }
2825}
2826
2827DEFUN (router_rip,
2828 router_rip_cmd,
2829 "router rip",
2830 "Enable a routing process\n"
2831 "Routing Information Protocol (RIP)\n")
2832{
2833 int ret;
2834
2835 /* If rip is not enabled before. */
2836 if (! rip)
2837 {
2838 ret = rip_create ();
2839 if (ret < 0)
2840 {
2841 zlog_info ("Can't create RIP");
2842 return CMD_WARNING;
2843 }
2844 }
2845 vty->node = RIP_NODE;
2846 vty->index = rip;
2847
2848 return CMD_SUCCESS;
2849}
2850
2851DEFUN (no_router_rip,
2852 no_router_rip_cmd,
2853 "no router rip",
2854 NO_STR
2855 "Enable a routing process\n"
2856 "Routing Information Protocol (RIP)\n")
2857{
2858 if (rip)
2859 rip_clean ();
2860 return CMD_SUCCESS;
2861}
2862
2863DEFUN (rip_version,
2864 rip_version_cmd,
2865 "version <1-2>",
2866 "Set routing protocol version\n"
2867 "version\n")
2868{
2869 int version;
2870
2871 version = atoi (argv[0]);
2872 if (version != RIPv1 && version != RIPv2)
2873 {
2874 vty_out (vty, "invalid rip version %d%s", version,
2875 VTY_NEWLINE);
2876 return CMD_WARNING;
2877 }
paulf38a4712003-06-07 01:10:00 +00002878 rip->version_send = version;
2879 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002880
2881 return CMD_SUCCESS;
2882}
2883
2884DEFUN (no_rip_version,
2885 no_rip_version_cmd,
2886 "no version",
2887 NO_STR
2888 "Set routing protocol version\n")
2889{
2890 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002891 rip->version_send = RI_RIP_VERSION_2;
2892 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002893
2894 return CMD_SUCCESS;
2895}
2896
2897ALIAS (no_rip_version,
2898 no_rip_version_val_cmd,
2899 "no version <1-2>",
2900 NO_STR
2901 "Set routing protocol version\n"
2902 "version\n")
2903
2904DEFUN (rip_route,
2905 rip_route_cmd,
2906 "route A.B.C.D/M",
2907 "RIP static route configuration\n"
2908 "IP prefix <network>/<length>\n")
2909{
2910 int ret;
2911 struct prefix_ipv4 p;
2912 struct route_node *node;
2913
2914 ret = str2prefix_ipv4 (argv[0], &p);
2915 if (ret < 0)
2916 {
2917 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2918 return CMD_WARNING;
2919 }
2920 apply_mask_ipv4 (&p);
2921
2922 /* For router rip configuration. */
2923 node = route_node_get (rip->route, (struct prefix *) &p);
2924
2925 if (node->info)
2926 {
2927 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2928 route_unlock_node (node);
2929 return CMD_WARNING;
2930 }
2931
hasso8a676be2004-10-08 06:36:38 +00002932 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002933
vincentfbf5d032005-09-29 11:25:50 +00002934 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002935
2936 return CMD_SUCCESS;
2937}
2938
2939DEFUN (no_rip_route,
2940 no_rip_route_cmd,
2941 "no route A.B.C.D/M",
2942 NO_STR
2943 "RIP static route configuration\n"
2944 "IP prefix <network>/<length>\n")
2945{
2946 int ret;
2947 struct prefix_ipv4 p;
2948 struct route_node *node;
2949
2950 ret = str2prefix_ipv4 (argv[0], &p);
2951 if (ret < 0)
2952 {
2953 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2954 return CMD_WARNING;
2955 }
2956 apply_mask_ipv4 (&p);
2957
2958 /* For router rip configuration. */
2959 node = route_node_lookup (rip->route, (struct prefix *) &p);
2960 if (! node)
2961 {
2962 vty_out (vty, "Can't find route %s.%s", argv[0],
2963 VTY_NEWLINE);
2964 return CMD_WARNING;
2965 }
2966
2967 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2968 route_unlock_node (node);
2969
2970 node->info = NULL;
2971 route_unlock_node (node);
2972
2973 return CMD_SUCCESS;
2974}
2975
pauldc63bfd2005-10-25 23:31:05 +00002976static void
paul216565a2005-10-25 23:35:28 +00002977rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002978{
2979 struct route_node *np;
2980 struct rip_info *rinfo;
2981
2982 for (np = route_top (rip->table); np; np = route_next (np))
2983 if ((rinfo = np->info) != NULL)
2984 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2985 rinfo->metric = rip->default_metric;
2986}
2987
2988DEFUN (rip_default_metric,
2989 rip_default_metric_cmd,
2990 "default-metric <1-16>",
2991 "Set a metric of redistribute routes\n"
2992 "Default metric\n")
2993{
2994 if (rip)
2995 {
2996 rip->default_metric = atoi (argv[0]);
2997 /* rip_update_default_metric (); */
2998 }
2999 return CMD_SUCCESS;
3000}
3001
3002DEFUN (no_rip_default_metric,
3003 no_rip_default_metric_cmd,
3004 "no default-metric",
3005 NO_STR
3006 "Set a metric of redistribute routes\n"
3007 "Default metric\n")
3008{
3009 if (rip)
3010 {
3011 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3012 /* rip_update_default_metric (); */
3013 }
3014 return CMD_SUCCESS;
3015}
3016
3017ALIAS (no_rip_default_metric,
3018 no_rip_default_metric_val_cmd,
3019 "no default-metric <1-16>",
3020 NO_STR
3021 "Set a metric of redistribute routes\n"
3022 "Default metric\n")
3023
3024DEFUN (rip_timers,
3025 rip_timers_cmd,
3026 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3027 "Adjust routing timers\n"
3028 "Basic routing protocol update timers\n"
3029 "Routing table update timer value in second. Default is 30.\n"
3030 "Routing information timeout timer. Default is 180.\n"
3031 "Garbage collection timer. Default is 120.\n")
3032{
3033 unsigned long update;
3034 unsigned long timeout;
3035 unsigned long garbage;
3036 char *endptr = NULL;
3037 unsigned long RIP_TIMER_MAX = 2147483647;
3038 unsigned long RIP_TIMER_MIN = 5;
3039
3040 update = strtoul (argv[0], &endptr, 10);
3041 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3042 {
3043 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3044 return CMD_WARNING;
3045 }
3046
3047 timeout = strtoul (argv[1], &endptr, 10);
3048 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3049 {
3050 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3051 return CMD_WARNING;
3052 }
3053
3054 garbage = strtoul (argv[2], &endptr, 10);
3055 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3056 {
3057 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3058 return CMD_WARNING;
3059 }
3060
3061 /* Set each timer value. */
3062 rip->update_time = update;
3063 rip->timeout_time = timeout;
3064 rip->garbage_time = garbage;
3065
3066 /* Reset update timer thread. */
3067 rip_event (RIP_UPDATE_EVENT, 0);
3068
3069 return CMD_SUCCESS;
3070}
3071
3072DEFUN (no_rip_timers,
3073 no_rip_timers_cmd,
3074 "no timers basic",
3075 NO_STR
3076 "Adjust routing timers\n"
3077 "Basic routing protocol update timers\n")
3078{
3079 /* Set each timer value to the default. */
3080 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3081 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3082 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3083
3084 /* Reset update timer thread. */
3085 rip_event (RIP_UPDATE_EVENT, 0);
3086
3087 return CMD_SUCCESS;
3088}
hasso16705132003-05-25 14:49:19 +00003089
3090ALIAS (no_rip_timers,
3091 no_rip_timers_val_cmd,
3092 "no timers basic <0-65535> <0-65535> <0-65535>",
3093 NO_STR
3094 "Adjust routing timers\n"
3095 "Basic routing protocol update timers\n"
3096 "Routing table update timer value in second. Default is 30.\n"
3097 "Routing information timeout timer. Default is 180.\n"
3098 "Garbage collection timer. Default is 120.\n")
3099
paul718e3742002-12-13 20:15:29 +00003100
3101struct route_table *rip_distance_table;
3102
3103struct rip_distance
3104{
3105 /* Distance value for the IP source prefix. */
3106 u_char distance;
3107
3108 /* Name of the access-list to be matched. */
3109 char *access_list;
3110};
3111
pauldc63bfd2005-10-25 23:31:05 +00003112static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003113rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003114{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003115 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003116}
3117
pauldc63bfd2005-10-25 23:31:05 +00003118static void
paul718e3742002-12-13 20:15:29 +00003119rip_distance_free (struct rip_distance *rdistance)
3120{
3121 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3122}
3123
pauldc63bfd2005-10-25 23:31:05 +00003124static int
hasso98b718a2004-10-11 12:57:57 +00003125rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3126 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003127{
3128 int ret;
3129 struct prefix_ipv4 p;
3130 u_char distance;
3131 struct route_node *rn;
3132 struct rip_distance *rdistance;
3133
3134 ret = str2prefix_ipv4 (ip_str, &p);
3135 if (ret == 0)
3136 {
3137 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3138 return CMD_WARNING;
3139 }
3140
3141 distance = atoi (distance_str);
3142
3143 /* Get RIP distance node. */
3144 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3145 if (rn->info)
3146 {
3147 rdistance = rn->info;
3148 route_unlock_node (rn);
3149 }
3150 else
3151 {
3152 rdistance = rip_distance_new ();
3153 rn->info = rdistance;
3154 }
3155
3156 /* Set distance value. */
3157 rdistance->distance = distance;
3158
3159 /* Reset access-list configuration. */
3160 if (rdistance->access_list)
3161 {
3162 free (rdistance->access_list);
3163 rdistance->access_list = NULL;
3164 }
3165 if (access_list_str)
3166 rdistance->access_list = strdup (access_list_str);
3167
3168 return CMD_SUCCESS;
3169}
3170
pauldc63bfd2005-10-25 23:31:05 +00003171static int
hasso98b718a2004-10-11 12:57:57 +00003172rip_distance_unset (struct vty *vty, const char *distance_str,
3173 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003174{
3175 int ret;
3176 struct prefix_ipv4 p;
3177 u_char distance;
3178 struct route_node *rn;
3179 struct rip_distance *rdistance;
3180
3181 ret = str2prefix_ipv4 (ip_str, &p);
3182 if (ret == 0)
3183 {
3184 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3185 return CMD_WARNING;
3186 }
3187
3188 distance = atoi (distance_str);
3189
3190 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3191 if (! rn)
3192 {
3193 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3194 return CMD_WARNING;
3195 }
3196
3197 rdistance = rn->info;
3198
3199 if (rdistance->access_list)
3200 free (rdistance->access_list);
3201 rip_distance_free (rdistance);
3202
3203 rn->info = NULL;
3204 route_unlock_node (rn);
3205 route_unlock_node (rn);
3206
3207 return CMD_SUCCESS;
3208}
3209
pauldc63bfd2005-10-25 23:31:05 +00003210static void
paul216565a2005-10-25 23:35:28 +00003211rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003212{
3213 struct route_node *rn;
3214 struct rip_distance *rdistance;
3215
3216 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3217 if ((rdistance = rn->info) != NULL)
3218 {
3219 if (rdistance->access_list)
3220 free (rdistance->access_list);
3221 rip_distance_free (rdistance);
3222 rn->info = NULL;
3223 route_unlock_node (rn);
3224 }
3225}
3226
3227/* Apply RIP information to distance method. */
3228u_char
3229rip_distance_apply (struct rip_info *rinfo)
3230{
3231 struct route_node *rn;
3232 struct prefix_ipv4 p;
3233 struct rip_distance *rdistance;
3234 struct access_list *alist;
3235
3236 if (! rip)
3237 return 0;
3238
3239 memset (&p, 0, sizeof (struct prefix_ipv4));
3240 p.family = AF_INET;
3241 p.prefix = rinfo->from;
3242 p.prefixlen = IPV4_MAX_BITLEN;
3243
3244 /* Check source address. */
3245 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3246 if (rn)
3247 {
3248 rdistance = rn->info;
3249 route_unlock_node (rn);
3250
3251 if (rdistance->access_list)
3252 {
3253 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3254 if (alist == NULL)
3255 return 0;
3256 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3257 return 0;
3258
3259 return rdistance->distance;
3260 }
3261 else
3262 return rdistance->distance;
3263 }
3264
3265 if (rip->distance)
3266 return rip->distance;
3267
3268 return 0;
3269}
3270
pauldc63bfd2005-10-25 23:31:05 +00003271static void
paul718e3742002-12-13 20:15:29 +00003272rip_distance_show (struct vty *vty)
3273{
3274 struct route_node *rn;
3275 struct rip_distance *rdistance;
3276 int header = 1;
3277 char buf[BUFSIZ];
3278
3279 vty_out (vty, " Distance: (default is %d)%s",
3280 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3281 VTY_NEWLINE);
3282
3283 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3284 if ((rdistance = rn->info) != NULL)
3285 {
3286 if (header)
3287 {
3288 vty_out (vty, " Address Distance List%s",
3289 VTY_NEWLINE);
3290 header = 0;
3291 }
3292 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3293 vty_out (vty, " %-20s %4d %s%s",
3294 buf, rdistance->distance,
3295 rdistance->access_list ? rdistance->access_list : "",
3296 VTY_NEWLINE);
3297 }
3298}
3299
3300DEFUN (rip_distance,
3301 rip_distance_cmd,
3302 "distance <1-255>",
3303 "Administrative distance\n"
3304 "Distance value\n")
3305{
3306 rip->distance = atoi (argv[0]);
3307 return CMD_SUCCESS;
3308}
3309
3310DEFUN (no_rip_distance,
3311 no_rip_distance_cmd,
3312 "no distance <1-255>",
3313 NO_STR
3314 "Administrative distance\n"
3315 "Distance value\n")
3316{
3317 rip->distance = 0;
3318 return CMD_SUCCESS;
3319}
3320
3321DEFUN (rip_distance_source,
3322 rip_distance_source_cmd,
3323 "distance <1-255> A.B.C.D/M",
3324 "Administrative distance\n"
3325 "Distance value\n"
3326 "IP source prefix\n")
3327{
3328 rip_distance_set (vty, argv[0], argv[1], NULL);
3329 return CMD_SUCCESS;
3330}
3331
3332DEFUN (no_rip_distance_source,
3333 no_rip_distance_source_cmd,
3334 "no distance <1-255> A.B.C.D/M",
3335 NO_STR
3336 "Administrative distance\n"
3337 "Distance value\n"
3338 "IP source prefix\n")
3339{
3340 rip_distance_unset (vty, argv[0], argv[1], NULL);
3341 return CMD_SUCCESS;
3342}
3343
3344DEFUN (rip_distance_source_access_list,
3345 rip_distance_source_access_list_cmd,
3346 "distance <1-255> A.B.C.D/M WORD",
3347 "Administrative distance\n"
3348 "Distance value\n"
3349 "IP source prefix\n"
3350 "Access list name\n")
3351{
3352 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3353 return CMD_SUCCESS;
3354}
3355
3356DEFUN (no_rip_distance_source_access_list,
3357 no_rip_distance_source_access_list_cmd,
3358 "no distance <1-255> A.B.C.D/M WORD",
3359 NO_STR
3360 "Administrative distance\n"
3361 "Distance value\n"
3362 "IP source prefix\n"
3363 "Access list name\n")
3364{
3365 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3366 return CMD_SUCCESS;
3367}
3368
3369/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003370static void
paul718e3742002-12-13 20:15:29 +00003371rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3372{
paul718e3742002-12-13 20:15:29 +00003373 time_t clock;
3374 struct tm *tm;
3375#define TIME_BUF 25
3376 char timebuf [TIME_BUF];
3377 struct thread *thread;
3378
paul718e3742002-12-13 20:15:29 +00003379 if ((thread = rinfo->t_timeout) != NULL)
3380 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003381 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003382 tm = gmtime (&clock);
3383 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3384 vty_out (vty, "%5s", timebuf);
3385 }
3386 else if ((thread = rinfo->t_garbage_collect) != NULL)
3387 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003388 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003389 tm = gmtime (&clock);
3390 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3391 vty_out (vty, "%5s", timebuf);
3392 }
3393}
3394
pauldc63bfd2005-10-25 23:31:05 +00003395static const char *
paul718e3742002-12-13 20:15:29 +00003396rip_route_type_print (int sub_type)
3397{
3398 switch (sub_type)
3399 {
3400 case RIP_ROUTE_RTE:
3401 return "n";
3402 case RIP_ROUTE_STATIC:
3403 return "s";
3404 case RIP_ROUTE_DEFAULT:
3405 return "d";
3406 case RIP_ROUTE_REDISTRIBUTE:
3407 return "r";
3408 case RIP_ROUTE_INTERFACE:
3409 return "i";
3410 default:
3411 return "?";
3412 }
3413}
3414
3415DEFUN (show_ip_rip,
3416 show_ip_rip_cmd,
3417 "show ip rip",
3418 SHOW_STR
3419 IP_STR
3420 "Show RIP routes\n")
3421{
3422 struct route_node *np;
3423 struct rip_info *rinfo;
3424
3425 if (! rip)
3426 return CMD_SUCCESS;
3427
hasso16705132003-05-25 14:49:19 +00003428 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3429 "Sub-codes:%s"
3430 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003431 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003432 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003433 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003434
3435 for (np = route_top (rip->table); np; np = route_next (np))
3436 if ((rinfo = np->info) != NULL)
3437 {
3438 int len;
3439
ajsf52d13c2005-10-01 17:38:06 +00003440 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003441 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003442 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003443 rip_route_type_print (rinfo->sub_type),
3444 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3445
hassoa1455d82004-03-03 19:36:24 +00003446 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003447
3448 if (len > 0)
3449 vty_out (vty, "%*s", len, " ");
3450
3451 if (rinfo->nexthop.s_addr)
3452 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3453 rinfo->metric);
3454 else
3455 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3456
3457 /* Route which exist in kernel routing table. */
3458 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3459 (rinfo->sub_type == RIP_ROUTE_RTE))
3460 {
3461 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003462 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003463 rip_vty_out_uptime (vty, rinfo);
3464 }
3465 else if (rinfo->metric == RIP_METRIC_INFINITY)
3466 {
3467 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003468 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003469 rip_vty_out_uptime (vty, rinfo);
3470 }
3471 else
hasso16705132003-05-25 14:49:19 +00003472 {
vincentfbf5d032005-09-29 11:25:50 +00003473 if (rinfo->external_metric)
3474 {
3475 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003476 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003477 rinfo->external_metric);
3478 len = 16 - len;
3479 if (len > 0)
3480 vty_out (vty, "%*s", len, " ");
3481 }
3482 else
3483 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003484 vty_out (vty, "%3d", rinfo->tag);
3485 }
paul718e3742002-12-13 20:15:29 +00003486
3487 vty_out (vty, "%s", VTY_NEWLINE);
3488 }
3489 return CMD_SUCCESS;
3490}
3491
hasso16705132003-05-25 14:49:19 +00003492/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3493DEFUN (show_ip_rip_status,
3494 show_ip_rip_status_cmd,
3495 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003496 SHOW_STR
3497 IP_STR
hasso16705132003-05-25 14:49:19 +00003498 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003499 "IP routing protocol process parameters and statistics\n")
3500{
hasso52dc7ee2004-09-23 19:18:23 +00003501 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003502 struct interface *ifp;
3503 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003504 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003505 const char *send_version;
3506 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003507
3508 if (! rip)
3509 return CMD_SUCCESS;
3510
3511 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3512 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3513 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003514 vty_out (vty, " next due in %lu seconds%s",
3515 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003516 VTY_NEWLINE);
3517 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3518 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3519 VTY_NEWLINE);
3520
3521 /* Filtering status show. */
3522 config_show_distribute (vty);
3523
3524 /* Default metric information. */
3525 vty_out (vty, " Default redistribution metric is %d%s",
3526 rip->default_metric, VTY_NEWLINE);
3527
3528 /* Redistribute information. */
3529 vty_out (vty, " Redistributing:");
3530 config_write_rip_redistribute (vty, 0);
3531 vty_out (vty, "%s", VTY_NEWLINE);
3532
paulf38a4712003-06-07 01:10:00 +00003533 vty_out (vty, " Default version control: send version %s,",
3534 lookup(ri_version_msg,rip->version_send));
3535 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3536 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3537 else
3538 vty_out (vty, " receive version %s %s",
3539 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003540
3541 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3542
paul1eb8ef22005-04-07 07:30:20 +00003543 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003544 {
paul718e3742002-12-13 20:15:29 +00003545 ri = ifp->info;
3546
3547 if (ri->enable_network || ri->enable_interface)
3548 {
3549 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003550 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003551 else
3552 send_version = lookup (ri_version_msg, ri->ri_send);
3553
3554 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003555 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003556 else
3557 receive_version = lookup (ri_version_msg, ri->ri_receive);
3558
3559 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3560 send_version,
3561 receive_version,
3562 ri->key_chain ? ri->key_chain : "",
3563 VTY_NEWLINE);
3564 }
3565 }
3566
3567 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3568 config_write_rip_network (vty, 0);
3569
paul4aaff3f2003-06-07 01:04:45 +00003570 {
3571 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003572 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003573 {
paul4aaff3f2003-06-07 01:04:45 +00003574 ri = ifp->info;
3575
3576 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3577 {
3578 if (!found_passive)
3579 {
3580 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3581 found_passive = 1;
3582 }
3583 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3584 }
3585 }
3586 }
3587
paul718e3742002-12-13 20:15:29 +00003588 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3589 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3590 rip_peer_display (vty);
3591
3592 rip_distance_show (vty);
3593
3594 return CMD_SUCCESS;
3595}
3596
3597/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003598static int
paul718e3742002-12-13 20:15:29 +00003599config_write_rip (struct vty *vty)
3600{
3601 int write = 0;
3602 struct route_node *rn;
3603 struct rip_distance *rdistance;
3604
3605 if (rip)
3606 {
3607 /* Router RIP statement. */
3608 vty_out (vty, "router rip%s", VTY_NEWLINE);
3609 write++;
3610
3611 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003612 if (rip->version_send != RI_RIP_VERSION_2
3613 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3614 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003615 VTY_NEWLINE);
3616
3617 /* RIP timer configuration. */
3618 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3619 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3620 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3621 vty_out (vty, " timers basic %lu %lu %lu%s",
3622 rip->update_time,
3623 rip->timeout_time,
3624 rip->garbage_time,
3625 VTY_NEWLINE);
3626
3627 /* Default information configuration. */
3628 if (rip->default_information)
3629 {
3630 if (rip->default_information_route_map)
3631 vty_out (vty, " default-information originate route-map %s%s",
3632 rip->default_information_route_map, VTY_NEWLINE);
3633 else
3634 vty_out (vty, " default-information originate%s",
3635 VTY_NEWLINE);
3636 }
3637
3638 /* Redistribute configuration. */
3639 config_write_rip_redistribute (vty, 1);
3640
3641 /* RIP offset-list configuration. */
3642 config_write_rip_offset_list (vty);
3643
3644 /* RIP enabled network and interface configuration. */
3645 config_write_rip_network (vty, 1);
3646
3647 /* RIP default metric configuration */
3648 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3649 vty_out (vty, " default-metric %d%s",
3650 rip->default_metric, VTY_NEWLINE);
3651
3652 /* Distribute configuration. */
3653 write += config_write_distribute (vty);
3654
hasso16705132003-05-25 14:49:19 +00003655 /* Interface routemap configuration */
3656 write += config_write_if_rmap (vty);
3657
paul718e3742002-12-13 20:15:29 +00003658 /* Distance configuration. */
3659 if (rip->distance)
3660 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3661
3662 /* RIP source IP prefix distance configuration. */
3663 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3664 if ((rdistance = rn->info) != NULL)
3665 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3666 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3667 rdistance->access_list ? rdistance->access_list : "",
3668 VTY_NEWLINE);
3669
3670 /* RIP static route configuration. */
3671 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3672 if (rn->info)
3673 vty_out (vty, " route %s/%d%s",
3674 inet_ntoa (rn->p.u.prefix4),
3675 rn->p.prefixlen,
3676 VTY_NEWLINE);
3677
3678 }
3679 return write;
3680}
3681
3682/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003683static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003684{
3685 RIP_NODE,
3686 "%s(config-router)# ",
3687 1
3688};
3689
3690/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003691static void
paul718e3742002-12-13 20:15:29 +00003692rip_distribute_update (struct distribute *dist)
3693{
3694 struct interface *ifp;
3695 struct rip_interface *ri;
3696 struct access_list *alist;
3697 struct prefix_list *plist;
3698
3699 if (! dist->ifname)
3700 return;
3701
3702 ifp = if_lookup_by_name (dist->ifname);
3703 if (ifp == NULL)
3704 return;
3705
3706 ri = ifp->info;
3707
3708 if (dist->list[DISTRIBUTE_IN])
3709 {
3710 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3711 if (alist)
3712 ri->list[RIP_FILTER_IN] = alist;
3713 else
3714 ri->list[RIP_FILTER_IN] = NULL;
3715 }
3716 else
3717 ri->list[RIP_FILTER_IN] = NULL;
3718
3719 if (dist->list[DISTRIBUTE_OUT])
3720 {
3721 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3722 if (alist)
3723 ri->list[RIP_FILTER_OUT] = alist;
3724 else
3725 ri->list[RIP_FILTER_OUT] = NULL;
3726 }
3727 else
3728 ri->list[RIP_FILTER_OUT] = NULL;
3729
3730 if (dist->prefix[DISTRIBUTE_IN])
3731 {
3732 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3733 if (plist)
3734 ri->prefix[RIP_FILTER_IN] = plist;
3735 else
3736 ri->prefix[RIP_FILTER_IN] = NULL;
3737 }
3738 else
3739 ri->prefix[RIP_FILTER_IN] = NULL;
3740
3741 if (dist->prefix[DISTRIBUTE_OUT])
3742 {
3743 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3744 if (plist)
3745 ri->prefix[RIP_FILTER_OUT] = plist;
3746 else
3747 ri->prefix[RIP_FILTER_OUT] = NULL;
3748 }
3749 else
3750 ri->prefix[RIP_FILTER_OUT] = NULL;
3751}
3752
3753void
3754rip_distribute_update_interface (struct interface *ifp)
3755{
3756 struct distribute *dist;
3757
3758 dist = distribute_lookup (ifp->name);
3759 if (dist)
3760 rip_distribute_update (dist);
3761}
3762
3763/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003764/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003765static void
paul02ff83c2004-06-11 11:27:03 +00003766rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003767{
3768 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003769 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003770
paul1eb8ef22005-04-07 07:30:20 +00003771 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3772 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003773}
paul11dde9c2004-05-31 14:00:00 +00003774/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003775static void
paul11dde9c2004-05-31 14:00:00 +00003776rip_distribute_update_all_wrapper(struct access_list *notused)
3777{
paul02ff83c2004-06-11 11:27:03 +00003778 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003779}
paul718e3742002-12-13 20:15:29 +00003780
3781/* Delete all added rip route. */
3782void
paul216565a2005-10-25 23:35:28 +00003783rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003784{
3785 int i;
3786 struct route_node *rp;
3787 struct rip_info *rinfo;
3788
3789 if (rip)
3790 {
3791 /* Clear RIP routes */
3792 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3793 if ((rinfo = rp->info) != NULL)
3794 {
3795 if (rinfo->type == ZEBRA_ROUTE_RIP &&
3796 rinfo->sub_type == RIP_ROUTE_RTE)
3797 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
3798 &rinfo->nexthop, rinfo->metric);
3799
3800 RIP_TIMER_OFF (rinfo->t_timeout);
3801 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3802
3803 rp->info = NULL;
3804 route_unlock_node (rp);
3805
3806 rip_info_free (rinfo);
3807 }
3808
3809 /* Cancel RIP related timers. */
3810 RIP_TIMER_OFF (rip->t_update);
3811 RIP_TIMER_OFF (rip->t_triggered_update);
3812 RIP_TIMER_OFF (rip->t_triggered_interval);
3813
3814 /* Cancel read thread. */
3815 if (rip->t_read)
3816 {
3817 thread_cancel (rip->t_read);
3818 rip->t_read = NULL;
3819 }
3820
3821 /* Close RIP socket. */
3822 if (rip->sock >= 0)
3823 {
3824 close (rip->sock);
3825 rip->sock = -1;
3826 }
3827
3828 /* Static RIP route configuration. */
3829 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3830 if (rp->info)
3831 {
3832 rp->info = NULL;
3833 route_unlock_node (rp);
3834 }
3835
3836 /* RIP neighbor configuration. */
3837 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3838 if (rp->info)
3839 {
3840 rp->info = NULL;
3841 route_unlock_node (rp);
3842 }
3843
3844 /* Redistribute related clear. */
3845 if (rip->default_information_route_map)
3846 free (rip->default_information_route_map);
3847
3848 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3849 if (rip->route_map[i].name)
3850 free (rip->route_map[i].name);
3851
3852 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3853 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3854 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3855
3856 XFREE (MTYPE_RIP, rip);
3857 rip = NULL;
3858 }
3859
3860 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003861 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003862 rip_offset_clean ();
3863 rip_interface_clean ();
3864 rip_distance_reset ();
3865 rip_redistribute_clean ();
3866}
3867
3868/* Reset all values to the default settings. */
3869void
paul216565a2005-10-25 23:35:28 +00003870rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003871{
3872 /* Reset global counters. */
3873 rip_global_route_changes = 0;
3874 rip_global_queries = 0;
3875
3876 /* Call ripd related reset functions. */
3877 rip_debug_reset ();
3878 rip_route_map_reset ();
3879
3880 /* Call library reset functions. */
3881 vty_reset ();
3882 access_list_reset ();
3883 prefix_list_reset ();
3884
3885 distribute_list_reset ();
3886
3887 rip_interface_reset ();
3888 rip_distance_reset ();
3889
3890 rip_zclient_reset ();
3891}
3892
pauldc63bfd2005-10-25 23:31:05 +00003893static void
hasso16705132003-05-25 14:49:19 +00003894rip_if_rmap_update (struct if_rmap *if_rmap)
3895{
3896 struct interface *ifp;
3897 struct rip_interface *ri;
3898 struct route_map *rmap;
3899
3900 ifp = if_lookup_by_name (if_rmap->ifname);
3901 if (ifp == NULL)
3902 return;
3903
3904 ri = ifp->info;
3905
3906 if (if_rmap->routemap[IF_RMAP_IN])
3907 {
3908 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3909 if (rmap)
3910 ri->routemap[IF_RMAP_IN] = rmap;
3911 else
3912 ri->routemap[IF_RMAP_IN] = NULL;
3913 }
3914 else
3915 ri->routemap[RIP_FILTER_IN] = NULL;
3916
3917 if (if_rmap->routemap[IF_RMAP_OUT])
3918 {
3919 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3920 if (rmap)
3921 ri->routemap[IF_RMAP_OUT] = rmap;
3922 else
3923 ri->routemap[IF_RMAP_OUT] = NULL;
3924 }
3925 else
3926 ri->routemap[RIP_FILTER_OUT] = NULL;
3927}
3928
3929void
3930rip_if_rmap_update_interface (struct interface *ifp)
3931{
3932 struct if_rmap *if_rmap;
3933
3934 if_rmap = if_rmap_lookup (ifp->name);
3935 if (if_rmap)
3936 rip_if_rmap_update (if_rmap);
3937}
3938
pauldc63bfd2005-10-25 23:31:05 +00003939static void
hasso16705132003-05-25 14:49:19 +00003940rip_routemap_update_redistribute (void)
3941{
3942 int i;
3943
3944 if (rip)
3945 {
3946 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3947 {
3948 if (rip->route_map[i].name)
3949 rip->route_map[i].map =
3950 route_map_lookup_by_name (rip->route_map[i].name);
3951 }
3952 }
3953}
3954
paul11dde9c2004-05-31 14:00:00 +00003955/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003956static void
hasso98b718a2004-10-11 12:57:57 +00003957rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00003958{
3959 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003960 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00003961
paul1eb8ef22005-04-07 07:30:20 +00003962 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3963 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00003964
3965 rip_routemap_update_redistribute ();
3966}
3967
paul718e3742002-12-13 20:15:29 +00003968/* Allocate new rip structure and set default value. */
3969void
pauldc63bfd2005-10-25 23:31:05 +00003970rip_init (void)
paul718e3742002-12-13 20:15:29 +00003971{
3972 /* Randomize for triggered update random(). */
3973 srand (time (NULL));
3974
3975 /* Install top nodes. */
3976 install_node (&rip_node, config_write_rip);
3977
3978 /* Install rip commands. */
3979 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003980 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003981 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003982 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003983 install_element (CONFIG_NODE, &router_rip_cmd);
3984 install_element (CONFIG_NODE, &no_router_rip_cmd);
3985
3986 install_default (RIP_NODE);
3987 install_element (RIP_NODE, &rip_version_cmd);
3988 install_element (RIP_NODE, &no_rip_version_cmd);
3989 install_element (RIP_NODE, &no_rip_version_val_cmd);
3990 install_element (RIP_NODE, &rip_default_metric_cmd);
3991 install_element (RIP_NODE, &no_rip_default_metric_cmd);
3992 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
3993 install_element (RIP_NODE, &rip_timers_cmd);
3994 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00003995 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00003996 install_element (RIP_NODE, &rip_route_cmd);
3997 install_element (RIP_NODE, &no_rip_route_cmd);
3998 install_element (RIP_NODE, &rip_distance_cmd);
3999 install_element (RIP_NODE, &no_rip_distance_cmd);
4000 install_element (RIP_NODE, &rip_distance_source_cmd);
4001 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4002 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4003 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
4004
4005 /* Debug related init. */
4006 rip_debug_init ();
4007
paul718e3742002-12-13 20:15:29 +00004008 /* SNMP init. */
4009#ifdef HAVE_SNMP
4010 rip_snmp_init ();
4011#endif /* HAVE_SNMP */
4012
4013 /* Access list install. */
4014 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004015 access_list_add_hook (rip_distribute_update_all_wrapper);
4016 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004017
4018 /* Prefix list initialize.*/
4019 prefix_list_init ();
4020 prefix_list_add_hook (rip_distribute_update_all);
4021 prefix_list_delete_hook (rip_distribute_update_all);
4022
4023 /* Distribute list install. */
4024 distribute_list_init (RIP_NODE);
4025 distribute_list_add_hook (rip_distribute_update);
4026 distribute_list_delete_hook (rip_distribute_update);
4027
hasso16705132003-05-25 14:49:19 +00004028 /* Route-map */
4029 rip_route_map_init ();
4030 rip_offset_init ();
4031
4032 route_map_add_hook (rip_routemap_update);
4033 route_map_delete_hook (rip_routemap_update);
4034
4035 if_rmap_init (RIP_NODE);
4036 if_rmap_hook_add (rip_if_rmap_update);
4037 if_rmap_hook_delete (rip_if_rmap_update);
4038
paul718e3742002-12-13 20:15:29 +00004039 /* Distance control. */
4040 rip_distance_table = route_table_init ();
4041}