blob: 5a6dbc8c9a24b3ccb8152e7bf4ca0bbdc22387f5 [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 */
Stephen Hemminger78b31d52009-07-21 16:27:26 -07001375#ifdef IPTOS_PREC_INTERNETCONTROL
1376 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
1377#endif
paula4e987e2005-06-03 17:46:49 +00001378
1379 if (ripd_privs.change (ZPRIVS_RAISE))
1380 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001381 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1382 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1383
paula4e987e2005-06-03 17:46:49 +00001384 {
1385 int save_errno = errno;
1386 if (ripd_privs.change (ZPRIVS_LOWER))
1387 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001388
1389 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1390 sock, inet_ntoa(addr.sin_addr),
1391 (int) ntohs(addr.sin_port),
1392 safe_strerror(save_errno));
1393
paulf69bd9d2005-06-03 18:01:50 +00001394 close (sock);
paula4e987e2005-06-03 17:46:49 +00001395 return ret;
1396 }
paulf69bd9d2005-06-03 18:01:50 +00001397
paula4e987e2005-06-03 17:46:49 +00001398 if (ripd_privs.change (ZPRIVS_LOWER))
1399 zlog_err ("rip_create_socket: could not lower privs");
1400
1401 return sock;
1402}
1403
paulc49ad8f2004-10-22 10:27:28 +00001404/* RIP packet send to destination address, on interface denoted by
1405 * by connected argument. NULL to argument denotes destination should be
1406 * should be RIP multicast group
1407 */
pauldc63bfd2005-10-25 23:31:05 +00001408static int
paulc49ad8f2004-10-22 10:27:28 +00001409rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1410 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001411{
paul931cd542004-01-23 15:31:42 +00001412 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001413 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001414
1415 assert (ifc != NULL);
1416
paul931cd542004-01-23 15:31:42 +00001417 if (IS_RIP_DEBUG_PACKET)
1418 {
paulf69bd9d2005-06-03 18:01:50 +00001419#define ADDRESS_SIZE 20
1420 char dst[ADDRESS_SIZE];
1421 dst[ADDRESS_SIZE - 1] = '\0';
1422
paul931cd542004-01-23 15:31:42 +00001423 if (to)
1424 {
paulf69bd9d2005-06-03 18:01:50 +00001425 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001426 }
1427 else
1428 {
1429 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001430 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001431 }
paulf69bd9d2005-06-03 18:01:50 +00001432#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001433 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001434 inet_ntoa(ifc->address->u.prefix4),
1435 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001436 }
paulf69bd9d2005-06-03 18:01:50 +00001437
paulc49ad8f2004-10-22 10:27:28 +00001438 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001439 {
1440 /*
1441 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1442 * with multiple addresses on the same subnet: the first address
1443 * on the subnet is configured "primary", and all subsequent addresses
1444 * on that subnet are treated as "secondary" addresses.
1445 * In order to avoid routing-table bloat on other rip listeners,
1446 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1447 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1448 * flag is set, we would end up sending a packet for a "secondary"
1449 * source address on non-linux systems.
1450 */
1451 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001452 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001453 return 0;
1454 }
1455
paul718e3742002-12-13 20:15:29 +00001456 /* Make destination address. */
1457 memset (&sin, 0, sizeof (struct sockaddr_in));
1458 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001459#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001460 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001461#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001462
1463 /* When destination is specified, use it's port and address. */
1464 if (to)
1465 {
paul718e3742002-12-13 20:15:29 +00001466 sin.sin_port = to->sin_port;
1467 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001468 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001469 }
1470 else
1471 {
paul2c61ae32005-08-16 15:22:14 +00001472 struct sockaddr_in from;
1473
paul718e3742002-12-13 20:15:29 +00001474 sin.sin_port = htons (RIP_PORT_DEFAULT);
1475 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001476
1477 /* multicast send should bind to local interface address */
1478 from.sin_family = AF_INET;
1479 from.sin_port = htons (RIP_PORT_DEFAULT);
1480 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001481#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001482 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001483#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001484
paul931cd542004-01-23 15:31:42 +00001485 /*
1486 * we have to open a new socket for each packet because this
1487 * is the most portable way to bind to a different source
1488 * ipv4 address for each packet.
1489 */
paul2c61ae32005-08-16 15:22:14 +00001490 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001491 {
paulf69bd9d2005-06-03 18:01:50 +00001492 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001493 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001494 }
paulc49ad8f2004-10-22 10:27:28 +00001495 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001496 }
1497
paul931cd542004-01-23 15:31:42 +00001498 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001499 sizeof (struct sockaddr_in));
1500
1501 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001502 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001503 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001504
1505 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001506 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001507
paul931cd542004-01-23 15:31:42 +00001508 if (!to)
1509 close(send_sock);
1510
paul718e3742002-12-13 20:15:29 +00001511 return ret;
1512}
1513
1514/* Add redistributed route to RIP table. */
1515void
1516rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001517 unsigned int ifindex, struct in_addr *nexthop,
1518 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001519{
1520 int ret;
1521 struct route_node *rp;
1522 struct rip_info *rinfo;
1523
1524 /* Redistribute route */
1525 ret = rip_destination_check (p->prefix);
1526 if (! ret)
1527 return;
1528
1529 rp = route_node_get (rip->table, (struct prefix *) p);
1530
1531 rinfo = rp->info;
1532
1533 if (rinfo)
1534 {
1535 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1536 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1537 && rinfo->metric != RIP_METRIC_INFINITY)
1538 {
1539 route_unlock_node (rp);
1540 return;
1541 }
1542
1543 /* Manually configured RIP route check. */
1544 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001545 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1546 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001547 {
hasso16705132003-05-25 14:49:19 +00001548 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1549 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001550 {
1551 route_unlock_node (rp);
1552 return;
1553 }
1554 }
1555
1556 RIP_TIMER_OFF (rinfo->t_timeout);
1557 RIP_TIMER_OFF (rinfo->t_garbage_collect);
1558
1559 if (rip_route_rte (rinfo))
1560 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
1561 rinfo->metric);
1562 rp->info = NULL;
1563 rip_info_free (rinfo);
1564
1565 route_unlock_node (rp);
1566 }
1567
1568 rinfo = rip_info_new ();
1569
1570 rinfo->type = type;
1571 rinfo->sub_type = sub_type;
1572 rinfo->ifindex = ifindex;
1573 rinfo->metric = 1;
vincentfbf5d032005-09-29 11:25:50 +00001574 rinfo->external_metric = metric;
1575 rinfo->distance = distance;
paul718e3742002-12-13 20:15:29 +00001576 rinfo->rp = rp;
1577
1578 if (nexthop)
1579 rinfo->nexthop = *nexthop;
1580
1581 rinfo->flags |= RIP_RTF_FIB;
1582 rp->info = rinfo;
1583
1584 rinfo->flags |= RIP_RTF_CHANGED;
1585
hasso16705132003-05-25 14:49:19 +00001586 if (IS_RIP_DEBUG_EVENT) {
1587 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001588 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001589 inet_ntoa(p->prefix), p->prefixlen,
1590 ifindex2ifname(ifindex));
1591 else
ajs5d6c3772004-12-08 19:24:06 +00001592 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001593 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1594 ifindex2ifname(ifindex));
1595 }
1596
1597
paul718e3742002-12-13 20:15:29 +00001598 rip_event (RIP_TRIGGERED_UPDATE, 0);
1599}
1600
1601/* Delete redistributed route from RIP table. */
1602void
1603rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1604 unsigned int ifindex)
1605{
1606 int ret;
1607 struct route_node *rp;
1608 struct rip_info *rinfo;
1609
1610 ret = rip_destination_check (p->prefix);
1611 if (! ret)
1612 return;
1613
1614 rp = route_node_lookup (rip->table, (struct prefix *) p);
1615 if (rp)
1616 {
1617 rinfo = rp->info;
1618
1619 if (rinfo != NULL
1620 && rinfo->type == type
1621 && rinfo->sub_type == sub_type
1622 && rinfo->ifindex == ifindex)
1623 {
1624 /* Perform poisoned reverse. */
1625 rinfo->metric = RIP_METRIC_INFINITY;
1626 RIP_TIMER_ON (rinfo->t_garbage_collect,
1627 rip_garbage_collect, rip->garbage_time);
1628 RIP_TIMER_OFF (rinfo->t_timeout);
1629 rinfo->flags |= RIP_RTF_CHANGED;
1630
hasso16705132003-05-25 14:49:19 +00001631 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001632 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso16705132003-05-25 14:49:19 +00001633 inet_ntoa(p->prefix), p->prefixlen,
1634 ifindex2ifname(ifindex));
1635
paul718e3742002-12-13 20:15:29 +00001636 rip_event (RIP_TRIGGERED_UPDATE, 0);
1637 }
1638 }
1639}
1640
1641/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001642static void
paul718e3742002-12-13 20:15:29 +00001643rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001644 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001645{
1646 caddr_t lim;
1647 struct rte *rte;
1648 struct prefix_ipv4 p;
1649 struct route_node *rp;
1650 struct rip_info *rinfo;
1651 struct rip_interface *ri;
1652
hasso16705132003-05-25 14:49:19 +00001653 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001654 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001655 return;
1656
hasso429a0f82004-02-22 23:42:22 +00001657 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001658 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001659 if (! ri->running)
1660 return;
paul718e3742002-12-13 20:15:29 +00001661
1662 /* When passive interface is specified, suppress responses */
1663 if (ri->passive)
1664 return;
paulc49ad8f2004-10-22 10:27:28 +00001665
paul718e3742002-12-13 20:15:29 +00001666 /* RIP peer update. */
1667 rip_peer_update (from, packet->version);
1668
1669 lim = ((caddr_t) packet) + size;
1670 rte = packet->rte;
1671
1672 /* The Request is processed entry by entry. If there are no
1673 entries, no response is given. */
1674 if (lim == (caddr_t) rte)
1675 return;
1676
1677 /* There is one special case. If there is exactly one entry in the
1678 request, and it has an address family identifier of zero and a
1679 metric of infinity (i.e., 16), then this is a request to send the
1680 entire routing table. */
1681 if (lim == ((caddr_t) (rte + 1)) &&
1682 ntohs (rte->family) == 0 &&
1683 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1684 {
paulcc1131a2003-10-15 23:20:17 +00001685 struct prefix_ipv4 saddr;
1686
1687 /* saddr will be used for determining which routes to split-horizon.
1688 Since the source address we'll pick will be on the same subnet as the
1689 destination, for the purpose of split-horizoning, we'll
1690 pretend that "from" is our source address. */
1691 saddr.family = AF_INET;
1692 saddr.prefixlen = IPV4_MAX_BITLEN;
1693 saddr.prefix = from->sin_addr;
1694
paul718e3742002-12-13 20:15:29 +00001695 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001696 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001697 }
1698 else
1699 {
1700 /* Examine the list of RTEs in the Request one by one. For each
1701 entry, look up the destination in the router's routing
1702 database and, if there is a route, put that route's metric in
1703 the metric field of the RTE. If there is no explicit route
1704 to the specified destination, put infinity in the metric
1705 field. Once all the entries have been filled in, change the
1706 command from Request to Response and send the datagram back
1707 to the requestor. */
1708 p.family = AF_INET;
1709
1710 for (; ((caddr_t) rte) < lim; rte++)
1711 {
1712 p.prefix = rte->prefix;
1713 p.prefixlen = ip_masklen (rte->mask);
1714 apply_mask_ipv4 (&p);
1715
1716 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1717 if (rp)
1718 {
1719 rinfo = rp->info;
1720 rte->metric = htonl (rinfo->metric);
1721 route_unlock_node (rp);
1722 }
1723 else
1724 rte->metric = htonl (RIP_METRIC_INFINITY);
1725 }
1726 packet->command = RIP_RESPONSE;
1727
paulc49ad8f2004-10-22 10:27:28 +00001728 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001729 }
1730 rip_global_queries++;
1731}
1732
1733#if RIP_RECVMSG
1734/* Set IPv6 packet info to the socket. */
1735static int
1736setsockopt_pktinfo (int sock)
1737{
1738 int ret;
1739 int val = 1;
1740
1741 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1742 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001743 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001744 return ret;
1745}
1746
1747/* Read RIP packet by recvmsg function. */
1748int
1749rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1750 int *ifindex)
1751{
1752 int ret;
1753 struct msghdr msg;
1754 struct iovec iov;
1755 struct cmsghdr *ptr;
1756 char adata[1024];
1757
1758 msg.msg_name = (void *) from;
1759 msg.msg_namelen = sizeof (struct sockaddr_in);
1760 msg.msg_iov = &iov;
1761 msg.msg_iovlen = 1;
1762 msg.msg_control = (void *) adata;
1763 msg.msg_controllen = sizeof adata;
1764 iov.iov_base = buf;
1765 iov.iov_len = size;
1766
1767 ret = recvmsg (sock, &msg, 0);
1768 if (ret < 0)
1769 return ret;
1770
ajsb99760a2005-01-04 16:24:43 +00001771 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001772 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1773 {
1774 struct in_pktinfo *pktinfo;
1775 int i;
1776
1777 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1778 i = pktinfo->ipi_ifindex;
1779 }
1780 return ret;
1781}
1782
1783/* RIP packet read function. */
1784int
1785rip_read_new (struct thread *t)
1786{
1787 int ret;
1788 int sock;
1789 char buf[RIP_PACKET_MAXSIZ];
1790 struct sockaddr_in from;
1791 unsigned int ifindex;
1792
1793 /* Fetch socket then register myself. */
1794 sock = THREAD_FD (t);
1795 rip_event (RIP_READ, sock);
1796
1797 /* Read RIP packet. */
1798 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1799 if (ret < 0)
1800 {
ajs6099b3b2004-11-20 02:06:59 +00001801 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001802 return ret;
1803 }
1804
1805 return ret;
1806}
1807#endif /* RIP_RECVMSG */
1808
1809/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001810static int
paul718e3742002-12-13 20:15:29 +00001811rip_read (struct thread *t)
1812{
1813 int sock;
1814 int ret;
1815 int rtenum;
1816 union rip_buf rip_buf;
1817 struct rip_packet *packet;
1818 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001819 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001820 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001821 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001822 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001823 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001824 struct rip_interface *ri;
1825
1826 /* Fetch socket then register myself. */
1827 sock = THREAD_FD (t);
1828 rip->t_read = NULL;
1829
1830 /* Add myself to tne next event */
1831 rip_event (RIP_READ, sock);
1832
1833 /* RIPd manages only IPv4. */
1834 memset (&from, 0, sizeof (struct sockaddr_in));
1835 fromlen = sizeof (struct sockaddr_in);
1836
1837 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1838 (struct sockaddr *) &from, &fromlen);
1839 if (len < 0)
1840 {
ajs6099b3b2004-11-20 02:06:59 +00001841 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001842 return len;
1843 }
1844
1845 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001846 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001847 {
1848 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001849 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001850 return -1;
1851 }
1852
1853 /* Which interface is this packet comes from. */
1854 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001855
paul718e3742002-12-13 20:15:29 +00001856 /* RIP packet received */
1857 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001858 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001859 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1860 ifp ? ifp->name : "unknown");
1861
1862 /* If this packet come from unknown interface, ignore it. */
1863 if (ifp == NULL)
1864 {
ajs766a0ca2004-12-15 14:55:51 +00001865 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1866 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001867 return -1;
1868 }
1869
1870 ifc = connected_lookup_address (ifp, from.sin_addr);
1871
1872 if (ifc == NULL)
1873 {
ajs766a0ca2004-12-15 14:55:51 +00001874 zlog_info ("rip_read: cannot find connected address for packet from %s "
1875 "port %d on interface %s",
1876 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001877 return -1;
1878 }
1879
1880 /* Packet length check. */
1881 if (len < RIP_PACKET_MINSIZ)
1882 {
1883 zlog_warn ("packet size %d is smaller than minimum size %d",
1884 len, RIP_PACKET_MINSIZ);
1885 rip_peer_bad_packet (&from);
1886 return len;
1887 }
1888 if (len > RIP_PACKET_MAXSIZ)
1889 {
1890 zlog_warn ("packet size %d is larger than max size %d",
1891 len, RIP_PACKET_MAXSIZ);
1892 rip_peer_bad_packet (&from);
1893 return len;
1894 }
1895
1896 /* Packet alignment check. */
1897 if ((len - RIP_PACKET_MINSIZ) % 20)
1898 {
1899 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1900 rip_peer_bad_packet (&from);
1901 return len;
1902 }
1903
1904 /* Set RTE number. */
1905 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1906
1907 /* For easy to handle. */
1908 packet = &rip_buf.rip_packet;
1909
1910 /* RIP version check. */
1911 if (packet->version == 0)
1912 {
1913 zlog_info ("version 0 with command %d received.", packet->command);
1914 rip_peer_bad_packet (&from);
1915 return -1;
1916 }
1917
1918 /* Dump RIP packet. */
1919 if (IS_RIP_DEBUG_RECV)
1920 rip_packet_dump (packet, len, "RECV");
1921
1922 /* RIP version adjust. This code should rethink now. RFC1058 says
1923 that "Version 1 implementations are to ignore this extra data and
1924 process only the fields specified in this document.". So RIPv3
1925 packet should be treated as RIPv1 ignoring must be zero field. */
1926 if (packet->version > RIPv2)
1927 packet->version = RIPv2;
1928
1929 /* Is RIP running or is this RIP neighbor ?*/
1930 ri = ifp->info;
1931 if (! ri->running && ! rip_neighbor_lookup (&from))
1932 {
1933 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001934 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001935 rip_peer_bad_packet (&from);
1936 return -1;
1937 }
1938
Paul Jakma15a2b082006-05-04 07:36:34 +00001939 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001940 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1941 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001942 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001943 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001944 if (IS_RIP_DEBUG_PACKET)
1945 zlog_debug (" packet's v%d doesn't fit to if version spec",
1946 packet->version);
1947 rip_peer_bad_packet (&from);
1948 return -1;
paul718e3742002-12-13 20:15:29 +00001949 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001950 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1951 {
1952 if (IS_RIP_DEBUG_PACKET)
1953 zlog_debug (" packet's v%d doesn't fit to if version spec",
1954 packet->version);
1955 rip_peer_bad_packet (&from);
1956 return -1;
1957 }
1958
paul718e3742002-12-13 20:15:29 +00001959 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1960 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1961 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001962 if ((ri->auth_type == RIP_NO_AUTH)
1963 && rtenum
paulca5e5162004-06-06 22:06:33 +00001964 && (packet->version == RIPv2)
1965 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001966 {
1967 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001968 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001969 packet->version);
1970 rip_peer_bad_packet (&from);
1971 return -1;
1972 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001973
1974 /* RFC:
1975 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001976 RIP-1 messages and RIP-2 messages which pass authentication
1977 testing shall be accepted; unauthenticated and failed
1978 authentication RIP-2 messages shall be discarded. For maximum
1979 security, RIP-1 messages should be ignored when authentication is
1980 in use (see section 4.1); otherwise, the routing information from
1981 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001982 unauthenticated manner.
1983 */
1984 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1985 * always reply regardless of authentication settings, because:
1986 *
1987 * - if there other authorised routers on-link, the REQUESTor can
1988 * passively obtain the routing updates anyway
1989 * - if there are no other authorised routers on-link, RIP can
1990 * easily be disabled for the link to prevent giving out information
1991 * on state of this routers RIP routing table..
1992 *
1993 * I.e. if RIPv1 has any place anymore these days, it's as a very
1994 * simple way to distribute routing information (e.g. to embedded
1995 * hosts / appliances) and the ability to give out RIPv1
1996 * routing-information freely, while still requiring RIPv2
1997 * authentication for any RESPONSEs might be vaguely useful.
1998 */
1999 if (ri->auth_type != RIP_NO_AUTH
2000 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002001 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002002 /* Discard RIPv1 messages other than REQUESTs */
2003 if (packet->command != RIP_REQUEST)
2004 {
2005 if (IS_RIP_DEBUG_PACKET)
2006 zlog_debug ("RIPv1" " dropped because authentication enabled");
2007 rip_peer_bad_packet (&from);
2008 return -1;
2009 }
2010 }
2011 else if (ri->auth_type != RIP_NO_AUTH)
2012 {
2013 const char *auth_desc;
2014
2015 if (rtenum == 0)
2016 {
2017 /* There definitely is no authentication in the packet. */
2018 if (IS_RIP_DEBUG_PACKET)
2019 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2020 rip_peer_bad_packet (&from);
2021 return -1;
2022 }
2023
2024 /* First RTE must be an Authentication Family RTE */
2025 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2026 {
2027 if (IS_RIP_DEBUG_PACKET)
2028 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002029 rip_peer_bad_packet (&from);
2030 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002031 }
2032
paul718e3742002-12-13 20:15:29 +00002033 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002034 switch (ntohs(packet->rte->tag))
2035 {
2036 case RIP_AUTH_SIMPLE_PASSWORD:
2037 auth_desc = "simple";
2038 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2039 break;
2040
2041 case RIP_AUTH_MD5:
2042 auth_desc = "MD5";
2043 ret = rip_auth_md5 (packet, &from, len, ifp);
2044 /* Reset RIP packet length to trim MD5 data. */
2045 len = ret;
2046 break;
2047
2048 default:
2049 ret = 0;
2050 auth_desc = "unknown type";
2051 if (IS_RIP_DEBUG_PACKET)
2052 zlog_debug ("RIPv2 Unknown authentication type %d",
2053 ntohs (packet->rte->tag));
2054 }
2055
2056 if (ret)
2057 {
2058 if (IS_RIP_DEBUG_PACKET)
2059 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2060 }
2061 else
2062 {
2063 if (IS_RIP_DEBUG_PACKET)
2064 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2065 rip_peer_bad_packet (&from);
2066 return -1;
2067 }
paul718e3742002-12-13 20:15:29 +00002068 }
2069
2070 /* Process each command. */
2071 switch (packet->command)
2072 {
2073 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002074 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002075 break;
2076 case RIP_REQUEST:
2077 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002078 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002079 break;
2080 case RIP_TRACEON:
2081 case RIP_TRACEOFF:
2082 zlog_info ("Obsolete command %s received, please sent it to routed",
2083 lookup (rip_msg, packet->command));
2084 rip_peer_bad_packet (&from);
2085 break;
2086 case RIP_POLL_ENTRY:
2087 zlog_info ("Obsolete command %s received",
2088 lookup (rip_msg, packet->command));
2089 rip_peer_bad_packet (&from);
2090 break;
2091 default:
2092 zlog_info ("Unknown RIP command %d received", packet->command);
2093 rip_peer_bad_packet (&from);
2094 break;
2095 }
2096
2097 return len;
2098}
2099
paul718e3742002-12-13 20:15:29 +00002100/* Write routing table entry to the stream and return next index of
2101 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002102static int
paul718e3742002-12-13 20:15:29 +00002103rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002104 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002105{
2106 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002107
2108 /* Write routing table entry. */
2109 if (version == RIPv1)
2110 {
2111 stream_putw (s, AF_INET);
2112 stream_putw (s, 0);
2113 stream_put_ipv4 (s, p->prefix.s_addr);
2114 stream_put_ipv4 (s, 0);
2115 stream_put_ipv4 (s, 0);
2116 stream_putl (s, rinfo->metric_out);
2117 }
2118 else
2119 {
2120 masklen2ip (p->prefixlen, &mask);
2121
2122 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002123 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002124 stream_put_ipv4 (s, p->prefix.s_addr);
2125 stream_put_ipv4 (s, mask.s_addr);
2126 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2127 stream_putl (s, rinfo->metric_out);
2128 }
2129
2130 return ++num;
2131}
2132
2133/* Send update to the ifp or spcified neighbor. */
2134void
paulc49ad8f2004-10-22 10:27:28 +00002135rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2136 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002137{
2138 int ret;
2139 struct stream *s;
2140 struct route_node *rp;
2141 struct rip_info *rinfo;
2142 struct rip_interface *ri;
2143 struct prefix_ipv4 *p;
2144 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002145 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002146 struct key *key = NULL;
2147 /* this might need to made dynamic if RIP ever supported auth methods
2148 with larger key string sizes */
2149 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002150 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002151 int num = 0;
paul718e3742002-12-13 20:15:29 +00002152 int rtemax;
paul01d09082003-06-08 21:22:18 +00002153 int subnetted = 0;
paul718e3742002-12-13 20:15:29 +00002154
2155 /* Logging output event. */
2156 if (IS_RIP_DEBUG_EVENT)
2157 {
2158 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002159 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002160 else
ajs5d6c3772004-12-08 19:24:06 +00002161 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002162 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002163 }
2164
2165 /* Set output stream. */
2166 s = rip->obuf;
2167
2168 /* Reset stream and RTE counter. */
2169 stream_reset (s);
paul718e3742002-12-13 20:15:29 +00002170 rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
2171
2172 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002173 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002174
2175 /* If output interface is in simple password authentication mode, we
2176 need space for authentication data. */
2177 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2178 rtemax -= 1;
2179
2180 /* If output interface is in MD5 authentication mode, we need space
2181 for authentication header and data. */
2182 if (ri->auth_type == RIP_AUTH_MD5)
2183 rtemax -= 2;
2184
2185 /* If output interface is in simple password authentication mode
2186 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002187 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002188 {
2189 if (ri->key_chain)
2190 {
2191 struct keychain *keychain;
2192
2193 keychain = keychain_lookup (ri->key_chain);
2194 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002195 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002196 }
paulb14ee002005-02-04 23:42:41 +00002197 /* to be passed to auth functions later */
2198 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002199 }
2200
paul727d1042002-12-13 20:50:29 +00002201 if (version == RIPv1)
2202 {
paulc49ad8f2004-10-22 10:27:28 +00002203 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002204 apply_classful_mask_ipv4 (&ifaddrclass);
2205 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002206 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002207 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002208 }
2209
paul718e3742002-12-13 20:15:29 +00002210 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2211 if ((rinfo = rp->info) != NULL)
2212 {
paul727d1042002-12-13 20:50:29 +00002213 /* For RIPv1, if we are subnetted, output subnets in our network */
2214 /* that have the same mask as the output "interface". For other */
2215 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002216
2217 if (version == RIPv1)
2218 {
paul727d1042002-12-13 20:50:29 +00002219 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002220
2221 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002222 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002223 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002224
paul727d1042002-12-13 20:50:29 +00002225 if (subnetted &&
2226 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2227 {
paulc49ad8f2004-10-22 10:27:28 +00002228 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002229 (rp->p.prefixlen != 32))
2230 continue;
2231 }
2232 else
2233 {
2234 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2235 apply_classful_mask_ipv4(&classfull);
2236 if (rp->p.u.prefix4.s_addr != 0 &&
2237 classfull.prefixlen != rp->p.prefixlen)
2238 continue;
2239 }
paul718e3742002-12-13 20:15:29 +00002240 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002241 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002242 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002243 }
2244 else
2245 p = (struct prefix_ipv4 *) &rp->p;
2246
2247 /* Apply output filters. */
2248 ret = rip_outgoing_filter (p, ri);
2249 if (ret < 0)
2250 continue;
2251
2252 /* Changed route only output. */
2253 if (route_type == rip_changed_route &&
2254 (! (rinfo->flags & RIP_RTF_CHANGED)))
2255 continue;
2256
2257 /* Split horizon. */
2258 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002259 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002260 {
paul42d14d92003-11-17 09:15:18 +00002261 /*
2262 * We perform split horizon for RIP and connected route.
2263 * For rip routes, we want to suppress the route if we would
2264 * end up sending the route back on the interface that we
2265 * learned it from, with a higher metric. For connected routes,
2266 * we suppress the route if the prefix is a subset of the
2267 * source address that we are going to use for the packet
2268 * (in order to handle the case when multiple subnets are
2269 * configured on the same interface).
2270 */
2271 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002272 rinfo->ifindex == ifc->ifp->ifindex)
paul42d14d92003-11-17 09:15:18 +00002273 continue;
2274 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002275 prefix_match((struct prefix *)p, ifc->address))
paul718e3742002-12-13 20:15:29 +00002276 continue;
2277 }
2278
2279 /* Preparation for route-map. */
2280 rinfo->metric_set = 0;
2281 rinfo->nexthop_out.s_addr = 0;
2282 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002283 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002284 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002285
hasso16705132003-05-25 14:49:19 +00002286 /* In order to avoid some local loops,
2287 * if the RIP route has a nexthop via this interface, keep the nexthop,
2288 * otherwise set it to 0. The nexthop should not be propagated
2289 * beyond the local broadcast/multicast area in order
2290 * to avoid an IGP multi-level recursive look-up.
2291 * see (4.4)
2292 */
paulc49ad8f2004-10-22 10:27:28 +00002293 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002294 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002295
2296 /* Interface route-map */
2297 if (ri->routemap[RIP_FILTER_OUT])
2298 {
2299 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2300 (struct prefix *) p, RMAP_RIP,
2301 rinfo);
2302
2303 if (ret == RMAP_DENYMATCH)
2304 {
2305 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002306 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002307 inet_ntoa (p->prefix), p->prefixlen);
2308 continue;
2309 }
2310 }
paul718e3742002-12-13 20:15:29 +00002311
hasso16705132003-05-25 14:49:19 +00002312 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002313 if (rip->route_map[rinfo->type].name
2314 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2315 {
2316 ret = route_map_apply (rip->route_map[rinfo->type].map,
2317 (struct prefix *)p, RMAP_RIP, rinfo);
2318
2319 if (ret == RMAP_DENYMATCH)
2320 {
2321 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002322 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002323 inet_ntoa (p->prefix), p->prefixlen);
2324 continue;
2325 }
2326 }
2327
2328 /* When route-map does not set metric. */
2329 if (! rinfo->metric_set)
2330 {
2331 /* If redistribute metric is set. */
2332 if (rip->route_map[rinfo->type].metric_config
2333 && rinfo->metric != RIP_METRIC_INFINITY)
2334 {
2335 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2336 }
2337 else
2338 {
2339 /* If the route is not connected or localy generated
2340 one, use default-metric value*/
2341 if (rinfo->type != ZEBRA_ROUTE_RIP
2342 && rinfo->type != ZEBRA_ROUTE_CONNECT
2343 && rinfo->metric != RIP_METRIC_INFINITY)
2344 rinfo->metric_out = rip->default_metric;
2345 }
2346 }
2347
2348 /* Apply offset-list */
2349 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002350 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002351
2352 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2353 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002354
2355 /* Perform split-horizon with poisoned reverse
2356 * for RIP and connected routes.
2357 **/
2358 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002359 /*
2360 * We perform split horizon for RIP and connected route.
2361 * For rip routes, we want to suppress the route if we would
2362 * end up sending the route back on the interface that we
2363 * learned it from, with a higher metric. For connected routes,
2364 * we suppress the route if the prefix is a subset of the
2365 * source address that we are going to use for the packet
2366 * (in order to handle the case when multiple subnets are
2367 * configured on the same interface).
2368 */
2369 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002370 rinfo->ifindex == ifc->ifp->ifindex)
hasso16705132003-05-25 14:49:19 +00002371 rinfo->metric_out = RIP_METRIC_INFINITY;
paul42d14d92003-11-17 09:15:18 +00002372 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002373 prefix_match((struct prefix *)p, ifc->address))
paul42d14d92003-11-17 09:15:18 +00002374 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002375 }
paulb14ee002005-02-04 23:42:41 +00002376
2377 /* Prepare preamble, auth headers, if needs be */
2378 if (num == 0)
2379 {
2380 stream_putc (s, RIP_RESPONSE);
2381 stream_putc (s, version);
2382 stream_putw (s, 0);
2383
paul0cb8a012005-05-29 11:27:24 +00002384 /* auth header for !v1 && !no_auth */
2385 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002386 doff = rip_auth_header_write (s, ri, key, auth_str,
2387 RIP_AUTH_SIMPLE_SIZE);
2388 }
2389
paul718e3742002-12-13 20:15:29 +00002390 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002391 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002392 if (num == rtemax)
2393 {
2394 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002395 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002396
2397 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002398 to, ifc);
paul718e3742002-12-13 20:15:29 +00002399
2400 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2401 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2402 stream_get_endp(s), "SEND");
2403 num = 0;
2404 stream_reset (s);
2405 }
2406 }
2407
2408 /* Flush unwritten RTE. */
2409 if (num != 0)
2410 {
2411 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002412 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002413
paulc49ad8f2004-10-22 10:27:28 +00002414 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002415
2416 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2417 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2418 stream_get_endp (s), "SEND");
2419 num = 0;
2420 stream_reset (s);
2421 }
2422
2423 /* Statistics updates. */
2424 ri->sent_updates++;
2425}
2426
2427/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002428static void
paulc49ad8f2004-10-22 10:27:28 +00002429rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002430{
paul718e3742002-12-13 20:15:29 +00002431 struct sockaddr_in to;
2432
2433 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002434 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002435 {
2436 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002437 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002438
paulc49ad8f2004-10-22 10:27:28 +00002439 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002440 return;
2441 }
paulc49ad8f2004-10-22 10:27:28 +00002442
paul718e3742002-12-13 20:15:29 +00002443 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002444 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002445 {
paulc49ad8f2004-10-22 10:27:28 +00002446 if (ifc->address->family == AF_INET)
2447 {
2448 /* Destination address and port setting. */
2449 memset (&to, 0, sizeof (struct sockaddr_in));
2450 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002451 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002452 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002453 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002454 /* calculate the appropriate broadcast address */
2455 to.sin_addr.s_addr =
2456 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2457 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002458 else
2459 /* do not know where to send the packet */
2460 return;
paulc49ad8f2004-10-22 10:27:28 +00002461 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002462
paulc49ad8f2004-10-22 10:27:28 +00002463 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002464 zlog_debug("%s announce to %s on %s",
2465 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2466 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002467
paulc49ad8f2004-10-22 10:27:28 +00002468 rip_output_process (ifc, &to, route_type, version);
2469 }
paul718e3742002-12-13 20:15:29 +00002470 }
2471}
2472
2473/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002474static void
paul718e3742002-12-13 20:15:29 +00002475rip_update_process (int route_type)
2476{
paul1eb8ef22005-04-07 07:30:20 +00002477 struct listnode *node;
2478 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002479 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002480 struct interface *ifp;
2481 struct rip_interface *ri;
2482 struct route_node *rp;
2483 struct sockaddr_in to;
2484 struct prefix_ipv4 *p;
2485
2486 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002487 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002488 {
paul718e3742002-12-13 20:15:29 +00002489 if (if_is_loopback (ifp))
2490 continue;
2491
paul2e3b2e42002-12-13 21:03:13 +00002492 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002493 continue;
2494
2495 /* Fetch RIP interface information. */
2496 ri = ifp->info;
2497
2498 /* When passive interface is specified, suppress announce to the
2499 interface. */
2500 if (ri->passive)
2501 continue;
2502
2503 if (ri->running)
2504 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002505 /*
2506 * If there is no version configuration in the interface,
2507 * use rip's version setting.
2508 */
2509 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2510 rip->version_send : ri->ri_send);
2511
paul718e3742002-12-13 20:15:29 +00002512 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002513 zlog_debug("SEND UPDATE to %s ifindex %d",
2514 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002515
paulcc1131a2003-10-15 23:20:17 +00002516 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002517 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002518 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002519 if (connected->address->family == AF_INET)
2520 {
2521 if (vsend & RIPv1)
2522 rip_update_interface (connected, RIPv1, route_type);
2523 if ((vsend & RIPv2) && if_is_multicast(ifp))
2524 rip_update_interface (connected, RIPv2, route_type);
2525 }
2526 }
paul718e3742002-12-13 20:15:29 +00002527 }
2528 }
2529
2530 /* RIP send updates to each neighbor. */
2531 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2532 if (rp->info != NULL)
2533 {
2534 p = (struct prefix_ipv4 *) &rp->p;
2535
2536 ifp = if_lookup_address (p->prefix);
2537 if (! ifp)
2538 {
paulc49ad8f2004-10-22 10:27:28 +00002539 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002540 inet_ntoa (p->prefix));
2541 continue;
2542 }
paulc49ad8f2004-10-22 10:27:28 +00002543
2544 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2545 {
2546 zlog_warn ("Neighbor %s doesnt have connected network",
2547 inet_ntoa (p->prefix));
2548 continue;
2549 }
2550
paul718e3742002-12-13 20:15:29 +00002551 /* Set destination address and port */
2552 memset (&to, 0, sizeof (struct sockaddr_in));
2553 to.sin_addr = p->prefix;
2554 to.sin_port = htons (RIP_PORT_DEFAULT);
2555
2556 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002557 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002558 }
2559}
2560
2561/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002562static int
paul718e3742002-12-13 20:15:29 +00002563rip_update (struct thread *t)
2564{
2565 /* Clear timer pointer. */
2566 rip->t_update = NULL;
2567
2568 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002569 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002570
2571 /* Process update output. */
2572 rip_update_process (rip_all_route);
2573
2574 /* Triggered updates may be suppressed if a regular update is due by
2575 the time the triggered update would be sent. */
2576 if (rip->t_triggered_interval)
2577 {
2578 thread_cancel (rip->t_triggered_interval);
2579 rip->t_triggered_interval = NULL;
2580 }
2581 rip->trigger = 0;
2582
2583 /* Register myself. */
2584 rip_event (RIP_UPDATE_EVENT, 0);
2585
2586 return 0;
2587}
2588
2589/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002590static void
paul216565a2005-10-25 23:35:28 +00002591rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002592{
2593 struct route_node *rp;
2594 struct rip_info *rinfo;
2595
2596 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2597 if ((rinfo = rp->info) != NULL)
2598 if (rinfo->flags & RIP_RTF_CHANGED)
2599 rinfo->flags &= ~RIP_RTF_CHANGED;
2600}
2601
2602/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002603static int
paul718e3742002-12-13 20:15:29 +00002604rip_triggered_interval (struct thread *t)
2605{
2606 int rip_triggered_update (struct thread *);
2607
2608 rip->t_triggered_interval = NULL;
2609
2610 if (rip->trigger)
2611 {
2612 rip->trigger = 0;
2613 rip_triggered_update (t);
2614 }
2615 return 0;
2616}
2617
2618/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002619static int
paul718e3742002-12-13 20:15:29 +00002620rip_triggered_update (struct thread *t)
2621{
2622 int interval;
2623
2624 /* Clear thred pointer. */
2625 rip->t_triggered_update = NULL;
2626
2627 /* Cancel interval timer. */
2628 if (rip->t_triggered_interval)
2629 {
2630 thread_cancel (rip->t_triggered_interval);
2631 rip->t_triggered_interval = NULL;
2632 }
2633 rip->trigger = 0;
2634
2635 /* Logging triggered update. */
2636 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002637 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002638
2639 /* Split Horizon processing is done when generating triggered
2640 updates as well as normal updates (see section 2.6). */
2641 rip_update_process (rip_changed_route);
2642
2643 /* Once all of the triggered updates have been generated, the route
2644 change flags should be cleared. */
2645 rip_clear_changed_flag ();
2646
2647 /* After a triggered update is sent, a timer should be set for a
2648 random interval between 1 and 5 seconds. If other changes that
2649 would trigger updates occur before the timer expires, a single
2650 update is triggered when the timer expires. */
2651 interval = (random () % 5) + 1;
2652
2653 rip->t_triggered_interval =
2654 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2655
2656 return 0;
2657}
2658
2659/* Withdraw redistributed route. */
2660void
2661rip_redistribute_withdraw (int type)
2662{
2663 struct route_node *rp;
2664 struct rip_info *rinfo;
2665
2666 if (!rip)
2667 return;
2668
2669 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2670 if ((rinfo = rp->info) != NULL)
2671 {
2672 if (rinfo->type == type
2673 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2674 {
2675 /* Perform poisoned reverse. */
2676 rinfo->metric = RIP_METRIC_INFINITY;
2677 RIP_TIMER_ON (rinfo->t_garbage_collect,
2678 rip_garbage_collect, rip->garbage_time);
2679 RIP_TIMER_OFF (rinfo->t_timeout);
2680 rinfo->flags |= RIP_RTF_CHANGED;
2681
hasso16705132003-05-25 14:49:19 +00002682 if (IS_RIP_DEBUG_EVENT) {
2683 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2684
ajs5d6c3772004-12-08 19:24:06 +00002685 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002686 inet_ntoa(p->prefix), p->prefixlen,
2687 ifindex2ifname(rinfo->ifindex));
2688 }
2689
paul718e3742002-12-13 20:15:29 +00002690 rip_event (RIP_TRIGGERED_UPDATE, 0);
2691 }
2692 }
2693}
2694
2695/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002696static int
2697rip_create (void)
paul718e3742002-12-13 20:15:29 +00002698{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002699 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002700
2701 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002702 rip->version_send = RI_RIP_VERSION_2;
2703 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002704 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2705 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2706 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2707 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2708
2709 /* Initialize RIP routig table. */
2710 rip->table = route_table_init ();
2711 rip->route = route_table_init ();
2712 rip->neighbor = route_table_init ();
2713
2714 /* Make output stream. */
2715 rip->obuf = stream_new (1500);
2716
2717 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002718 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002719 if (rip->sock < 0)
2720 return rip->sock;
2721
2722 /* Create read and timer thread. */
2723 rip_event (RIP_READ, rip->sock);
2724 rip_event (RIP_UPDATE_EVENT, 1);
2725
2726 return 0;
2727}
2728
2729/* Sned RIP request to the destination. */
2730int
2731rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002732 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002733{
2734 struct rte *rte;
2735 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002736 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002737
2738 memset (&rip_packet, 0, sizeof (rip_packet));
2739
2740 rip_packet.command = RIP_REQUEST;
2741 rip_packet.version = version;
2742 rte = rip_packet.rte;
2743 rte->metric = htonl (RIP_METRIC_INFINITY);
2744
paul931cd542004-01-23 15:31:42 +00002745 if (connected)
2746 {
2747 /*
2748 * connected is only sent for ripv1 case, or when
2749 * interface does not support multicast. Caller loops
2750 * over each connected address for this case.
2751 */
paul11dde9c2004-05-31 14:00:00 +00002752 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002753 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002754 return -1;
2755 else
2756 return sizeof (rip_packet);
2757 }
2758
paulcc1131a2003-10-15 23:20:17 +00002759 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002760 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002761 {
2762 struct prefix_ipv4 *p;
2763
2764 p = (struct prefix_ipv4 *) connected->address;
2765
2766 if (p->family != AF_INET)
2767 continue;
2768
paul11dde9c2004-05-31 14:00:00 +00002769 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002770 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002771 return -1;
2772 }
2773 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002774}
2775
pauldc63bfd2005-10-25 23:31:05 +00002776static int
paul718e3742002-12-13 20:15:29 +00002777rip_update_jitter (unsigned long time)
2778{
paul239389b2004-05-05 14:09:37 +00002779#define JITTER_BOUND 4
2780 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2781 Given that, we cannot let time be less than JITTER_BOUND seconds.
2782 The RIPv2 RFC says jitter should be small compared to
2783 update_time. We consider 1/JITTER_BOUND to be small.
2784 */
2785
2786 int jitter_input = time;
2787 int jitter;
2788
2789 if (jitter_input < JITTER_BOUND)
2790 jitter_input = JITTER_BOUND;
2791
2792 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2793
2794 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002795}
2796
2797void
2798rip_event (enum rip_event event, int sock)
2799{
2800 int jitter = 0;
2801
2802 switch (event)
2803 {
2804 case RIP_READ:
2805 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2806 break;
2807 case RIP_UPDATE_EVENT:
2808 if (rip->t_update)
2809 {
2810 thread_cancel (rip->t_update);
2811 rip->t_update = NULL;
2812 }
2813 jitter = rip_update_jitter (rip->update_time);
2814 rip->t_update =
2815 thread_add_timer (master, rip_update, NULL,
2816 sock ? 2 : rip->update_time + jitter);
2817 break;
2818 case RIP_TRIGGERED_UPDATE:
2819 if (rip->t_triggered_interval)
2820 rip->trigger = 1;
2821 else if (! rip->t_triggered_update)
2822 rip->t_triggered_update =
2823 thread_add_event (master, rip_triggered_update, NULL, 0);
2824 break;
2825 default:
2826 break;
2827 }
2828}
2829
2830DEFUN (router_rip,
2831 router_rip_cmd,
2832 "router rip",
2833 "Enable a routing process\n"
2834 "Routing Information Protocol (RIP)\n")
2835{
2836 int ret;
2837
2838 /* If rip is not enabled before. */
2839 if (! rip)
2840 {
2841 ret = rip_create ();
2842 if (ret < 0)
2843 {
2844 zlog_info ("Can't create RIP");
2845 return CMD_WARNING;
2846 }
2847 }
2848 vty->node = RIP_NODE;
2849 vty->index = rip;
2850
2851 return CMD_SUCCESS;
2852}
2853
2854DEFUN (no_router_rip,
2855 no_router_rip_cmd,
2856 "no router rip",
2857 NO_STR
2858 "Enable a routing process\n"
2859 "Routing Information Protocol (RIP)\n")
2860{
2861 if (rip)
2862 rip_clean ();
2863 return CMD_SUCCESS;
2864}
2865
2866DEFUN (rip_version,
2867 rip_version_cmd,
2868 "version <1-2>",
2869 "Set routing protocol version\n"
2870 "version\n")
2871{
2872 int version;
2873
2874 version = atoi (argv[0]);
2875 if (version != RIPv1 && version != RIPv2)
2876 {
2877 vty_out (vty, "invalid rip version %d%s", version,
2878 VTY_NEWLINE);
2879 return CMD_WARNING;
2880 }
paulf38a4712003-06-07 01:10:00 +00002881 rip->version_send = version;
2882 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002883
2884 return CMD_SUCCESS;
2885}
2886
2887DEFUN (no_rip_version,
2888 no_rip_version_cmd,
2889 "no version",
2890 NO_STR
2891 "Set routing protocol version\n")
2892{
2893 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002894 rip->version_send = RI_RIP_VERSION_2;
2895 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002896
2897 return CMD_SUCCESS;
2898}
2899
2900ALIAS (no_rip_version,
2901 no_rip_version_val_cmd,
2902 "no version <1-2>",
2903 NO_STR
2904 "Set routing protocol version\n"
2905 "version\n")
2906
2907DEFUN (rip_route,
2908 rip_route_cmd,
2909 "route A.B.C.D/M",
2910 "RIP static route configuration\n"
2911 "IP prefix <network>/<length>\n")
2912{
2913 int ret;
2914 struct prefix_ipv4 p;
2915 struct route_node *node;
2916
2917 ret = str2prefix_ipv4 (argv[0], &p);
2918 if (ret < 0)
2919 {
2920 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2921 return CMD_WARNING;
2922 }
2923 apply_mask_ipv4 (&p);
2924
2925 /* For router rip configuration. */
2926 node = route_node_get (rip->route, (struct prefix *) &p);
2927
2928 if (node->info)
2929 {
2930 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2931 route_unlock_node (node);
2932 return CMD_WARNING;
2933 }
2934
hasso8a676be2004-10-08 06:36:38 +00002935 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002936
vincentfbf5d032005-09-29 11:25:50 +00002937 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002938
2939 return CMD_SUCCESS;
2940}
2941
2942DEFUN (no_rip_route,
2943 no_rip_route_cmd,
2944 "no route A.B.C.D/M",
2945 NO_STR
2946 "RIP static route configuration\n"
2947 "IP prefix <network>/<length>\n")
2948{
2949 int ret;
2950 struct prefix_ipv4 p;
2951 struct route_node *node;
2952
2953 ret = str2prefix_ipv4 (argv[0], &p);
2954 if (ret < 0)
2955 {
2956 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2957 return CMD_WARNING;
2958 }
2959 apply_mask_ipv4 (&p);
2960
2961 /* For router rip configuration. */
2962 node = route_node_lookup (rip->route, (struct prefix *) &p);
2963 if (! node)
2964 {
2965 vty_out (vty, "Can't find route %s.%s", argv[0],
2966 VTY_NEWLINE);
2967 return CMD_WARNING;
2968 }
2969
2970 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2971 route_unlock_node (node);
2972
2973 node->info = NULL;
2974 route_unlock_node (node);
2975
2976 return CMD_SUCCESS;
2977}
2978
Stephen Hemminger2c239702009-12-10 19:16:05 +03002979#if 0
pauldc63bfd2005-10-25 23:31:05 +00002980static void
paul216565a2005-10-25 23:35:28 +00002981rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002982{
2983 struct route_node *np;
2984 struct rip_info *rinfo;
2985
2986 for (np = route_top (rip->table); np; np = route_next (np))
2987 if ((rinfo = np->info) != NULL)
2988 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2989 rinfo->metric = rip->default_metric;
2990}
Stephen Hemminger2c239702009-12-10 19:16:05 +03002991#endif
paul718e3742002-12-13 20:15:29 +00002992
2993DEFUN (rip_default_metric,
2994 rip_default_metric_cmd,
2995 "default-metric <1-16>",
2996 "Set a metric of redistribute routes\n"
2997 "Default metric\n")
2998{
2999 if (rip)
3000 {
3001 rip->default_metric = atoi (argv[0]);
3002 /* rip_update_default_metric (); */
3003 }
3004 return CMD_SUCCESS;
3005}
3006
3007DEFUN (no_rip_default_metric,
3008 no_rip_default_metric_cmd,
3009 "no default-metric",
3010 NO_STR
3011 "Set a metric of redistribute routes\n"
3012 "Default metric\n")
3013{
3014 if (rip)
3015 {
3016 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3017 /* rip_update_default_metric (); */
3018 }
3019 return CMD_SUCCESS;
3020}
3021
3022ALIAS (no_rip_default_metric,
3023 no_rip_default_metric_val_cmd,
3024 "no default-metric <1-16>",
3025 NO_STR
3026 "Set a metric of redistribute routes\n"
3027 "Default metric\n")
3028
3029DEFUN (rip_timers,
3030 rip_timers_cmd,
3031 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3032 "Adjust routing timers\n"
3033 "Basic routing protocol update timers\n"
3034 "Routing table update timer value in second. Default is 30.\n"
3035 "Routing information timeout timer. Default is 180.\n"
3036 "Garbage collection timer. Default is 120.\n")
3037{
3038 unsigned long update;
3039 unsigned long timeout;
3040 unsigned long garbage;
3041 char *endptr = NULL;
3042 unsigned long RIP_TIMER_MAX = 2147483647;
3043 unsigned long RIP_TIMER_MIN = 5;
3044
3045 update = strtoul (argv[0], &endptr, 10);
3046 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3047 {
3048 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3049 return CMD_WARNING;
3050 }
3051
3052 timeout = strtoul (argv[1], &endptr, 10);
3053 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3054 {
3055 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3056 return CMD_WARNING;
3057 }
3058
3059 garbage = strtoul (argv[2], &endptr, 10);
3060 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3061 {
3062 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3063 return CMD_WARNING;
3064 }
3065
3066 /* Set each timer value. */
3067 rip->update_time = update;
3068 rip->timeout_time = timeout;
3069 rip->garbage_time = garbage;
3070
3071 /* Reset update timer thread. */
3072 rip_event (RIP_UPDATE_EVENT, 0);
3073
3074 return CMD_SUCCESS;
3075}
3076
3077DEFUN (no_rip_timers,
3078 no_rip_timers_cmd,
3079 "no timers basic",
3080 NO_STR
3081 "Adjust routing timers\n"
3082 "Basic routing protocol update timers\n")
3083{
3084 /* Set each timer value to the default. */
3085 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3086 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3087 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3088
3089 /* Reset update timer thread. */
3090 rip_event (RIP_UPDATE_EVENT, 0);
3091
3092 return CMD_SUCCESS;
3093}
hasso16705132003-05-25 14:49:19 +00003094
3095ALIAS (no_rip_timers,
3096 no_rip_timers_val_cmd,
3097 "no timers basic <0-65535> <0-65535> <0-65535>",
3098 NO_STR
3099 "Adjust routing timers\n"
3100 "Basic routing protocol update timers\n"
3101 "Routing table update timer value in second. Default is 30.\n"
3102 "Routing information timeout timer. Default is 180.\n"
3103 "Garbage collection timer. Default is 120.\n")
3104
paul718e3742002-12-13 20:15:29 +00003105
3106struct route_table *rip_distance_table;
3107
3108struct rip_distance
3109{
3110 /* Distance value for the IP source prefix. */
3111 u_char distance;
3112
3113 /* Name of the access-list to be matched. */
3114 char *access_list;
3115};
3116
pauldc63bfd2005-10-25 23:31:05 +00003117static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003118rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003119{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003120 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003121}
3122
pauldc63bfd2005-10-25 23:31:05 +00003123static void
paul718e3742002-12-13 20:15:29 +00003124rip_distance_free (struct rip_distance *rdistance)
3125{
3126 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3127}
3128
pauldc63bfd2005-10-25 23:31:05 +00003129static int
hasso98b718a2004-10-11 12:57:57 +00003130rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3131 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003132{
3133 int ret;
3134 struct prefix_ipv4 p;
3135 u_char distance;
3136 struct route_node *rn;
3137 struct rip_distance *rdistance;
3138
3139 ret = str2prefix_ipv4 (ip_str, &p);
3140 if (ret == 0)
3141 {
3142 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3143 return CMD_WARNING;
3144 }
3145
3146 distance = atoi (distance_str);
3147
3148 /* Get RIP distance node. */
3149 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3150 if (rn->info)
3151 {
3152 rdistance = rn->info;
3153 route_unlock_node (rn);
3154 }
3155 else
3156 {
3157 rdistance = rip_distance_new ();
3158 rn->info = rdistance;
3159 }
3160
3161 /* Set distance value. */
3162 rdistance->distance = distance;
3163
3164 /* Reset access-list configuration. */
3165 if (rdistance->access_list)
3166 {
3167 free (rdistance->access_list);
3168 rdistance->access_list = NULL;
3169 }
3170 if (access_list_str)
3171 rdistance->access_list = strdup (access_list_str);
3172
3173 return CMD_SUCCESS;
3174}
3175
pauldc63bfd2005-10-25 23:31:05 +00003176static int
hasso98b718a2004-10-11 12:57:57 +00003177rip_distance_unset (struct vty *vty, const char *distance_str,
3178 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003179{
3180 int ret;
3181 struct prefix_ipv4 p;
3182 u_char distance;
3183 struct route_node *rn;
3184 struct rip_distance *rdistance;
3185
3186 ret = str2prefix_ipv4 (ip_str, &p);
3187 if (ret == 0)
3188 {
3189 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3190 return CMD_WARNING;
3191 }
3192
3193 distance = atoi (distance_str);
3194
3195 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3196 if (! rn)
3197 {
3198 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3199 return CMD_WARNING;
3200 }
3201
3202 rdistance = rn->info;
3203
3204 if (rdistance->access_list)
3205 free (rdistance->access_list);
3206 rip_distance_free (rdistance);
3207
3208 rn->info = NULL;
3209 route_unlock_node (rn);
3210 route_unlock_node (rn);
3211
3212 return CMD_SUCCESS;
3213}
3214
pauldc63bfd2005-10-25 23:31:05 +00003215static void
paul216565a2005-10-25 23:35:28 +00003216rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003217{
3218 struct route_node *rn;
3219 struct rip_distance *rdistance;
3220
3221 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3222 if ((rdistance = rn->info) != NULL)
3223 {
3224 if (rdistance->access_list)
3225 free (rdistance->access_list);
3226 rip_distance_free (rdistance);
3227 rn->info = NULL;
3228 route_unlock_node (rn);
3229 }
3230}
3231
3232/* Apply RIP information to distance method. */
3233u_char
3234rip_distance_apply (struct rip_info *rinfo)
3235{
3236 struct route_node *rn;
3237 struct prefix_ipv4 p;
3238 struct rip_distance *rdistance;
3239 struct access_list *alist;
3240
3241 if (! rip)
3242 return 0;
3243
3244 memset (&p, 0, sizeof (struct prefix_ipv4));
3245 p.family = AF_INET;
3246 p.prefix = rinfo->from;
3247 p.prefixlen = IPV4_MAX_BITLEN;
3248
3249 /* Check source address. */
3250 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3251 if (rn)
3252 {
3253 rdistance = rn->info;
3254 route_unlock_node (rn);
3255
3256 if (rdistance->access_list)
3257 {
3258 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3259 if (alist == NULL)
3260 return 0;
3261 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3262 return 0;
3263
3264 return rdistance->distance;
3265 }
3266 else
3267 return rdistance->distance;
3268 }
3269
3270 if (rip->distance)
3271 return rip->distance;
3272
3273 return 0;
3274}
3275
pauldc63bfd2005-10-25 23:31:05 +00003276static void
paul718e3742002-12-13 20:15:29 +00003277rip_distance_show (struct vty *vty)
3278{
3279 struct route_node *rn;
3280 struct rip_distance *rdistance;
3281 int header = 1;
3282 char buf[BUFSIZ];
3283
3284 vty_out (vty, " Distance: (default is %d)%s",
3285 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3286 VTY_NEWLINE);
3287
3288 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3289 if ((rdistance = rn->info) != NULL)
3290 {
3291 if (header)
3292 {
3293 vty_out (vty, " Address Distance List%s",
3294 VTY_NEWLINE);
3295 header = 0;
3296 }
3297 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3298 vty_out (vty, " %-20s %4d %s%s",
3299 buf, rdistance->distance,
3300 rdistance->access_list ? rdistance->access_list : "",
3301 VTY_NEWLINE);
3302 }
3303}
3304
3305DEFUN (rip_distance,
3306 rip_distance_cmd,
3307 "distance <1-255>",
3308 "Administrative distance\n"
3309 "Distance value\n")
3310{
3311 rip->distance = atoi (argv[0]);
3312 return CMD_SUCCESS;
3313}
3314
3315DEFUN (no_rip_distance,
3316 no_rip_distance_cmd,
3317 "no distance <1-255>",
3318 NO_STR
3319 "Administrative distance\n"
3320 "Distance value\n")
3321{
3322 rip->distance = 0;
3323 return CMD_SUCCESS;
3324}
3325
3326DEFUN (rip_distance_source,
3327 rip_distance_source_cmd,
3328 "distance <1-255> A.B.C.D/M",
3329 "Administrative distance\n"
3330 "Distance value\n"
3331 "IP source prefix\n")
3332{
3333 rip_distance_set (vty, argv[0], argv[1], NULL);
3334 return CMD_SUCCESS;
3335}
3336
3337DEFUN (no_rip_distance_source,
3338 no_rip_distance_source_cmd,
3339 "no distance <1-255> A.B.C.D/M",
3340 NO_STR
3341 "Administrative distance\n"
3342 "Distance value\n"
3343 "IP source prefix\n")
3344{
3345 rip_distance_unset (vty, argv[0], argv[1], NULL);
3346 return CMD_SUCCESS;
3347}
3348
3349DEFUN (rip_distance_source_access_list,
3350 rip_distance_source_access_list_cmd,
3351 "distance <1-255> A.B.C.D/M WORD",
3352 "Administrative distance\n"
3353 "Distance value\n"
3354 "IP source prefix\n"
3355 "Access list name\n")
3356{
3357 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3358 return CMD_SUCCESS;
3359}
3360
3361DEFUN (no_rip_distance_source_access_list,
3362 no_rip_distance_source_access_list_cmd,
3363 "no distance <1-255> A.B.C.D/M WORD",
3364 NO_STR
3365 "Administrative distance\n"
3366 "Distance value\n"
3367 "IP source prefix\n"
3368 "Access list name\n")
3369{
3370 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3371 return CMD_SUCCESS;
3372}
3373
3374/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003375static void
paul718e3742002-12-13 20:15:29 +00003376rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3377{
paul718e3742002-12-13 20:15:29 +00003378 time_t clock;
3379 struct tm *tm;
3380#define TIME_BUF 25
3381 char timebuf [TIME_BUF];
3382 struct thread *thread;
3383
paul718e3742002-12-13 20:15:29 +00003384 if ((thread = rinfo->t_timeout) != NULL)
3385 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003386 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003387 tm = gmtime (&clock);
3388 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3389 vty_out (vty, "%5s", timebuf);
3390 }
3391 else if ((thread = rinfo->t_garbage_collect) != NULL)
3392 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003393 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003394 tm = gmtime (&clock);
3395 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3396 vty_out (vty, "%5s", timebuf);
3397 }
3398}
3399
pauldc63bfd2005-10-25 23:31:05 +00003400static const char *
paul718e3742002-12-13 20:15:29 +00003401rip_route_type_print (int sub_type)
3402{
3403 switch (sub_type)
3404 {
3405 case RIP_ROUTE_RTE:
3406 return "n";
3407 case RIP_ROUTE_STATIC:
3408 return "s";
3409 case RIP_ROUTE_DEFAULT:
3410 return "d";
3411 case RIP_ROUTE_REDISTRIBUTE:
3412 return "r";
3413 case RIP_ROUTE_INTERFACE:
3414 return "i";
3415 default:
3416 return "?";
3417 }
3418}
3419
3420DEFUN (show_ip_rip,
3421 show_ip_rip_cmd,
3422 "show ip rip",
3423 SHOW_STR
3424 IP_STR
3425 "Show RIP routes\n")
3426{
3427 struct route_node *np;
3428 struct rip_info *rinfo;
3429
3430 if (! rip)
3431 return CMD_SUCCESS;
3432
hasso16705132003-05-25 14:49:19 +00003433 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3434 "Sub-codes:%s"
3435 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003436 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003437 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003438 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003439
3440 for (np = route_top (rip->table); np; np = route_next (np))
3441 if ((rinfo = np->info) != NULL)
3442 {
3443 int len;
3444
ajsf52d13c2005-10-01 17:38:06 +00003445 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003446 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003447 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003448 rip_route_type_print (rinfo->sub_type),
3449 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3450
hassoa1455d82004-03-03 19:36:24 +00003451 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003452
3453 if (len > 0)
3454 vty_out (vty, "%*s", len, " ");
3455
3456 if (rinfo->nexthop.s_addr)
3457 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3458 rinfo->metric);
3459 else
3460 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3461
3462 /* Route which exist in kernel routing table. */
3463 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3464 (rinfo->sub_type == RIP_ROUTE_RTE))
3465 {
3466 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003467 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003468 rip_vty_out_uptime (vty, rinfo);
3469 }
3470 else if (rinfo->metric == RIP_METRIC_INFINITY)
3471 {
3472 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003473 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003474 rip_vty_out_uptime (vty, rinfo);
3475 }
3476 else
hasso16705132003-05-25 14:49:19 +00003477 {
vincentfbf5d032005-09-29 11:25:50 +00003478 if (rinfo->external_metric)
3479 {
3480 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003481 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003482 rinfo->external_metric);
3483 len = 16 - len;
3484 if (len > 0)
3485 vty_out (vty, "%*s", len, " ");
3486 }
3487 else
3488 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003489 vty_out (vty, "%3d", rinfo->tag);
3490 }
paul718e3742002-12-13 20:15:29 +00003491
3492 vty_out (vty, "%s", VTY_NEWLINE);
3493 }
3494 return CMD_SUCCESS;
3495}
3496
hasso16705132003-05-25 14:49:19 +00003497/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3498DEFUN (show_ip_rip_status,
3499 show_ip_rip_status_cmd,
3500 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003501 SHOW_STR
3502 IP_STR
hasso16705132003-05-25 14:49:19 +00003503 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003504 "IP routing protocol process parameters and statistics\n")
3505{
hasso52dc7ee2004-09-23 19:18:23 +00003506 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003507 struct interface *ifp;
3508 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003509 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003510 const char *send_version;
3511 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003512
3513 if (! rip)
3514 return CMD_SUCCESS;
3515
3516 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3517 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3518 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003519 vty_out (vty, " next due in %lu seconds%s",
3520 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003521 VTY_NEWLINE);
3522 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3523 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3524 VTY_NEWLINE);
3525
3526 /* Filtering status show. */
3527 config_show_distribute (vty);
3528
3529 /* Default metric information. */
3530 vty_out (vty, " Default redistribution metric is %d%s",
3531 rip->default_metric, VTY_NEWLINE);
3532
3533 /* Redistribute information. */
3534 vty_out (vty, " Redistributing:");
3535 config_write_rip_redistribute (vty, 0);
3536 vty_out (vty, "%s", VTY_NEWLINE);
3537
paulf38a4712003-06-07 01:10:00 +00003538 vty_out (vty, " Default version control: send version %s,",
3539 lookup(ri_version_msg,rip->version_send));
3540 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3541 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3542 else
3543 vty_out (vty, " receive version %s %s",
3544 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003545
3546 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3547
paul1eb8ef22005-04-07 07:30:20 +00003548 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003549 {
paul718e3742002-12-13 20:15:29 +00003550 ri = ifp->info;
3551
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003552 if (!ri->running)
3553 continue;
3554
paul718e3742002-12-13 20:15:29 +00003555 if (ri->enable_network || ri->enable_interface)
3556 {
3557 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003558 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003559 else
3560 send_version = lookup (ri_version_msg, ri->ri_send);
3561
3562 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003563 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003564 else
3565 receive_version = lookup (ri_version_msg, ri->ri_receive);
3566
3567 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3568 send_version,
3569 receive_version,
3570 ri->key_chain ? ri->key_chain : "",
3571 VTY_NEWLINE);
3572 }
3573 }
3574
3575 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3576 config_write_rip_network (vty, 0);
3577
paul4aaff3f2003-06-07 01:04:45 +00003578 {
3579 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003580 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003581 {
paul4aaff3f2003-06-07 01:04:45 +00003582 ri = ifp->info;
3583
3584 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3585 {
3586 if (!found_passive)
3587 {
3588 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3589 found_passive = 1;
3590 }
3591 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3592 }
3593 }
3594 }
3595
paul718e3742002-12-13 20:15:29 +00003596 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3597 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3598 rip_peer_display (vty);
3599
3600 rip_distance_show (vty);
3601
3602 return CMD_SUCCESS;
3603}
3604
3605/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003606static int
paul718e3742002-12-13 20:15:29 +00003607config_write_rip (struct vty *vty)
3608{
3609 int write = 0;
3610 struct route_node *rn;
3611 struct rip_distance *rdistance;
3612
3613 if (rip)
3614 {
3615 /* Router RIP statement. */
3616 vty_out (vty, "router rip%s", VTY_NEWLINE);
3617 write++;
3618
3619 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003620 if (rip->version_send != RI_RIP_VERSION_2
3621 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3622 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003623 VTY_NEWLINE);
3624
3625 /* RIP timer configuration. */
3626 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3627 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3628 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3629 vty_out (vty, " timers basic %lu %lu %lu%s",
3630 rip->update_time,
3631 rip->timeout_time,
3632 rip->garbage_time,
3633 VTY_NEWLINE);
3634
3635 /* Default information configuration. */
3636 if (rip->default_information)
3637 {
3638 if (rip->default_information_route_map)
3639 vty_out (vty, " default-information originate route-map %s%s",
3640 rip->default_information_route_map, VTY_NEWLINE);
3641 else
3642 vty_out (vty, " default-information originate%s",
3643 VTY_NEWLINE);
3644 }
3645
3646 /* Redistribute configuration. */
3647 config_write_rip_redistribute (vty, 1);
3648
3649 /* RIP offset-list configuration. */
3650 config_write_rip_offset_list (vty);
3651
3652 /* RIP enabled network and interface configuration. */
3653 config_write_rip_network (vty, 1);
3654
3655 /* RIP default metric configuration */
3656 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3657 vty_out (vty, " default-metric %d%s",
3658 rip->default_metric, VTY_NEWLINE);
3659
3660 /* Distribute configuration. */
3661 write += config_write_distribute (vty);
3662
hasso16705132003-05-25 14:49:19 +00003663 /* Interface routemap configuration */
3664 write += config_write_if_rmap (vty);
3665
paul718e3742002-12-13 20:15:29 +00003666 /* Distance configuration. */
3667 if (rip->distance)
3668 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3669
3670 /* RIP source IP prefix distance configuration. */
3671 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3672 if ((rdistance = rn->info) != NULL)
3673 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3674 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3675 rdistance->access_list ? rdistance->access_list : "",
3676 VTY_NEWLINE);
3677
3678 /* RIP static route configuration. */
3679 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3680 if (rn->info)
3681 vty_out (vty, " route %s/%d%s",
3682 inet_ntoa (rn->p.u.prefix4),
3683 rn->p.prefixlen,
3684 VTY_NEWLINE);
3685
3686 }
3687 return write;
3688}
3689
3690/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003691static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003692{
3693 RIP_NODE,
3694 "%s(config-router)# ",
3695 1
3696};
3697
3698/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003699static void
paul718e3742002-12-13 20:15:29 +00003700rip_distribute_update (struct distribute *dist)
3701{
3702 struct interface *ifp;
3703 struct rip_interface *ri;
3704 struct access_list *alist;
3705 struct prefix_list *plist;
3706
3707 if (! dist->ifname)
3708 return;
3709
3710 ifp = if_lookup_by_name (dist->ifname);
3711 if (ifp == NULL)
3712 return;
3713
3714 ri = ifp->info;
3715
3716 if (dist->list[DISTRIBUTE_IN])
3717 {
3718 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3719 if (alist)
3720 ri->list[RIP_FILTER_IN] = alist;
3721 else
3722 ri->list[RIP_FILTER_IN] = NULL;
3723 }
3724 else
3725 ri->list[RIP_FILTER_IN] = NULL;
3726
3727 if (dist->list[DISTRIBUTE_OUT])
3728 {
3729 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3730 if (alist)
3731 ri->list[RIP_FILTER_OUT] = alist;
3732 else
3733 ri->list[RIP_FILTER_OUT] = NULL;
3734 }
3735 else
3736 ri->list[RIP_FILTER_OUT] = NULL;
3737
3738 if (dist->prefix[DISTRIBUTE_IN])
3739 {
3740 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3741 if (plist)
3742 ri->prefix[RIP_FILTER_IN] = plist;
3743 else
3744 ri->prefix[RIP_FILTER_IN] = NULL;
3745 }
3746 else
3747 ri->prefix[RIP_FILTER_IN] = NULL;
3748
3749 if (dist->prefix[DISTRIBUTE_OUT])
3750 {
3751 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3752 if (plist)
3753 ri->prefix[RIP_FILTER_OUT] = plist;
3754 else
3755 ri->prefix[RIP_FILTER_OUT] = NULL;
3756 }
3757 else
3758 ri->prefix[RIP_FILTER_OUT] = NULL;
3759}
3760
3761void
3762rip_distribute_update_interface (struct interface *ifp)
3763{
3764 struct distribute *dist;
3765
3766 dist = distribute_lookup (ifp->name);
3767 if (dist)
3768 rip_distribute_update (dist);
3769}
3770
3771/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003772/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003773static void
paul02ff83c2004-06-11 11:27:03 +00003774rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003775{
3776 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003777 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003778
paul1eb8ef22005-04-07 07:30:20 +00003779 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3780 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003781}
paul11dde9c2004-05-31 14:00:00 +00003782/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003783static void
paul11dde9c2004-05-31 14:00:00 +00003784rip_distribute_update_all_wrapper(struct access_list *notused)
3785{
paul02ff83c2004-06-11 11:27:03 +00003786 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003787}
paul718e3742002-12-13 20:15:29 +00003788
3789/* Delete all added rip route. */
3790void
paul216565a2005-10-25 23:35:28 +00003791rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003792{
3793 int i;
3794 struct route_node *rp;
3795 struct rip_info *rinfo;
3796
3797 if (rip)
3798 {
3799 /* Clear RIP routes */
3800 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3801 if ((rinfo = rp->info) != NULL)
3802 {
3803 if (rinfo->type == ZEBRA_ROUTE_RIP &&
3804 rinfo->sub_type == RIP_ROUTE_RTE)
3805 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
3806 &rinfo->nexthop, rinfo->metric);
3807
3808 RIP_TIMER_OFF (rinfo->t_timeout);
3809 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3810
3811 rp->info = NULL;
3812 route_unlock_node (rp);
3813
3814 rip_info_free (rinfo);
3815 }
3816
3817 /* Cancel RIP related timers. */
3818 RIP_TIMER_OFF (rip->t_update);
3819 RIP_TIMER_OFF (rip->t_triggered_update);
3820 RIP_TIMER_OFF (rip->t_triggered_interval);
3821
3822 /* Cancel read thread. */
3823 if (rip->t_read)
3824 {
3825 thread_cancel (rip->t_read);
3826 rip->t_read = NULL;
3827 }
3828
3829 /* Close RIP socket. */
3830 if (rip->sock >= 0)
3831 {
3832 close (rip->sock);
3833 rip->sock = -1;
3834 }
3835
3836 /* Static RIP route configuration. */
3837 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3838 if (rp->info)
3839 {
3840 rp->info = NULL;
3841 route_unlock_node (rp);
3842 }
3843
3844 /* RIP neighbor configuration. */
3845 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3846 if (rp->info)
3847 {
3848 rp->info = NULL;
3849 route_unlock_node (rp);
3850 }
3851
3852 /* Redistribute related clear. */
3853 if (rip->default_information_route_map)
3854 free (rip->default_information_route_map);
3855
3856 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3857 if (rip->route_map[i].name)
3858 free (rip->route_map[i].name);
3859
3860 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3861 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3862 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3863
3864 XFREE (MTYPE_RIP, rip);
3865 rip = NULL;
3866 }
3867
3868 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003869 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003870 rip_offset_clean ();
3871 rip_interface_clean ();
3872 rip_distance_reset ();
3873 rip_redistribute_clean ();
3874}
3875
3876/* Reset all values to the default settings. */
3877void
paul216565a2005-10-25 23:35:28 +00003878rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003879{
3880 /* Reset global counters. */
3881 rip_global_route_changes = 0;
3882 rip_global_queries = 0;
3883
3884 /* Call ripd related reset functions. */
3885 rip_debug_reset ();
3886 rip_route_map_reset ();
3887
3888 /* Call library reset functions. */
3889 vty_reset ();
3890 access_list_reset ();
3891 prefix_list_reset ();
3892
3893 distribute_list_reset ();
3894
3895 rip_interface_reset ();
3896 rip_distance_reset ();
3897
3898 rip_zclient_reset ();
3899}
3900
pauldc63bfd2005-10-25 23:31:05 +00003901static void
hasso16705132003-05-25 14:49:19 +00003902rip_if_rmap_update (struct if_rmap *if_rmap)
3903{
3904 struct interface *ifp;
3905 struct rip_interface *ri;
3906 struct route_map *rmap;
3907
3908 ifp = if_lookup_by_name (if_rmap->ifname);
3909 if (ifp == NULL)
3910 return;
3911
3912 ri = ifp->info;
3913
3914 if (if_rmap->routemap[IF_RMAP_IN])
3915 {
3916 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3917 if (rmap)
3918 ri->routemap[IF_RMAP_IN] = rmap;
3919 else
3920 ri->routemap[IF_RMAP_IN] = NULL;
3921 }
3922 else
3923 ri->routemap[RIP_FILTER_IN] = NULL;
3924
3925 if (if_rmap->routemap[IF_RMAP_OUT])
3926 {
3927 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3928 if (rmap)
3929 ri->routemap[IF_RMAP_OUT] = rmap;
3930 else
3931 ri->routemap[IF_RMAP_OUT] = NULL;
3932 }
3933 else
3934 ri->routemap[RIP_FILTER_OUT] = NULL;
3935}
3936
3937void
3938rip_if_rmap_update_interface (struct interface *ifp)
3939{
3940 struct if_rmap *if_rmap;
3941
3942 if_rmap = if_rmap_lookup (ifp->name);
3943 if (if_rmap)
3944 rip_if_rmap_update (if_rmap);
3945}
3946
pauldc63bfd2005-10-25 23:31:05 +00003947static void
hasso16705132003-05-25 14:49:19 +00003948rip_routemap_update_redistribute (void)
3949{
3950 int i;
3951
3952 if (rip)
3953 {
3954 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3955 {
3956 if (rip->route_map[i].name)
3957 rip->route_map[i].map =
3958 route_map_lookup_by_name (rip->route_map[i].name);
3959 }
3960 }
3961}
3962
paul11dde9c2004-05-31 14:00:00 +00003963/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003964static void
hasso98b718a2004-10-11 12:57:57 +00003965rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00003966{
3967 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003968 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00003969
paul1eb8ef22005-04-07 07:30:20 +00003970 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3971 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00003972
3973 rip_routemap_update_redistribute ();
3974}
3975
paul718e3742002-12-13 20:15:29 +00003976/* Allocate new rip structure and set default value. */
3977void
pauldc63bfd2005-10-25 23:31:05 +00003978rip_init (void)
paul718e3742002-12-13 20:15:29 +00003979{
3980 /* Randomize for triggered update random(). */
3981 srand (time (NULL));
3982
3983 /* Install top nodes. */
3984 install_node (&rip_node, config_write_rip);
3985
3986 /* Install rip commands. */
3987 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003988 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003989 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003990 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003991 install_element (CONFIG_NODE, &router_rip_cmd);
3992 install_element (CONFIG_NODE, &no_router_rip_cmd);
3993
3994 install_default (RIP_NODE);
3995 install_element (RIP_NODE, &rip_version_cmd);
3996 install_element (RIP_NODE, &no_rip_version_cmd);
3997 install_element (RIP_NODE, &no_rip_version_val_cmd);
3998 install_element (RIP_NODE, &rip_default_metric_cmd);
3999 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4000 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4001 install_element (RIP_NODE, &rip_timers_cmd);
4002 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004003 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004004 install_element (RIP_NODE, &rip_route_cmd);
4005 install_element (RIP_NODE, &no_rip_route_cmd);
4006 install_element (RIP_NODE, &rip_distance_cmd);
4007 install_element (RIP_NODE, &no_rip_distance_cmd);
4008 install_element (RIP_NODE, &rip_distance_source_cmd);
4009 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4010 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4011 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
4012
4013 /* Debug related init. */
4014 rip_debug_init ();
4015
paul718e3742002-12-13 20:15:29 +00004016 /* SNMP init. */
4017#ifdef HAVE_SNMP
4018 rip_snmp_init ();
4019#endif /* HAVE_SNMP */
4020
4021 /* Access list install. */
4022 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004023 access_list_add_hook (rip_distribute_update_all_wrapper);
4024 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004025
4026 /* Prefix list initialize.*/
4027 prefix_list_init ();
4028 prefix_list_add_hook (rip_distribute_update_all);
4029 prefix_list_delete_hook (rip_distribute_update_all);
4030
4031 /* Distribute list install. */
4032 distribute_list_init (RIP_NODE);
4033 distribute_list_add_hook (rip_distribute_update);
4034 distribute_list_delete_hook (rip_distribute_update);
4035
hasso16705132003-05-25 14:49:19 +00004036 /* Route-map */
4037 rip_route_map_init ();
4038 rip_offset_init ();
4039
4040 route_map_add_hook (rip_routemap_update);
4041 route_map_delete_hook (rip_routemap_update);
4042
4043 if_rmap_init (RIP_NODE);
4044 if_rmap_hook_add (rip_if_rmap_update);
4045 if_rmap_hook_delete (rip_if_rmap_update);
4046
paul718e3742002-12-13 20:15:29 +00004047 /* Distance control. */
4048 rip_distance_table = route_table_init ();
4049}