blob: db29d54a2dd21f56e078db625641dfc5c54f24f3 [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 */
Nick Hilliardbb2315f2012-08-18 15:10:57 +00001478 memset (&from, 0, sizeof (from));
paul2c61ae32005-08-16 15:22:14 +00001479 from.sin_family = AF_INET;
1480 from.sin_port = htons (RIP_PORT_DEFAULT);
1481 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001482#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001483 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001484#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001485
paul931cd542004-01-23 15:31:42 +00001486 /*
1487 * we have to open a new socket for each packet because this
1488 * is the most portable way to bind to a different source
1489 * ipv4 address for each packet.
1490 */
paul2c61ae32005-08-16 15:22:14 +00001491 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001492 {
paulf69bd9d2005-06-03 18:01:50 +00001493 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001494 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001495 }
paulc49ad8f2004-10-22 10:27:28 +00001496 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001497 }
1498
paul931cd542004-01-23 15:31:42 +00001499 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001500 sizeof (struct sockaddr_in));
1501
1502 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001503 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001504 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001505
1506 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001507 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001508
paul931cd542004-01-23 15:31:42 +00001509 if (!to)
1510 close(send_sock);
1511
paul718e3742002-12-13 20:15:29 +00001512 return ret;
1513}
1514
1515/* Add redistributed route to RIP table. */
1516void
1517rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001518 unsigned int ifindex, struct in_addr *nexthop,
1519 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001520{
1521 int ret;
1522 struct route_node *rp;
1523 struct rip_info *rinfo;
1524
1525 /* Redistribute route */
1526 ret = rip_destination_check (p->prefix);
1527 if (! ret)
1528 return;
1529
1530 rp = route_node_get (rip->table, (struct prefix *) p);
1531
1532 rinfo = rp->info;
1533
1534 if (rinfo)
1535 {
1536 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1537 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1538 && rinfo->metric != RIP_METRIC_INFINITY)
1539 {
1540 route_unlock_node (rp);
1541 return;
1542 }
1543
1544 /* Manually configured RIP route check. */
1545 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001546 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1547 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001548 {
hasso16705132003-05-25 14:49:19 +00001549 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1550 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001551 {
1552 route_unlock_node (rp);
1553 return;
1554 }
1555 }
1556
1557 RIP_TIMER_OFF (rinfo->t_timeout);
1558 RIP_TIMER_OFF (rinfo->t_garbage_collect);
1559
1560 if (rip_route_rte (rinfo))
1561 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
1562 rinfo->metric);
1563 rp->info = NULL;
1564 rip_info_free (rinfo);
1565
1566 route_unlock_node (rp);
1567 }
1568
1569 rinfo = rip_info_new ();
1570
1571 rinfo->type = type;
1572 rinfo->sub_type = sub_type;
1573 rinfo->ifindex = ifindex;
1574 rinfo->metric = 1;
vincentfbf5d032005-09-29 11:25:50 +00001575 rinfo->external_metric = metric;
1576 rinfo->distance = distance;
paul718e3742002-12-13 20:15:29 +00001577 rinfo->rp = rp;
1578
1579 if (nexthop)
1580 rinfo->nexthop = *nexthop;
1581
1582 rinfo->flags |= RIP_RTF_FIB;
1583 rp->info = rinfo;
1584
1585 rinfo->flags |= RIP_RTF_CHANGED;
1586
hasso16705132003-05-25 14:49:19 +00001587 if (IS_RIP_DEBUG_EVENT) {
1588 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001589 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001590 inet_ntoa(p->prefix), p->prefixlen,
1591 ifindex2ifname(ifindex));
1592 else
ajs5d6c3772004-12-08 19:24:06 +00001593 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001594 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1595 ifindex2ifname(ifindex));
1596 }
1597
1598
paul718e3742002-12-13 20:15:29 +00001599 rip_event (RIP_TRIGGERED_UPDATE, 0);
1600}
1601
1602/* Delete redistributed route from RIP table. */
1603void
1604rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1605 unsigned int ifindex)
1606{
1607 int ret;
1608 struct route_node *rp;
1609 struct rip_info *rinfo;
1610
1611 ret = rip_destination_check (p->prefix);
1612 if (! ret)
1613 return;
1614
1615 rp = route_node_lookup (rip->table, (struct prefix *) p);
1616 if (rp)
1617 {
1618 rinfo = rp->info;
1619
1620 if (rinfo != NULL
1621 && rinfo->type == type
1622 && rinfo->sub_type == sub_type
1623 && rinfo->ifindex == ifindex)
1624 {
1625 /* Perform poisoned reverse. */
1626 rinfo->metric = RIP_METRIC_INFINITY;
1627 RIP_TIMER_ON (rinfo->t_garbage_collect,
1628 rip_garbage_collect, rip->garbage_time);
1629 RIP_TIMER_OFF (rinfo->t_timeout);
1630 rinfo->flags |= RIP_RTF_CHANGED;
1631
hasso16705132003-05-25 14:49:19 +00001632 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001633 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso16705132003-05-25 14:49:19 +00001634 inet_ntoa(p->prefix), p->prefixlen,
1635 ifindex2ifname(ifindex));
1636
paul718e3742002-12-13 20:15:29 +00001637 rip_event (RIP_TRIGGERED_UPDATE, 0);
1638 }
1639 }
1640}
1641
1642/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001643static void
paul718e3742002-12-13 20:15:29 +00001644rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001645 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001646{
1647 caddr_t lim;
1648 struct rte *rte;
1649 struct prefix_ipv4 p;
1650 struct route_node *rp;
1651 struct rip_info *rinfo;
1652 struct rip_interface *ri;
1653
hasso16705132003-05-25 14:49:19 +00001654 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001655 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001656 return;
1657
hasso429a0f82004-02-22 23:42:22 +00001658 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001659 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001660 if (! ri->running)
1661 return;
paul718e3742002-12-13 20:15:29 +00001662
1663 /* When passive interface is specified, suppress responses */
1664 if (ri->passive)
1665 return;
paulc49ad8f2004-10-22 10:27:28 +00001666
paul718e3742002-12-13 20:15:29 +00001667 /* RIP peer update. */
1668 rip_peer_update (from, packet->version);
1669
1670 lim = ((caddr_t) packet) + size;
1671 rte = packet->rte;
1672
1673 /* The Request is processed entry by entry. If there are no
1674 entries, no response is given. */
1675 if (lim == (caddr_t) rte)
1676 return;
1677
1678 /* There is one special case. If there is exactly one entry in the
1679 request, and it has an address family identifier of zero and a
1680 metric of infinity (i.e., 16), then this is a request to send the
1681 entire routing table. */
1682 if (lim == ((caddr_t) (rte + 1)) &&
1683 ntohs (rte->family) == 0 &&
1684 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1685 {
paulcc1131a2003-10-15 23:20:17 +00001686 struct prefix_ipv4 saddr;
1687
1688 /* saddr will be used for determining which routes to split-horizon.
1689 Since the source address we'll pick will be on the same subnet as the
1690 destination, for the purpose of split-horizoning, we'll
1691 pretend that "from" is our source address. */
1692 saddr.family = AF_INET;
1693 saddr.prefixlen = IPV4_MAX_BITLEN;
1694 saddr.prefix = from->sin_addr;
1695
paul718e3742002-12-13 20:15:29 +00001696 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001697 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001698 }
1699 else
1700 {
1701 /* Examine the list of RTEs in the Request one by one. For each
1702 entry, look up the destination in the router's routing
1703 database and, if there is a route, put that route's metric in
1704 the metric field of the RTE. If there is no explicit route
1705 to the specified destination, put infinity in the metric
1706 field. Once all the entries have been filled in, change the
1707 command from Request to Response and send the datagram back
1708 to the requestor. */
1709 p.family = AF_INET;
1710
1711 for (; ((caddr_t) rte) < lim; rte++)
1712 {
1713 p.prefix = rte->prefix;
1714 p.prefixlen = ip_masklen (rte->mask);
1715 apply_mask_ipv4 (&p);
1716
1717 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1718 if (rp)
1719 {
1720 rinfo = rp->info;
1721 rte->metric = htonl (rinfo->metric);
1722 route_unlock_node (rp);
1723 }
1724 else
1725 rte->metric = htonl (RIP_METRIC_INFINITY);
1726 }
1727 packet->command = RIP_RESPONSE;
1728
paulc49ad8f2004-10-22 10:27:28 +00001729 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001730 }
1731 rip_global_queries++;
1732}
1733
1734#if RIP_RECVMSG
1735/* Set IPv6 packet info to the socket. */
1736static int
1737setsockopt_pktinfo (int sock)
1738{
1739 int ret;
1740 int val = 1;
1741
1742 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1743 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001744 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001745 return ret;
1746}
1747
1748/* Read RIP packet by recvmsg function. */
1749int
1750rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1751 int *ifindex)
1752{
1753 int ret;
1754 struct msghdr msg;
1755 struct iovec iov;
1756 struct cmsghdr *ptr;
1757 char adata[1024];
1758
1759 msg.msg_name = (void *) from;
1760 msg.msg_namelen = sizeof (struct sockaddr_in);
1761 msg.msg_iov = &iov;
1762 msg.msg_iovlen = 1;
1763 msg.msg_control = (void *) adata;
1764 msg.msg_controllen = sizeof adata;
1765 iov.iov_base = buf;
1766 iov.iov_len = size;
1767
1768 ret = recvmsg (sock, &msg, 0);
1769 if (ret < 0)
1770 return ret;
1771
ajsb99760a2005-01-04 16:24:43 +00001772 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001773 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1774 {
1775 struct in_pktinfo *pktinfo;
1776 int i;
1777
1778 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1779 i = pktinfo->ipi_ifindex;
1780 }
1781 return ret;
1782}
1783
1784/* RIP packet read function. */
1785int
1786rip_read_new (struct thread *t)
1787{
1788 int ret;
1789 int sock;
1790 char buf[RIP_PACKET_MAXSIZ];
1791 struct sockaddr_in from;
1792 unsigned int ifindex;
1793
1794 /* Fetch socket then register myself. */
1795 sock = THREAD_FD (t);
1796 rip_event (RIP_READ, sock);
1797
1798 /* Read RIP packet. */
1799 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1800 if (ret < 0)
1801 {
ajs6099b3b2004-11-20 02:06:59 +00001802 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001803 return ret;
1804 }
1805
1806 return ret;
1807}
1808#endif /* RIP_RECVMSG */
1809
1810/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001811static int
paul718e3742002-12-13 20:15:29 +00001812rip_read (struct thread *t)
1813{
1814 int sock;
1815 int ret;
1816 int rtenum;
1817 union rip_buf rip_buf;
1818 struct rip_packet *packet;
1819 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001820 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001821 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001822 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001823 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001824 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001825 struct rip_interface *ri;
1826
1827 /* Fetch socket then register myself. */
1828 sock = THREAD_FD (t);
1829 rip->t_read = NULL;
1830
1831 /* Add myself to tne next event */
1832 rip_event (RIP_READ, sock);
1833
1834 /* RIPd manages only IPv4. */
1835 memset (&from, 0, sizeof (struct sockaddr_in));
1836 fromlen = sizeof (struct sockaddr_in);
1837
1838 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1839 (struct sockaddr *) &from, &fromlen);
1840 if (len < 0)
1841 {
ajs6099b3b2004-11-20 02:06:59 +00001842 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001843 return len;
1844 }
1845
1846 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001847 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001848 {
1849 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001850 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001851 return -1;
1852 }
1853
1854 /* Which interface is this packet comes from. */
1855 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001856
paul718e3742002-12-13 20:15:29 +00001857 /* RIP packet received */
1858 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001859 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001860 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1861 ifp ? ifp->name : "unknown");
1862
1863 /* If this packet come from unknown interface, ignore it. */
1864 if (ifp == NULL)
1865 {
ajs766a0ca2004-12-15 14:55:51 +00001866 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1867 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001868 return -1;
1869 }
1870
1871 ifc = connected_lookup_address (ifp, from.sin_addr);
1872
1873 if (ifc == NULL)
1874 {
ajs766a0ca2004-12-15 14:55:51 +00001875 zlog_info ("rip_read: cannot find connected address for packet from %s "
1876 "port %d on interface %s",
1877 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001878 return -1;
1879 }
1880
1881 /* Packet length check. */
1882 if (len < RIP_PACKET_MINSIZ)
1883 {
1884 zlog_warn ("packet size %d is smaller than minimum size %d",
1885 len, RIP_PACKET_MINSIZ);
1886 rip_peer_bad_packet (&from);
1887 return len;
1888 }
1889 if (len > RIP_PACKET_MAXSIZ)
1890 {
1891 zlog_warn ("packet size %d is larger than max size %d",
1892 len, RIP_PACKET_MAXSIZ);
1893 rip_peer_bad_packet (&from);
1894 return len;
1895 }
1896
1897 /* Packet alignment check. */
1898 if ((len - RIP_PACKET_MINSIZ) % 20)
1899 {
1900 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1901 rip_peer_bad_packet (&from);
1902 return len;
1903 }
1904
1905 /* Set RTE number. */
1906 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1907
1908 /* For easy to handle. */
1909 packet = &rip_buf.rip_packet;
1910
1911 /* RIP version check. */
1912 if (packet->version == 0)
1913 {
1914 zlog_info ("version 0 with command %d received.", packet->command);
1915 rip_peer_bad_packet (&from);
1916 return -1;
1917 }
1918
1919 /* Dump RIP packet. */
1920 if (IS_RIP_DEBUG_RECV)
1921 rip_packet_dump (packet, len, "RECV");
1922
1923 /* RIP version adjust. This code should rethink now. RFC1058 says
1924 that "Version 1 implementations are to ignore this extra data and
1925 process only the fields specified in this document.". So RIPv3
1926 packet should be treated as RIPv1 ignoring must be zero field. */
1927 if (packet->version > RIPv2)
1928 packet->version = RIPv2;
1929
1930 /* Is RIP running or is this RIP neighbor ?*/
1931 ri = ifp->info;
1932 if (! ri->running && ! rip_neighbor_lookup (&from))
1933 {
1934 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001935 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001936 rip_peer_bad_packet (&from);
1937 return -1;
1938 }
1939
Paul Jakma15a2b082006-05-04 07:36:34 +00001940 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001941 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1942 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001943 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001944 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001945 if (IS_RIP_DEBUG_PACKET)
1946 zlog_debug (" packet's v%d doesn't fit to if version spec",
1947 packet->version);
1948 rip_peer_bad_packet (&from);
1949 return -1;
paul718e3742002-12-13 20:15:29 +00001950 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001951 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1952 {
1953 if (IS_RIP_DEBUG_PACKET)
1954 zlog_debug (" packet's v%d doesn't fit to if version spec",
1955 packet->version);
1956 rip_peer_bad_packet (&from);
1957 return -1;
1958 }
1959
paul718e3742002-12-13 20:15:29 +00001960 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1961 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1962 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001963 if ((ri->auth_type == RIP_NO_AUTH)
1964 && rtenum
paulca5e5162004-06-06 22:06:33 +00001965 && (packet->version == RIPv2)
1966 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001967 {
1968 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001969 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001970 packet->version);
1971 rip_peer_bad_packet (&from);
1972 return -1;
1973 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001974
1975 /* RFC:
1976 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001977 RIP-1 messages and RIP-2 messages which pass authentication
1978 testing shall be accepted; unauthenticated and failed
1979 authentication RIP-2 messages shall be discarded. For maximum
1980 security, RIP-1 messages should be ignored when authentication is
1981 in use (see section 4.1); otherwise, the routing information from
1982 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001983 unauthenticated manner.
1984 */
1985 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1986 * always reply regardless of authentication settings, because:
1987 *
1988 * - if there other authorised routers on-link, the REQUESTor can
1989 * passively obtain the routing updates anyway
1990 * - if there are no other authorised routers on-link, RIP can
1991 * easily be disabled for the link to prevent giving out information
1992 * on state of this routers RIP routing table..
1993 *
1994 * I.e. if RIPv1 has any place anymore these days, it's as a very
1995 * simple way to distribute routing information (e.g. to embedded
1996 * hosts / appliances) and the ability to give out RIPv1
1997 * routing-information freely, while still requiring RIPv2
1998 * authentication for any RESPONSEs might be vaguely useful.
1999 */
2000 if (ri->auth_type != RIP_NO_AUTH
2001 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002002 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002003 /* Discard RIPv1 messages other than REQUESTs */
2004 if (packet->command != RIP_REQUEST)
2005 {
2006 if (IS_RIP_DEBUG_PACKET)
2007 zlog_debug ("RIPv1" " dropped because authentication enabled");
2008 rip_peer_bad_packet (&from);
2009 return -1;
2010 }
2011 }
2012 else if (ri->auth_type != RIP_NO_AUTH)
2013 {
2014 const char *auth_desc;
2015
2016 if (rtenum == 0)
2017 {
2018 /* There definitely is no authentication in the packet. */
2019 if (IS_RIP_DEBUG_PACKET)
2020 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2021 rip_peer_bad_packet (&from);
2022 return -1;
2023 }
2024
2025 /* First RTE must be an Authentication Family RTE */
2026 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2027 {
2028 if (IS_RIP_DEBUG_PACKET)
2029 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002030 rip_peer_bad_packet (&from);
2031 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002032 }
2033
paul718e3742002-12-13 20:15:29 +00002034 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002035 switch (ntohs(packet->rte->tag))
2036 {
2037 case RIP_AUTH_SIMPLE_PASSWORD:
2038 auth_desc = "simple";
2039 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2040 break;
2041
2042 case RIP_AUTH_MD5:
2043 auth_desc = "MD5";
2044 ret = rip_auth_md5 (packet, &from, len, ifp);
2045 /* Reset RIP packet length to trim MD5 data. */
2046 len = ret;
2047 break;
2048
2049 default:
2050 ret = 0;
2051 auth_desc = "unknown type";
2052 if (IS_RIP_DEBUG_PACKET)
2053 zlog_debug ("RIPv2 Unknown authentication type %d",
2054 ntohs (packet->rte->tag));
2055 }
2056
2057 if (ret)
2058 {
2059 if (IS_RIP_DEBUG_PACKET)
2060 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2061 }
2062 else
2063 {
2064 if (IS_RIP_DEBUG_PACKET)
2065 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2066 rip_peer_bad_packet (&from);
2067 return -1;
2068 }
paul718e3742002-12-13 20:15:29 +00002069 }
2070
2071 /* Process each command. */
2072 switch (packet->command)
2073 {
2074 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002075 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002076 break;
2077 case RIP_REQUEST:
2078 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002079 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002080 break;
2081 case RIP_TRACEON:
2082 case RIP_TRACEOFF:
2083 zlog_info ("Obsolete command %s received, please sent it to routed",
2084 lookup (rip_msg, packet->command));
2085 rip_peer_bad_packet (&from);
2086 break;
2087 case RIP_POLL_ENTRY:
2088 zlog_info ("Obsolete command %s received",
2089 lookup (rip_msg, packet->command));
2090 rip_peer_bad_packet (&from);
2091 break;
2092 default:
2093 zlog_info ("Unknown RIP command %d received", packet->command);
2094 rip_peer_bad_packet (&from);
2095 break;
2096 }
2097
2098 return len;
2099}
2100
paul718e3742002-12-13 20:15:29 +00002101/* Write routing table entry to the stream and return next index of
2102 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002103static int
paul718e3742002-12-13 20:15:29 +00002104rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002105 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002106{
2107 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002108
2109 /* Write routing table entry. */
2110 if (version == RIPv1)
2111 {
2112 stream_putw (s, AF_INET);
2113 stream_putw (s, 0);
2114 stream_put_ipv4 (s, p->prefix.s_addr);
2115 stream_put_ipv4 (s, 0);
2116 stream_put_ipv4 (s, 0);
2117 stream_putl (s, rinfo->metric_out);
2118 }
2119 else
2120 {
2121 masklen2ip (p->prefixlen, &mask);
2122
2123 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002124 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002125 stream_put_ipv4 (s, p->prefix.s_addr);
2126 stream_put_ipv4 (s, mask.s_addr);
2127 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2128 stream_putl (s, rinfo->metric_out);
2129 }
2130
2131 return ++num;
2132}
2133
2134/* Send update to the ifp or spcified neighbor. */
2135void
paulc49ad8f2004-10-22 10:27:28 +00002136rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2137 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002138{
2139 int ret;
2140 struct stream *s;
2141 struct route_node *rp;
2142 struct rip_info *rinfo;
2143 struct rip_interface *ri;
2144 struct prefix_ipv4 *p;
2145 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002146 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002147 struct key *key = NULL;
2148 /* this might need to made dynamic if RIP ever supported auth methods
2149 with larger key string sizes */
2150 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002151 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002152 int num = 0;
paul718e3742002-12-13 20:15:29 +00002153 int rtemax;
paul01d09082003-06-08 21:22:18 +00002154 int subnetted = 0;
paul718e3742002-12-13 20:15:29 +00002155
2156 /* Logging output event. */
2157 if (IS_RIP_DEBUG_EVENT)
2158 {
2159 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002160 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002161 else
ajs5d6c3772004-12-08 19:24:06 +00002162 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002163 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002164 }
2165
2166 /* Set output stream. */
2167 s = rip->obuf;
2168
2169 /* Reset stream and RTE counter. */
2170 stream_reset (s);
paul718e3742002-12-13 20:15:29 +00002171 rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
2172
2173 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002174 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002175
2176 /* If output interface is in simple password authentication mode, we
2177 need space for authentication data. */
2178 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2179 rtemax -= 1;
2180
2181 /* If output interface is in MD5 authentication mode, we need space
2182 for authentication header and data. */
2183 if (ri->auth_type == RIP_AUTH_MD5)
2184 rtemax -= 2;
2185
2186 /* If output interface is in simple password authentication mode
2187 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002188 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002189 {
2190 if (ri->key_chain)
2191 {
2192 struct keychain *keychain;
2193
2194 keychain = keychain_lookup (ri->key_chain);
2195 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002196 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002197 }
paulb14ee002005-02-04 23:42:41 +00002198 /* to be passed to auth functions later */
2199 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002200 }
2201
paul727d1042002-12-13 20:50:29 +00002202 if (version == RIPv1)
2203 {
paulc49ad8f2004-10-22 10:27:28 +00002204 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002205 apply_classful_mask_ipv4 (&ifaddrclass);
2206 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002207 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002208 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002209 }
2210
paul718e3742002-12-13 20:15:29 +00002211 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2212 if ((rinfo = rp->info) != NULL)
2213 {
paul727d1042002-12-13 20:50:29 +00002214 /* For RIPv1, if we are subnetted, output subnets in our network */
2215 /* that have the same mask as the output "interface". For other */
2216 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002217
2218 if (version == RIPv1)
2219 {
paul727d1042002-12-13 20:50:29 +00002220 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002221
2222 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002223 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002224 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002225
paul727d1042002-12-13 20:50:29 +00002226 if (subnetted &&
2227 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2228 {
paulc49ad8f2004-10-22 10:27:28 +00002229 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002230 (rp->p.prefixlen != 32))
2231 continue;
2232 }
2233 else
2234 {
2235 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2236 apply_classful_mask_ipv4(&classfull);
2237 if (rp->p.u.prefix4.s_addr != 0 &&
2238 classfull.prefixlen != rp->p.prefixlen)
2239 continue;
2240 }
paul718e3742002-12-13 20:15:29 +00002241 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002242 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002243 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002244 }
2245 else
2246 p = (struct prefix_ipv4 *) &rp->p;
2247
2248 /* Apply output filters. */
2249 ret = rip_outgoing_filter (p, ri);
2250 if (ret < 0)
2251 continue;
2252
2253 /* Changed route only output. */
2254 if (route_type == rip_changed_route &&
2255 (! (rinfo->flags & RIP_RTF_CHANGED)))
2256 continue;
2257
2258 /* Split horizon. */
2259 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002260 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002261 {
paul42d14d92003-11-17 09:15:18 +00002262 /*
2263 * We perform split horizon for RIP and connected route.
2264 * For rip routes, we want to suppress the route if we would
2265 * end up sending the route back on the interface that we
2266 * learned it from, with a higher metric. For connected routes,
2267 * we suppress the route if the prefix is a subset of the
2268 * source address that we are going to use for the packet
2269 * (in order to handle the case when multiple subnets are
2270 * configured on the same interface).
2271 */
2272 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002273 rinfo->ifindex == ifc->ifp->ifindex)
paul42d14d92003-11-17 09:15:18 +00002274 continue;
2275 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002276 prefix_match((struct prefix *)p, ifc->address))
paul718e3742002-12-13 20:15:29 +00002277 continue;
2278 }
2279
2280 /* Preparation for route-map. */
2281 rinfo->metric_set = 0;
2282 rinfo->nexthop_out.s_addr = 0;
2283 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002284 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002285 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002286
hasso16705132003-05-25 14:49:19 +00002287 /* In order to avoid some local loops,
2288 * if the RIP route has a nexthop via this interface, keep the nexthop,
2289 * otherwise set it to 0. The nexthop should not be propagated
2290 * beyond the local broadcast/multicast area in order
2291 * to avoid an IGP multi-level recursive look-up.
2292 * see (4.4)
2293 */
paulc49ad8f2004-10-22 10:27:28 +00002294 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002295 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002296
2297 /* Interface route-map */
2298 if (ri->routemap[RIP_FILTER_OUT])
2299 {
2300 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2301 (struct prefix *) p, RMAP_RIP,
2302 rinfo);
2303
2304 if (ret == RMAP_DENYMATCH)
2305 {
2306 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002307 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002308 inet_ntoa (p->prefix), p->prefixlen);
2309 continue;
2310 }
2311 }
paul718e3742002-12-13 20:15:29 +00002312
hasso16705132003-05-25 14:49:19 +00002313 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002314 if (rip->route_map[rinfo->type].name
2315 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2316 {
2317 ret = route_map_apply (rip->route_map[rinfo->type].map,
2318 (struct prefix *)p, RMAP_RIP, rinfo);
2319
2320 if (ret == RMAP_DENYMATCH)
2321 {
2322 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002323 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002324 inet_ntoa (p->prefix), p->prefixlen);
2325 continue;
2326 }
2327 }
2328
2329 /* When route-map does not set metric. */
2330 if (! rinfo->metric_set)
2331 {
2332 /* If redistribute metric is set. */
2333 if (rip->route_map[rinfo->type].metric_config
2334 && rinfo->metric != RIP_METRIC_INFINITY)
2335 {
2336 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2337 }
2338 else
2339 {
2340 /* If the route is not connected or localy generated
2341 one, use default-metric value*/
2342 if (rinfo->type != ZEBRA_ROUTE_RIP
2343 && rinfo->type != ZEBRA_ROUTE_CONNECT
2344 && rinfo->metric != RIP_METRIC_INFINITY)
2345 rinfo->metric_out = rip->default_metric;
2346 }
2347 }
2348
2349 /* Apply offset-list */
2350 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002351 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002352
2353 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2354 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002355
2356 /* Perform split-horizon with poisoned reverse
2357 * for RIP and connected routes.
2358 **/
2359 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002360 /*
2361 * We perform split horizon for RIP and connected route.
2362 * For rip routes, we want to suppress the route if we would
2363 * end up sending the route back on the interface that we
2364 * learned it from, with a higher metric. For connected routes,
2365 * we suppress the route if the prefix is a subset of the
2366 * source address that we are going to use for the packet
2367 * (in order to handle the case when multiple subnets are
2368 * configured on the same interface).
2369 */
2370 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002371 rinfo->ifindex == ifc->ifp->ifindex)
hasso16705132003-05-25 14:49:19 +00002372 rinfo->metric_out = RIP_METRIC_INFINITY;
paul42d14d92003-11-17 09:15:18 +00002373 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002374 prefix_match((struct prefix *)p, ifc->address))
paul42d14d92003-11-17 09:15:18 +00002375 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002376 }
paulb14ee002005-02-04 23:42:41 +00002377
2378 /* Prepare preamble, auth headers, if needs be */
2379 if (num == 0)
2380 {
2381 stream_putc (s, RIP_RESPONSE);
2382 stream_putc (s, version);
2383 stream_putw (s, 0);
2384
paul0cb8a012005-05-29 11:27:24 +00002385 /* auth header for !v1 && !no_auth */
2386 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002387 doff = rip_auth_header_write (s, ri, key, auth_str,
2388 RIP_AUTH_SIMPLE_SIZE);
2389 }
2390
paul718e3742002-12-13 20:15:29 +00002391 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002392 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002393 if (num == rtemax)
2394 {
2395 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002396 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002397
2398 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002399 to, ifc);
paul718e3742002-12-13 20:15:29 +00002400
2401 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2402 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2403 stream_get_endp(s), "SEND");
2404 num = 0;
2405 stream_reset (s);
2406 }
2407 }
2408
2409 /* Flush unwritten RTE. */
2410 if (num != 0)
2411 {
2412 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002413 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002414
paulc49ad8f2004-10-22 10:27:28 +00002415 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002416
2417 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2418 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2419 stream_get_endp (s), "SEND");
2420 num = 0;
2421 stream_reset (s);
2422 }
2423
2424 /* Statistics updates. */
2425 ri->sent_updates++;
2426}
2427
2428/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002429static void
paulc49ad8f2004-10-22 10:27:28 +00002430rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002431{
paul718e3742002-12-13 20:15:29 +00002432 struct sockaddr_in to;
2433
2434 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002435 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002436 {
2437 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002438 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002439
paulc49ad8f2004-10-22 10:27:28 +00002440 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002441 return;
2442 }
paulc49ad8f2004-10-22 10:27:28 +00002443
paul718e3742002-12-13 20:15:29 +00002444 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002445 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002446 {
paulc49ad8f2004-10-22 10:27:28 +00002447 if (ifc->address->family == AF_INET)
2448 {
2449 /* Destination address and port setting. */
2450 memset (&to, 0, sizeof (struct sockaddr_in));
2451 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002452 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002453 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002454 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002455 /* calculate the appropriate broadcast address */
2456 to.sin_addr.s_addr =
2457 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2458 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002459 else
2460 /* do not know where to send the packet */
2461 return;
paulc49ad8f2004-10-22 10:27:28 +00002462 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002463
paulc49ad8f2004-10-22 10:27:28 +00002464 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002465 zlog_debug("%s announce to %s on %s",
2466 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2467 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002468
paulc49ad8f2004-10-22 10:27:28 +00002469 rip_output_process (ifc, &to, route_type, version);
2470 }
paul718e3742002-12-13 20:15:29 +00002471 }
2472}
2473
2474/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002475static void
paul718e3742002-12-13 20:15:29 +00002476rip_update_process (int route_type)
2477{
paul1eb8ef22005-04-07 07:30:20 +00002478 struct listnode *node;
2479 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002480 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002481 struct interface *ifp;
2482 struct rip_interface *ri;
2483 struct route_node *rp;
2484 struct sockaddr_in to;
2485 struct prefix_ipv4 *p;
2486
2487 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002488 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002489 {
paul718e3742002-12-13 20:15:29 +00002490 if (if_is_loopback (ifp))
2491 continue;
2492
paul2e3b2e42002-12-13 21:03:13 +00002493 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002494 continue;
2495
2496 /* Fetch RIP interface information. */
2497 ri = ifp->info;
2498
2499 /* When passive interface is specified, suppress announce to the
2500 interface. */
2501 if (ri->passive)
2502 continue;
2503
2504 if (ri->running)
2505 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002506 /*
2507 * If there is no version configuration in the interface,
2508 * use rip's version setting.
2509 */
2510 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2511 rip->version_send : ri->ri_send);
2512
paul718e3742002-12-13 20:15:29 +00002513 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002514 zlog_debug("SEND UPDATE to %s ifindex %d",
2515 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002516
paulcc1131a2003-10-15 23:20:17 +00002517 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002518 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002519 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002520 if (connected->address->family == AF_INET)
2521 {
2522 if (vsend & RIPv1)
2523 rip_update_interface (connected, RIPv1, route_type);
2524 if ((vsend & RIPv2) && if_is_multicast(ifp))
2525 rip_update_interface (connected, RIPv2, route_type);
2526 }
2527 }
paul718e3742002-12-13 20:15:29 +00002528 }
2529 }
2530
2531 /* RIP send updates to each neighbor. */
2532 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2533 if (rp->info != NULL)
2534 {
2535 p = (struct prefix_ipv4 *) &rp->p;
2536
2537 ifp = if_lookup_address (p->prefix);
2538 if (! ifp)
2539 {
paulc49ad8f2004-10-22 10:27:28 +00002540 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002541 inet_ntoa (p->prefix));
2542 continue;
2543 }
paulc49ad8f2004-10-22 10:27:28 +00002544
2545 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2546 {
2547 zlog_warn ("Neighbor %s doesnt have connected network",
2548 inet_ntoa (p->prefix));
2549 continue;
2550 }
2551
paul718e3742002-12-13 20:15:29 +00002552 /* Set destination address and port */
2553 memset (&to, 0, sizeof (struct sockaddr_in));
2554 to.sin_addr = p->prefix;
2555 to.sin_port = htons (RIP_PORT_DEFAULT);
2556
2557 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002558 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002559 }
2560}
2561
2562/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002563static int
paul718e3742002-12-13 20:15:29 +00002564rip_update (struct thread *t)
2565{
2566 /* Clear timer pointer. */
2567 rip->t_update = NULL;
2568
2569 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002570 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002571
2572 /* Process update output. */
2573 rip_update_process (rip_all_route);
2574
2575 /* Triggered updates may be suppressed if a regular update is due by
2576 the time the triggered update would be sent. */
2577 if (rip->t_triggered_interval)
2578 {
2579 thread_cancel (rip->t_triggered_interval);
2580 rip->t_triggered_interval = NULL;
2581 }
2582 rip->trigger = 0;
2583
2584 /* Register myself. */
2585 rip_event (RIP_UPDATE_EVENT, 0);
2586
2587 return 0;
2588}
2589
2590/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002591static void
paul216565a2005-10-25 23:35:28 +00002592rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002593{
2594 struct route_node *rp;
2595 struct rip_info *rinfo;
2596
2597 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2598 if ((rinfo = rp->info) != NULL)
2599 if (rinfo->flags & RIP_RTF_CHANGED)
2600 rinfo->flags &= ~RIP_RTF_CHANGED;
2601}
2602
2603/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002604static int
paul718e3742002-12-13 20:15:29 +00002605rip_triggered_interval (struct thread *t)
2606{
2607 int rip_triggered_update (struct thread *);
2608
2609 rip->t_triggered_interval = NULL;
2610
2611 if (rip->trigger)
2612 {
2613 rip->trigger = 0;
2614 rip_triggered_update (t);
2615 }
2616 return 0;
2617}
2618
2619/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002620static int
paul718e3742002-12-13 20:15:29 +00002621rip_triggered_update (struct thread *t)
2622{
2623 int interval;
2624
2625 /* Clear thred pointer. */
2626 rip->t_triggered_update = NULL;
2627
2628 /* Cancel interval timer. */
2629 if (rip->t_triggered_interval)
2630 {
2631 thread_cancel (rip->t_triggered_interval);
2632 rip->t_triggered_interval = NULL;
2633 }
2634 rip->trigger = 0;
2635
2636 /* Logging triggered update. */
2637 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002638 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002639
2640 /* Split Horizon processing is done when generating triggered
2641 updates as well as normal updates (see section 2.6). */
2642 rip_update_process (rip_changed_route);
2643
2644 /* Once all of the triggered updates have been generated, the route
2645 change flags should be cleared. */
2646 rip_clear_changed_flag ();
2647
2648 /* After a triggered update is sent, a timer should be set for a
2649 random interval between 1 and 5 seconds. If other changes that
2650 would trigger updates occur before the timer expires, a single
2651 update is triggered when the timer expires. */
2652 interval = (random () % 5) + 1;
2653
2654 rip->t_triggered_interval =
2655 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2656
2657 return 0;
2658}
2659
2660/* Withdraw redistributed route. */
2661void
2662rip_redistribute_withdraw (int type)
2663{
2664 struct route_node *rp;
2665 struct rip_info *rinfo;
2666
2667 if (!rip)
2668 return;
2669
2670 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2671 if ((rinfo = rp->info) != NULL)
2672 {
2673 if (rinfo->type == type
2674 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2675 {
2676 /* Perform poisoned reverse. */
2677 rinfo->metric = RIP_METRIC_INFINITY;
2678 RIP_TIMER_ON (rinfo->t_garbage_collect,
2679 rip_garbage_collect, rip->garbage_time);
2680 RIP_TIMER_OFF (rinfo->t_timeout);
2681 rinfo->flags |= RIP_RTF_CHANGED;
2682
hasso16705132003-05-25 14:49:19 +00002683 if (IS_RIP_DEBUG_EVENT) {
2684 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2685
ajs5d6c3772004-12-08 19:24:06 +00002686 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002687 inet_ntoa(p->prefix), p->prefixlen,
2688 ifindex2ifname(rinfo->ifindex));
2689 }
2690
paul718e3742002-12-13 20:15:29 +00002691 rip_event (RIP_TRIGGERED_UPDATE, 0);
2692 }
2693 }
2694}
2695
2696/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002697static int
2698rip_create (void)
paul718e3742002-12-13 20:15:29 +00002699{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002700 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002701
2702 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002703 rip->version_send = RI_RIP_VERSION_2;
2704 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002705 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2706 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2707 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2708 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2709
2710 /* Initialize RIP routig table. */
2711 rip->table = route_table_init ();
2712 rip->route = route_table_init ();
2713 rip->neighbor = route_table_init ();
2714
2715 /* Make output stream. */
2716 rip->obuf = stream_new (1500);
2717
2718 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002719 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002720 if (rip->sock < 0)
2721 return rip->sock;
2722
2723 /* Create read and timer thread. */
2724 rip_event (RIP_READ, rip->sock);
2725 rip_event (RIP_UPDATE_EVENT, 1);
2726
2727 return 0;
2728}
2729
2730/* Sned RIP request to the destination. */
2731int
2732rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002733 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002734{
2735 struct rte *rte;
2736 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002737 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002738
2739 memset (&rip_packet, 0, sizeof (rip_packet));
2740
2741 rip_packet.command = RIP_REQUEST;
2742 rip_packet.version = version;
2743 rte = rip_packet.rte;
2744 rte->metric = htonl (RIP_METRIC_INFINITY);
2745
paul931cd542004-01-23 15:31:42 +00002746 if (connected)
2747 {
2748 /*
2749 * connected is only sent for ripv1 case, or when
2750 * interface does not support multicast. Caller loops
2751 * over each connected address for this case.
2752 */
paul11dde9c2004-05-31 14:00:00 +00002753 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002754 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002755 return -1;
2756 else
2757 return sizeof (rip_packet);
2758 }
2759
paulcc1131a2003-10-15 23:20:17 +00002760 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002761 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002762 {
2763 struct prefix_ipv4 *p;
2764
2765 p = (struct prefix_ipv4 *) connected->address;
2766
2767 if (p->family != AF_INET)
2768 continue;
2769
paul11dde9c2004-05-31 14:00:00 +00002770 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002771 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002772 return -1;
2773 }
2774 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002775}
2776
pauldc63bfd2005-10-25 23:31:05 +00002777static int
paul718e3742002-12-13 20:15:29 +00002778rip_update_jitter (unsigned long time)
2779{
paul239389b2004-05-05 14:09:37 +00002780#define JITTER_BOUND 4
2781 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2782 Given that, we cannot let time be less than JITTER_BOUND seconds.
2783 The RIPv2 RFC says jitter should be small compared to
2784 update_time. We consider 1/JITTER_BOUND to be small.
2785 */
2786
2787 int jitter_input = time;
2788 int jitter;
2789
2790 if (jitter_input < JITTER_BOUND)
2791 jitter_input = JITTER_BOUND;
2792
2793 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2794
2795 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002796}
2797
2798void
2799rip_event (enum rip_event event, int sock)
2800{
2801 int jitter = 0;
2802
2803 switch (event)
2804 {
2805 case RIP_READ:
2806 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2807 break;
2808 case RIP_UPDATE_EVENT:
2809 if (rip->t_update)
2810 {
2811 thread_cancel (rip->t_update);
2812 rip->t_update = NULL;
2813 }
2814 jitter = rip_update_jitter (rip->update_time);
2815 rip->t_update =
2816 thread_add_timer (master, rip_update, NULL,
2817 sock ? 2 : rip->update_time + jitter);
2818 break;
2819 case RIP_TRIGGERED_UPDATE:
2820 if (rip->t_triggered_interval)
2821 rip->trigger = 1;
2822 else if (! rip->t_triggered_update)
2823 rip->t_triggered_update =
2824 thread_add_event (master, rip_triggered_update, NULL, 0);
2825 break;
2826 default:
2827 break;
2828 }
2829}
2830
2831DEFUN (router_rip,
2832 router_rip_cmd,
2833 "router rip",
2834 "Enable a routing process\n"
2835 "Routing Information Protocol (RIP)\n")
2836{
2837 int ret;
2838
2839 /* If rip is not enabled before. */
2840 if (! rip)
2841 {
2842 ret = rip_create ();
2843 if (ret < 0)
2844 {
2845 zlog_info ("Can't create RIP");
2846 return CMD_WARNING;
2847 }
2848 }
2849 vty->node = RIP_NODE;
2850 vty->index = rip;
2851
2852 return CMD_SUCCESS;
2853}
2854
2855DEFUN (no_router_rip,
2856 no_router_rip_cmd,
2857 "no router rip",
2858 NO_STR
2859 "Enable a routing process\n"
2860 "Routing Information Protocol (RIP)\n")
2861{
2862 if (rip)
2863 rip_clean ();
2864 return CMD_SUCCESS;
2865}
2866
2867DEFUN (rip_version,
2868 rip_version_cmd,
2869 "version <1-2>",
2870 "Set routing protocol version\n"
2871 "version\n")
2872{
2873 int version;
2874
2875 version = atoi (argv[0]);
2876 if (version != RIPv1 && version != RIPv2)
2877 {
2878 vty_out (vty, "invalid rip version %d%s", version,
2879 VTY_NEWLINE);
2880 return CMD_WARNING;
2881 }
paulf38a4712003-06-07 01:10:00 +00002882 rip->version_send = version;
2883 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002884
2885 return CMD_SUCCESS;
2886}
2887
2888DEFUN (no_rip_version,
2889 no_rip_version_cmd,
2890 "no version",
2891 NO_STR
2892 "Set routing protocol version\n")
2893{
2894 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002895 rip->version_send = RI_RIP_VERSION_2;
2896 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002897
2898 return CMD_SUCCESS;
2899}
2900
2901ALIAS (no_rip_version,
2902 no_rip_version_val_cmd,
2903 "no version <1-2>",
2904 NO_STR
2905 "Set routing protocol version\n"
2906 "version\n")
2907
2908DEFUN (rip_route,
2909 rip_route_cmd,
2910 "route A.B.C.D/M",
2911 "RIP static route configuration\n"
2912 "IP prefix <network>/<length>\n")
2913{
2914 int ret;
2915 struct prefix_ipv4 p;
2916 struct route_node *node;
2917
2918 ret = str2prefix_ipv4 (argv[0], &p);
2919 if (ret < 0)
2920 {
2921 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2922 return CMD_WARNING;
2923 }
2924 apply_mask_ipv4 (&p);
2925
2926 /* For router rip configuration. */
2927 node = route_node_get (rip->route, (struct prefix *) &p);
2928
2929 if (node->info)
2930 {
2931 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2932 route_unlock_node (node);
2933 return CMD_WARNING;
2934 }
2935
hasso8a676be2004-10-08 06:36:38 +00002936 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002937
vincentfbf5d032005-09-29 11:25:50 +00002938 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002939
2940 return CMD_SUCCESS;
2941}
2942
2943DEFUN (no_rip_route,
2944 no_rip_route_cmd,
2945 "no route A.B.C.D/M",
2946 NO_STR
2947 "RIP static route configuration\n"
2948 "IP prefix <network>/<length>\n")
2949{
2950 int ret;
2951 struct prefix_ipv4 p;
2952 struct route_node *node;
2953
2954 ret = str2prefix_ipv4 (argv[0], &p);
2955 if (ret < 0)
2956 {
2957 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2958 return CMD_WARNING;
2959 }
2960 apply_mask_ipv4 (&p);
2961
2962 /* For router rip configuration. */
2963 node = route_node_lookup (rip->route, (struct prefix *) &p);
2964 if (! node)
2965 {
2966 vty_out (vty, "Can't find route %s.%s", argv[0],
2967 VTY_NEWLINE);
2968 return CMD_WARNING;
2969 }
2970
2971 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2972 route_unlock_node (node);
2973
2974 node->info = NULL;
2975 route_unlock_node (node);
2976
2977 return CMD_SUCCESS;
2978}
2979
Stephen Hemminger2c239702009-12-10 19:16:05 +03002980#if 0
pauldc63bfd2005-10-25 23:31:05 +00002981static void
paul216565a2005-10-25 23:35:28 +00002982rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002983{
2984 struct route_node *np;
2985 struct rip_info *rinfo;
2986
2987 for (np = route_top (rip->table); np; np = route_next (np))
2988 if ((rinfo = np->info) != NULL)
2989 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2990 rinfo->metric = rip->default_metric;
2991}
Stephen Hemminger2c239702009-12-10 19:16:05 +03002992#endif
paul718e3742002-12-13 20:15:29 +00002993
2994DEFUN (rip_default_metric,
2995 rip_default_metric_cmd,
2996 "default-metric <1-16>",
2997 "Set a metric of redistribute routes\n"
2998 "Default metric\n")
2999{
3000 if (rip)
3001 {
3002 rip->default_metric = atoi (argv[0]);
3003 /* rip_update_default_metric (); */
3004 }
3005 return CMD_SUCCESS;
3006}
3007
3008DEFUN (no_rip_default_metric,
3009 no_rip_default_metric_cmd,
3010 "no default-metric",
3011 NO_STR
3012 "Set a metric of redistribute routes\n"
3013 "Default metric\n")
3014{
3015 if (rip)
3016 {
3017 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3018 /* rip_update_default_metric (); */
3019 }
3020 return CMD_SUCCESS;
3021}
3022
3023ALIAS (no_rip_default_metric,
3024 no_rip_default_metric_val_cmd,
3025 "no default-metric <1-16>",
3026 NO_STR
3027 "Set a metric of redistribute routes\n"
3028 "Default metric\n")
3029
3030DEFUN (rip_timers,
3031 rip_timers_cmd,
3032 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3033 "Adjust routing timers\n"
3034 "Basic routing protocol update timers\n"
3035 "Routing table update timer value in second. Default is 30.\n"
3036 "Routing information timeout timer. Default is 180.\n"
3037 "Garbage collection timer. Default is 120.\n")
3038{
3039 unsigned long update;
3040 unsigned long timeout;
3041 unsigned long garbage;
3042 char *endptr = NULL;
3043 unsigned long RIP_TIMER_MAX = 2147483647;
3044 unsigned long RIP_TIMER_MIN = 5;
3045
3046 update = strtoul (argv[0], &endptr, 10);
3047 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3048 {
3049 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3050 return CMD_WARNING;
3051 }
3052
3053 timeout = strtoul (argv[1], &endptr, 10);
3054 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3055 {
3056 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3057 return CMD_WARNING;
3058 }
3059
3060 garbage = strtoul (argv[2], &endptr, 10);
3061 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3062 {
3063 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3064 return CMD_WARNING;
3065 }
3066
3067 /* Set each timer value. */
3068 rip->update_time = update;
3069 rip->timeout_time = timeout;
3070 rip->garbage_time = garbage;
3071
3072 /* Reset update timer thread. */
3073 rip_event (RIP_UPDATE_EVENT, 0);
3074
3075 return CMD_SUCCESS;
3076}
3077
3078DEFUN (no_rip_timers,
3079 no_rip_timers_cmd,
3080 "no timers basic",
3081 NO_STR
3082 "Adjust routing timers\n"
3083 "Basic routing protocol update timers\n")
3084{
3085 /* Set each timer value to the default. */
3086 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3087 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3088 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3089
3090 /* Reset update timer thread. */
3091 rip_event (RIP_UPDATE_EVENT, 0);
3092
3093 return CMD_SUCCESS;
3094}
hasso16705132003-05-25 14:49:19 +00003095
3096ALIAS (no_rip_timers,
3097 no_rip_timers_val_cmd,
3098 "no timers basic <0-65535> <0-65535> <0-65535>",
3099 NO_STR
3100 "Adjust routing timers\n"
3101 "Basic routing protocol update timers\n"
3102 "Routing table update timer value in second. Default is 30.\n"
3103 "Routing information timeout timer. Default is 180.\n"
3104 "Garbage collection timer. Default is 120.\n")
3105
paul718e3742002-12-13 20:15:29 +00003106
3107struct route_table *rip_distance_table;
3108
3109struct rip_distance
3110{
3111 /* Distance value for the IP source prefix. */
3112 u_char distance;
3113
3114 /* Name of the access-list to be matched. */
3115 char *access_list;
3116};
3117
pauldc63bfd2005-10-25 23:31:05 +00003118static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003119rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003120{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003121 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003122}
3123
pauldc63bfd2005-10-25 23:31:05 +00003124static void
paul718e3742002-12-13 20:15:29 +00003125rip_distance_free (struct rip_distance *rdistance)
3126{
3127 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3128}
3129
pauldc63bfd2005-10-25 23:31:05 +00003130static int
hasso98b718a2004-10-11 12:57:57 +00003131rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3132 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003133{
3134 int ret;
3135 struct prefix_ipv4 p;
3136 u_char distance;
3137 struct route_node *rn;
3138 struct rip_distance *rdistance;
3139
3140 ret = str2prefix_ipv4 (ip_str, &p);
3141 if (ret == 0)
3142 {
3143 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3144 return CMD_WARNING;
3145 }
3146
3147 distance = atoi (distance_str);
3148
3149 /* Get RIP distance node. */
3150 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3151 if (rn->info)
3152 {
3153 rdistance = rn->info;
3154 route_unlock_node (rn);
3155 }
3156 else
3157 {
3158 rdistance = rip_distance_new ();
3159 rn->info = rdistance;
3160 }
3161
3162 /* Set distance value. */
3163 rdistance->distance = distance;
3164
3165 /* Reset access-list configuration. */
3166 if (rdistance->access_list)
3167 {
3168 free (rdistance->access_list);
3169 rdistance->access_list = NULL;
3170 }
3171 if (access_list_str)
3172 rdistance->access_list = strdup (access_list_str);
3173
3174 return CMD_SUCCESS;
3175}
3176
pauldc63bfd2005-10-25 23:31:05 +00003177static int
hasso98b718a2004-10-11 12:57:57 +00003178rip_distance_unset (struct vty *vty, const char *distance_str,
3179 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003180{
3181 int ret;
3182 struct prefix_ipv4 p;
3183 u_char distance;
3184 struct route_node *rn;
3185 struct rip_distance *rdistance;
3186
3187 ret = str2prefix_ipv4 (ip_str, &p);
3188 if (ret == 0)
3189 {
3190 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3191 return CMD_WARNING;
3192 }
3193
3194 distance = atoi (distance_str);
3195
3196 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3197 if (! rn)
3198 {
3199 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3200 return CMD_WARNING;
3201 }
3202
3203 rdistance = rn->info;
3204
3205 if (rdistance->access_list)
3206 free (rdistance->access_list);
3207 rip_distance_free (rdistance);
3208
3209 rn->info = NULL;
3210 route_unlock_node (rn);
3211 route_unlock_node (rn);
3212
3213 return CMD_SUCCESS;
3214}
3215
pauldc63bfd2005-10-25 23:31:05 +00003216static void
paul216565a2005-10-25 23:35:28 +00003217rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003218{
3219 struct route_node *rn;
3220 struct rip_distance *rdistance;
3221
3222 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3223 if ((rdistance = rn->info) != NULL)
3224 {
3225 if (rdistance->access_list)
3226 free (rdistance->access_list);
3227 rip_distance_free (rdistance);
3228 rn->info = NULL;
3229 route_unlock_node (rn);
3230 }
3231}
3232
3233/* Apply RIP information to distance method. */
3234u_char
3235rip_distance_apply (struct rip_info *rinfo)
3236{
3237 struct route_node *rn;
3238 struct prefix_ipv4 p;
3239 struct rip_distance *rdistance;
3240 struct access_list *alist;
3241
3242 if (! rip)
3243 return 0;
3244
3245 memset (&p, 0, sizeof (struct prefix_ipv4));
3246 p.family = AF_INET;
3247 p.prefix = rinfo->from;
3248 p.prefixlen = IPV4_MAX_BITLEN;
3249
3250 /* Check source address. */
3251 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3252 if (rn)
3253 {
3254 rdistance = rn->info;
3255 route_unlock_node (rn);
3256
3257 if (rdistance->access_list)
3258 {
3259 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3260 if (alist == NULL)
3261 return 0;
3262 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3263 return 0;
3264
3265 return rdistance->distance;
3266 }
3267 else
3268 return rdistance->distance;
3269 }
3270
3271 if (rip->distance)
3272 return rip->distance;
3273
3274 return 0;
3275}
3276
pauldc63bfd2005-10-25 23:31:05 +00003277static void
paul718e3742002-12-13 20:15:29 +00003278rip_distance_show (struct vty *vty)
3279{
3280 struct route_node *rn;
3281 struct rip_distance *rdistance;
3282 int header = 1;
3283 char buf[BUFSIZ];
3284
3285 vty_out (vty, " Distance: (default is %d)%s",
3286 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3287 VTY_NEWLINE);
3288
3289 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3290 if ((rdistance = rn->info) != NULL)
3291 {
3292 if (header)
3293 {
3294 vty_out (vty, " Address Distance List%s",
3295 VTY_NEWLINE);
3296 header = 0;
3297 }
3298 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3299 vty_out (vty, " %-20s %4d %s%s",
3300 buf, rdistance->distance,
3301 rdistance->access_list ? rdistance->access_list : "",
3302 VTY_NEWLINE);
3303 }
3304}
3305
3306DEFUN (rip_distance,
3307 rip_distance_cmd,
3308 "distance <1-255>",
3309 "Administrative distance\n"
3310 "Distance value\n")
3311{
3312 rip->distance = atoi (argv[0]);
3313 return CMD_SUCCESS;
3314}
3315
3316DEFUN (no_rip_distance,
3317 no_rip_distance_cmd,
3318 "no distance <1-255>",
3319 NO_STR
3320 "Administrative distance\n"
3321 "Distance value\n")
3322{
3323 rip->distance = 0;
3324 return CMD_SUCCESS;
3325}
3326
3327DEFUN (rip_distance_source,
3328 rip_distance_source_cmd,
3329 "distance <1-255> A.B.C.D/M",
3330 "Administrative distance\n"
3331 "Distance value\n"
3332 "IP source prefix\n")
3333{
3334 rip_distance_set (vty, argv[0], argv[1], NULL);
3335 return CMD_SUCCESS;
3336}
3337
3338DEFUN (no_rip_distance_source,
3339 no_rip_distance_source_cmd,
3340 "no distance <1-255> A.B.C.D/M",
3341 NO_STR
3342 "Administrative distance\n"
3343 "Distance value\n"
3344 "IP source prefix\n")
3345{
3346 rip_distance_unset (vty, argv[0], argv[1], NULL);
3347 return CMD_SUCCESS;
3348}
3349
3350DEFUN (rip_distance_source_access_list,
3351 rip_distance_source_access_list_cmd,
3352 "distance <1-255> A.B.C.D/M WORD",
3353 "Administrative distance\n"
3354 "Distance value\n"
3355 "IP source prefix\n"
3356 "Access list name\n")
3357{
3358 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3359 return CMD_SUCCESS;
3360}
3361
3362DEFUN (no_rip_distance_source_access_list,
3363 no_rip_distance_source_access_list_cmd,
3364 "no distance <1-255> A.B.C.D/M WORD",
3365 NO_STR
3366 "Administrative distance\n"
3367 "Distance value\n"
3368 "IP source prefix\n"
3369 "Access list name\n")
3370{
3371 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3372 return CMD_SUCCESS;
3373}
3374
3375/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003376static void
paul718e3742002-12-13 20:15:29 +00003377rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3378{
paul718e3742002-12-13 20:15:29 +00003379 time_t clock;
3380 struct tm *tm;
3381#define TIME_BUF 25
3382 char timebuf [TIME_BUF];
3383 struct thread *thread;
3384
paul718e3742002-12-13 20:15:29 +00003385 if ((thread = rinfo->t_timeout) != NULL)
3386 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003387 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003388 tm = gmtime (&clock);
3389 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3390 vty_out (vty, "%5s", timebuf);
3391 }
3392 else if ((thread = rinfo->t_garbage_collect) != NULL)
3393 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003394 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003395 tm = gmtime (&clock);
3396 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3397 vty_out (vty, "%5s", timebuf);
3398 }
3399}
3400
pauldc63bfd2005-10-25 23:31:05 +00003401static const char *
paul718e3742002-12-13 20:15:29 +00003402rip_route_type_print (int sub_type)
3403{
3404 switch (sub_type)
3405 {
3406 case RIP_ROUTE_RTE:
3407 return "n";
3408 case RIP_ROUTE_STATIC:
3409 return "s";
3410 case RIP_ROUTE_DEFAULT:
3411 return "d";
3412 case RIP_ROUTE_REDISTRIBUTE:
3413 return "r";
3414 case RIP_ROUTE_INTERFACE:
3415 return "i";
3416 default:
3417 return "?";
3418 }
3419}
3420
3421DEFUN (show_ip_rip,
3422 show_ip_rip_cmd,
3423 "show ip rip",
3424 SHOW_STR
3425 IP_STR
3426 "Show RIP routes\n")
3427{
3428 struct route_node *np;
3429 struct rip_info *rinfo;
3430
3431 if (! rip)
3432 return CMD_SUCCESS;
3433
hasso16705132003-05-25 14:49:19 +00003434 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3435 "Sub-codes:%s"
3436 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003437 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003438 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003439 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003440
3441 for (np = route_top (rip->table); np; np = route_next (np))
3442 if ((rinfo = np->info) != NULL)
3443 {
3444 int len;
3445
ajsf52d13c2005-10-01 17:38:06 +00003446 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003447 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003448 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003449 rip_route_type_print (rinfo->sub_type),
3450 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3451
hassoa1455d82004-03-03 19:36:24 +00003452 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003453
3454 if (len > 0)
3455 vty_out (vty, "%*s", len, " ");
3456
3457 if (rinfo->nexthop.s_addr)
3458 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3459 rinfo->metric);
3460 else
3461 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3462
3463 /* Route which exist in kernel routing table. */
3464 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3465 (rinfo->sub_type == RIP_ROUTE_RTE))
3466 {
3467 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003468 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003469 rip_vty_out_uptime (vty, rinfo);
3470 }
3471 else if (rinfo->metric == RIP_METRIC_INFINITY)
3472 {
3473 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003474 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003475 rip_vty_out_uptime (vty, rinfo);
3476 }
3477 else
hasso16705132003-05-25 14:49:19 +00003478 {
vincentfbf5d032005-09-29 11:25:50 +00003479 if (rinfo->external_metric)
3480 {
3481 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003482 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003483 rinfo->external_metric);
3484 len = 16 - len;
3485 if (len > 0)
3486 vty_out (vty, "%*s", len, " ");
3487 }
3488 else
3489 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003490 vty_out (vty, "%3d", rinfo->tag);
3491 }
paul718e3742002-12-13 20:15:29 +00003492
3493 vty_out (vty, "%s", VTY_NEWLINE);
3494 }
3495 return CMD_SUCCESS;
3496}
3497
hasso16705132003-05-25 14:49:19 +00003498/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3499DEFUN (show_ip_rip_status,
3500 show_ip_rip_status_cmd,
3501 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003502 SHOW_STR
3503 IP_STR
hasso16705132003-05-25 14:49:19 +00003504 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003505 "IP routing protocol process parameters and statistics\n")
3506{
hasso52dc7ee2004-09-23 19:18:23 +00003507 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003508 struct interface *ifp;
3509 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003510 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003511 const char *send_version;
3512 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003513
3514 if (! rip)
3515 return CMD_SUCCESS;
3516
3517 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3518 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3519 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003520 vty_out (vty, " next due in %lu seconds%s",
3521 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003522 VTY_NEWLINE);
3523 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3524 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3525 VTY_NEWLINE);
3526
3527 /* Filtering status show. */
3528 config_show_distribute (vty);
3529
3530 /* Default metric information. */
3531 vty_out (vty, " Default redistribution metric is %d%s",
3532 rip->default_metric, VTY_NEWLINE);
3533
3534 /* Redistribute information. */
3535 vty_out (vty, " Redistributing:");
3536 config_write_rip_redistribute (vty, 0);
3537 vty_out (vty, "%s", VTY_NEWLINE);
3538
paulf38a4712003-06-07 01:10:00 +00003539 vty_out (vty, " Default version control: send version %s,",
3540 lookup(ri_version_msg,rip->version_send));
3541 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3542 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3543 else
3544 vty_out (vty, " receive version %s %s",
3545 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003546
3547 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3548
paul1eb8ef22005-04-07 07:30:20 +00003549 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003550 {
paul718e3742002-12-13 20:15:29 +00003551 ri = ifp->info;
3552
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003553 if (!ri->running)
3554 continue;
3555
paul718e3742002-12-13 20:15:29 +00003556 if (ri->enable_network || ri->enable_interface)
3557 {
3558 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003559 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003560 else
3561 send_version = lookup (ri_version_msg, ri->ri_send);
3562
3563 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003564 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003565 else
3566 receive_version = lookup (ri_version_msg, ri->ri_receive);
3567
3568 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3569 send_version,
3570 receive_version,
3571 ri->key_chain ? ri->key_chain : "",
3572 VTY_NEWLINE);
3573 }
3574 }
3575
3576 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3577 config_write_rip_network (vty, 0);
3578
paul4aaff3f2003-06-07 01:04:45 +00003579 {
3580 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003581 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003582 {
paul4aaff3f2003-06-07 01:04:45 +00003583 ri = ifp->info;
3584
3585 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3586 {
3587 if (!found_passive)
3588 {
3589 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3590 found_passive = 1;
3591 }
3592 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3593 }
3594 }
3595 }
3596
paul718e3742002-12-13 20:15:29 +00003597 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3598 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3599 rip_peer_display (vty);
3600
3601 rip_distance_show (vty);
3602
3603 return CMD_SUCCESS;
3604}
3605
3606/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003607static int
paul718e3742002-12-13 20:15:29 +00003608config_write_rip (struct vty *vty)
3609{
3610 int write = 0;
3611 struct route_node *rn;
3612 struct rip_distance *rdistance;
3613
3614 if (rip)
3615 {
3616 /* Router RIP statement. */
3617 vty_out (vty, "router rip%s", VTY_NEWLINE);
3618 write++;
3619
3620 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003621 if (rip->version_send != RI_RIP_VERSION_2
3622 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3623 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003624 VTY_NEWLINE);
3625
3626 /* RIP timer configuration. */
3627 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3628 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3629 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3630 vty_out (vty, " timers basic %lu %lu %lu%s",
3631 rip->update_time,
3632 rip->timeout_time,
3633 rip->garbage_time,
3634 VTY_NEWLINE);
3635
3636 /* Default information configuration. */
3637 if (rip->default_information)
3638 {
3639 if (rip->default_information_route_map)
3640 vty_out (vty, " default-information originate route-map %s%s",
3641 rip->default_information_route_map, VTY_NEWLINE);
3642 else
3643 vty_out (vty, " default-information originate%s",
3644 VTY_NEWLINE);
3645 }
3646
3647 /* Redistribute configuration. */
3648 config_write_rip_redistribute (vty, 1);
3649
3650 /* RIP offset-list configuration. */
3651 config_write_rip_offset_list (vty);
3652
3653 /* RIP enabled network and interface configuration. */
3654 config_write_rip_network (vty, 1);
3655
3656 /* RIP default metric configuration */
3657 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3658 vty_out (vty, " default-metric %d%s",
3659 rip->default_metric, VTY_NEWLINE);
3660
3661 /* Distribute configuration. */
3662 write += config_write_distribute (vty);
3663
hasso16705132003-05-25 14:49:19 +00003664 /* Interface routemap configuration */
3665 write += config_write_if_rmap (vty);
3666
paul718e3742002-12-13 20:15:29 +00003667 /* Distance configuration. */
3668 if (rip->distance)
3669 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3670
3671 /* RIP source IP prefix distance configuration. */
3672 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3673 if ((rdistance = rn->info) != NULL)
3674 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3675 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3676 rdistance->access_list ? rdistance->access_list : "",
3677 VTY_NEWLINE);
3678
3679 /* RIP static route configuration. */
3680 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3681 if (rn->info)
3682 vty_out (vty, " route %s/%d%s",
3683 inet_ntoa (rn->p.u.prefix4),
3684 rn->p.prefixlen,
3685 VTY_NEWLINE);
3686
3687 }
3688 return write;
3689}
3690
3691/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003692static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003693{
3694 RIP_NODE,
3695 "%s(config-router)# ",
3696 1
3697};
3698
3699/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003700static void
paul718e3742002-12-13 20:15:29 +00003701rip_distribute_update (struct distribute *dist)
3702{
3703 struct interface *ifp;
3704 struct rip_interface *ri;
3705 struct access_list *alist;
3706 struct prefix_list *plist;
3707
3708 if (! dist->ifname)
3709 return;
3710
3711 ifp = if_lookup_by_name (dist->ifname);
3712 if (ifp == NULL)
3713 return;
3714
3715 ri = ifp->info;
3716
3717 if (dist->list[DISTRIBUTE_IN])
3718 {
3719 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3720 if (alist)
3721 ri->list[RIP_FILTER_IN] = alist;
3722 else
3723 ri->list[RIP_FILTER_IN] = NULL;
3724 }
3725 else
3726 ri->list[RIP_FILTER_IN] = NULL;
3727
3728 if (dist->list[DISTRIBUTE_OUT])
3729 {
3730 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3731 if (alist)
3732 ri->list[RIP_FILTER_OUT] = alist;
3733 else
3734 ri->list[RIP_FILTER_OUT] = NULL;
3735 }
3736 else
3737 ri->list[RIP_FILTER_OUT] = NULL;
3738
3739 if (dist->prefix[DISTRIBUTE_IN])
3740 {
3741 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3742 if (plist)
3743 ri->prefix[RIP_FILTER_IN] = plist;
3744 else
3745 ri->prefix[RIP_FILTER_IN] = NULL;
3746 }
3747 else
3748 ri->prefix[RIP_FILTER_IN] = NULL;
3749
3750 if (dist->prefix[DISTRIBUTE_OUT])
3751 {
3752 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3753 if (plist)
3754 ri->prefix[RIP_FILTER_OUT] = plist;
3755 else
3756 ri->prefix[RIP_FILTER_OUT] = NULL;
3757 }
3758 else
3759 ri->prefix[RIP_FILTER_OUT] = NULL;
3760}
3761
3762void
3763rip_distribute_update_interface (struct interface *ifp)
3764{
3765 struct distribute *dist;
3766
3767 dist = distribute_lookup (ifp->name);
3768 if (dist)
3769 rip_distribute_update (dist);
3770}
3771
3772/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003773/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003774static void
paul02ff83c2004-06-11 11:27:03 +00003775rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003776{
3777 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003778 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003779
paul1eb8ef22005-04-07 07:30:20 +00003780 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3781 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003782}
paul11dde9c2004-05-31 14:00:00 +00003783/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003784static void
paul11dde9c2004-05-31 14:00:00 +00003785rip_distribute_update_all_wrapper(struct access_list *notused)
3786{
paul02ff83c2004-06-11 11:27:03 +00003787 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003788}
paul718e3742002-12-13 20:15:29 +00003789
3790/* Delete all added rip route. */
3791void
paul216565a2005-10-25 23:35:28 +00003792rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003793{
3794 int i;
3795 struct route_node *rp;
3796 struct rip_info *rinfo;
3797
3798 if (rip)
3799 {
3800 /* Clear RIP routes */
3801 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3802 if ((rinfo = rp->info) != NULL)
3803 {
3804 if (rinfo->type == ZEBRA_ROUTE_RIP &&
3805 rinfo->sub_type == RIP_ROUTE_RTE)
3806 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
3807 &rinfo->nexthop, rinfo->metric);
3808
3809 RIP_TIMER_OFF (rinfo->t_timeout);
3810 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3811
3812 rp->info = NULL;
3813 route_unlock_node (rp);
3814
3815 rip_info_free (rinfo);
3816 }
3817
3818 /* Cancel RIP related timers. */
3819 RIP_TIMER_OFF (rip->t_update);
3820 RIP_TIMER_OFF (rip->t_triggered_update);
3821 RIP_TIMER_OFF (rip->t_triggered_interval);
3822
3823 /* Cancel read thread. */
3824 if (rip->t_read)
3825 {
3826 thread_cancel (rip->t_read);
3827 rip->t_read = NULL;
3828 }
3829
3830 /* Close RIP socket. */
3831 if (rip->sock >= 0)
3832 {
3833 close (rip->sock);
3834 rip->sock = -1;
3835 }
3836
3837 /* Static RIP route configuration. */
3838 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3839 if (rp->info)
3840 {
3841 rp->info = NULL;
3842 route_unlock_node (rp);
3843 }
3844
3845 /* RIP neighbor configuration. */
3846 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3847 if (rp->info)
3848 {
3849 rp->info = NULL;
3850 route_unlock_node (rp);
3851 }
3852
3853 /* Redistribute related clear. */
3854 if (rip->default_information_route_map)
3855 free (rip->default_information_route_map);
3856
3857 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3858 if (rip->route_map[i].name)
3859 free (rip->route_map[i].name);
3860
3861 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3862 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3863 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3864
3865 XFREE (MTYPE_RIP, rip);
3866 rip = NULL;
3867 }
3868
3869 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003870 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003871 rip_offset_clean ();
3872 rip_interface_clean ();
3873 rip_distance_reset ();
3874 rip_redistribute_clean ();
3875}
3876
3877/* Reset all values to the default settings. */
3878void
paul216565a2005-10-25 23:35:28 +00003879rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003880{
3881 /* Reset global counters. */
3882 rip_global_route_changes = 0;
3883 rip_global_queries = 0;
3884
3885 /* Call ripd related reset functions. */
3886 rip_debug_reset ();
3887 rip_route_map_reset ();
3888
3889 /* Call library reset functions. */
3890 vty_reset ();
3891 access_list_reset ();
3892 prefix_list_reset ();
3893
3894 distribute_list_reset ();
3895
3896 rip_interface_reset ();
3897 rip_distance_reset ();
3898
3899 rip_zclient_reset ();
3900}
3901
pauldc63bfd2005-10-25 23:31:05 +00003902static void
hasso16705132003-05-25 14:49:19 +00003903rip_if_rmap_update (struct if_rmap *if_rmap)
3904{
3905 struct interface *ifp;
3906 struct rip_interface *ri;
3907 struct route_map *rmap;
3908
3909 ifp = if_lookup_by_name (if_rmap->ifname);
3910 if (ifp == NULL)
3911 return;
3912
3913 ri = ifp->info;
3914
3915 if (if_rmap->routemap[IF_RMAP_IN])
3916 {
3917 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3918 if (rmap)
3919 ri->routemap[IF_RMAP_IN] = rmap;
3920 else
3921 ri->routemap[IF_RMAP_IN] = NULL;
3922 }
3923 else
3924 ri->routemap[RIP_FILTER_IN] = NULL;
3925
3926 if (if_rmap->routemap[IF_RMAP_OUT])
3927 {
3928 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3929 if (rmap)
3930 ri->routemap[IF_RMAP_OUT] = rmap;
3931 else
3932 ri->routemap[IF_RMAP_OUT] = NULL;
3933 }
3934 else
3935 ri->routemap[RIP_FILTER_OUT] = NULL;
3936}
3937
3938void
3939rip_if_rmap_update_interface (struct interface *ifp)
3940{
3941 struct if_rmap *if_rmap;
3942
3943 if_rmap = if_rmap_lookup (ifp->name);
3944 if (if_rmap)
3945 rip_if_rmap_update (if_rmap);
3946}
3947
pauldc63bfd2005-10-25 23:31:05 +00003948static void
hasso16705132003-05-25 14:49:19 +00003949rip_routemap_update_redistribute (void)
3950{
3951 int i;
3952
3953 if (rip)
3954 {
3955 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3956 {
3957 if (rip->route_map[i].name)
3958 rip->route_map[i].map =
3959 route_map_lookup_by_name (rip->route_map[i].name);
3960 }
3961 }
3962}
3963
paul11dde9c2004-05-31 14:00:00 +00003964/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003965static void
hasso98b718a2004-10-11 12:57:57 +00003966rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00003967{
3968 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003969 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00003970
paul1eb8ef22005-04-07 07:30:20 +00003971 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3972 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00003973
3974 rip_routemap_update_redistribute ();
3975}
3976
paul718e3742002-12-13 20:15:29 +00003977/* Allocate new rip structure and set default value. */
3978void
pauldc63bfd2005-10-25 23:31:05 +00003979rip_init (void)
paul718e3742002-12-13 20:15:29 +00003980{
3981 /* Randomize for triggered update random(). */
3982 srand (time (NULL));
3983
3984 /* Install top nodes. */
3985 install_node (&rip_node, config_write_rip);
3986
3987 /* Install rip commands. */
3988 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003989 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003990 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003991 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003992 install_element (CONFIG_NODE, &router_rip_cmd);
3993 install_element (CONFIG_NODE, &no_router_rip_cmd);
3994
3995 install_default (RIP_NODE);
3996 install_element (RIP_NODE, &rip_version_cmd);
3997 install_element (RIP_NODE, &no_rip_version_cmd);
3998 install_element (RIP_NODE, &no_rip_version_val_cmd);
3999 install_element (RIP_NODE, &rip_default_metric_cmd);
4000 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4001 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4002 install_element (RIP_NODE, &rip_timers_cmd);
4003 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004004 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004005 install_element (RIP_NODE, &rip_route_cmd);
4006 install_element (RIP_NODE, &no_rip_route_cmd);
4007 install_element (RIP_NODE, &rip_distance_cmd);
4008 install_element (RIP_NODE, &no_rip_distance_cmd);
4009 install_element (RIP_NODE, &rip_distance_source_cmd);
4010 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4011 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4012 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
4013
4014 /* Debug related init. */
4015 rip_debug_init ();
4016
paul718e3742002-12-13 20:15:29 +00004017 /* SNMP init. */
4018#ifdef HAVE_SNMP
4019 rip_snmp_init ();
4020#endif /* HAVE_SNMP */
4021
4022 /* Access list install. */
4023 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004024 access_list_add_hook (rip_distribute_update_all_wrapper);
4025 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004026
4027 /* Prefix list initialize.*/
4028 prefix_list_init ();
4029 prefix_list_add_hook (rip_distribute_update_all);
4030 prefix_list_delete_hook (rip_distribute_update_all);
4031
4032 /* Distribute list install. */
4033 distribute_list_init (RIP_NODE);
4034 distribute_list_add_hook (rip_distribute_update);
4035 distribute_list_delete_hook (rip_distribute_update);
4036
hasso16705132003-05-25 14:49:19 +00004037 /* Route-map */
4038 rip_route_map_init ();
4039 rip_offset_init ();
4040
4041 route_map_add_hook (rip_routemap_update);
4042 route_map_delete_hook (rip_routemap_update);
4043
4044 if_rmap_init (RIP_NODE);
4045 if_rmap_hook_add (rip_if_rmap_update);
4046 if_rmap_hook_delete (rip_if_rmap_update);
4047
paul718e3742002-12-13 20:15:29 +00004048 /* Distance control. */
4049 rip_distance_table = route_table_init ();
4050}