blob: 82b1adaebf1681afe30094bbc0a256a7a9693b58 [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;
David Lamparter6b0655a2014-06-04 06:53:35 +020064
paul718e3742002-12-13 20:15:29 +000065/* 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);
David Lamparter6b0655a2014-06-04 06:53:35 +020070
paul718e3742002-12-13 20:15:29 +000071/* RIP output routes type. */
72enum
73{
74 rip_all_route,
75 rip_changed_route
76};
David Lamparter6b0655a2014-06-04 06:53:35 +020077
paul718e3742002-12-13 20:15:29 +000078/* 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};
David Lamparter6b0655a2014-06-04 06:53:35 +020089
paul718e3742002-12-13 20:15:29 +000090/* 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. */
Lu Fengb397cf42014-07-18 06:13:18 +0000141 listnode_delete (rp->info, rinfo);
142 if (list_isempty ((struct list *)rp->info))
143 {
144 list_free (rp->info);
145 rp->info = NULL;
146 route_unlock_node (rp);
147 }
paul718e3742002-12-13 20:15:29 +0000148
149 /* Free RIP routing information. */
150 rip_info_free (rinfo);
151
152 return 0;
153}
154
Lu Fengb397cf42014-07-18 06:13:18 +0000155static void rip_timeout_update (struct rip_info *rinfo);
156
157/* Add new route to the ECMP list.
Lu Feng0b74a0a2014-07-18 06:13:19 +0000158 * RETURN: the new entry added in the list, or NULL if it is not the first
159 * entry and ECMP is not allowed.
Lu Fengb397cf42014-07-18 06:13:18 +0000160 */
161struct rip_info *
162rip_ecmp_add (struct rip_info *rinfo_new)
163{
164 struct route_node *rp = rinfo_new->rp;
165 struct rip_info *rinfo = NULL;
166 struct list *list = NULL;
167
168 if (rp->info == NULL)
169 rp->info = list_new ();
170 list = (struct list *)rp->info;
171
Lu Feng0b74a0a2014-07-18 06:13:19 +0000172 /* If ECMP is not allowed and some entry already exists in the list,
173 * do nothing. */
174 if (listcount (list) && !rip->ecmp)
175 return NULL;
176
Lu Fengb397cf42014-07-18 06:13:18 +0000177 rinfo = rip_info_new ();
178 memcpy (rinfo, rinfo_new, sizeof (struct rip_info));
179 listnode_add (list, rinfo);
180
181 if (rip_route_rte (rinfo))
182 {
183 rip_timeout_update (rinfo);
184 rip_zebra_ipv4_add (rp);
185 }
186
187 /* Set the route change flag on the first entry. */
188 rinfo = listgetdata (listhead (list));
189 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
190
191 /* Signal the output process to trigger an update (see section 2.5). */
192 rip_event (RIP_TRIGGERED_UPDATE, 0);
193
194 return rinfo;
195}
196
197/* Replace the ECMP list with the new route.
198 * RETURN: the new entry added in the list
199 */
200struct rip_info *
201rip_ecmp_replace (struct rip_info *rinfo_new)
202{
203 struct route_node *rp = rinfo_new->rp;
204 struct list *list = (struct list *)rp->info;
205 struct rip_info *rinfo = NULL, *tmp_rinfo = NULL;
206 struct listnode *node = NULL, *nextnode = NULL;
207
208 if (list == NULL || listcount (list) == 0)
209 return rip_ecmp_add (rinfo_new);
210
211 /* Get the first entry */
212 rinfo = listgetdata (listhead (list));
213
214 /* Learnt route replaced by a local one. Delete it from zebra. */
215 if (rip_route_rte (rinfo) && !rip_route_rte (rinfo_new))
216 if (CHECK_FLAG (rinfo->flags, RIP_RTF_FIB))
217 rip_zebra_ipv4_delete (rp);
218
219 /* Re-use the first entry, and delete the others. */
220 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
221 if (tmp_rinfo != rinfo)
222 {
223 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
224 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
225 list_delete_node (list, node);
226 rip_info_free (tmp_rinfo);
227 }
228
229 RIP_TIMER_OFF (rinfo->t_timeout);
230 RIP_TIMER_OFF (rinfo->t_garbage_collect);
231 memcpy (rinfo, rinfo_new, sizeof (struct rip_info));
232
233 if (rip_route_rte (rinfo))
234 {
235 rip_timeout_update (rinfo);
236 /* The ADD message implies an update. */
237 rip_zebra_ipv4_add (rp);
238 }
239
240 /* Set the route change flag. */
241 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
242
243 /* Signal the output process to trigger an update (see section 2.5). */
244 rip_event (RIP_TRIGGERED_UPDATE, 0);
245
246 return rinfo;
247}
248
249/* Delete one route from the ECMP list.
250 * RETURN:
251 * null - the entry is freed, and other entries exist in the list
252 * the entry - the entry is the last one in the list; its metric is set
253 * to INFINITY, and the garbage collector is started for it
254 */
255struct rip_info *
256rip_ecmp_delete (struct rip_info *rinfo)
257{
258 struct route_node *rp = rinfo->rp;
259 struct list *list = (struct list *)rp->info;
260
261 RIP_TIMER_OFF (rinfo->t_timeout);
262
263 if (listcount (list) > 1)
264 {
265 /* Some other ECMP entries still exist. Just delete this entry. */
266 RIP_TIMER_OFF (rinfo->t_garbage_collect);
267 listnode_delete (list, rinfo);
268 if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB))
269 /* The ADD message implies the update. */
270 rip_zebra_ipv4_add (rp);
271 rip_info_free (rinfo);
272 rinfo = NULL;
273 }
274 else
275 {
276 assert (rinfo == listgetdata (listhead (list)));
277
278 /* This is the only entry left in the list. We must keep it in
279 * the list for garbage collection time, with INFINITY metric. */
280
281 rinfo->metric = RIP_METRIC_INFINITY;
282 RIP_TIMER_ON (rinfo->t_garbage_collect,
283 rip_garbage_collect, rip->garbage_time);
284
285 if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB))
286 rip_zebra_ipv4_delete (rp);
287 }
288
289 /* Set the route change flag on the first entry. */
290 rinfo = listgetdata (listhead (list));
291 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
292
293 /* Signal the output process to trigger an update (see section 2.5). */
294 rip_event (RIP_TRIGGERED_UPDATE, 0);
295
296 return rinfo;
297}
298
paul718e3742002-12-13 20:15:29 +0000299/* Timeout RIP routes. */
pauldc63bfd2005-10-25 23:31:05 +0000300static int
paul718e3742002-12-13 20:15:29 +0000301rip_timeout (struct thread *t)
302{
Lu Fengb397cf42014-07-18 06:13:18 +0000303 rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t));
paul718e3742002-12-13 20:15:29 +0000304 return 0;
305}
306
pauldc63bfd2005-10-25 23:31:05 +0000307static void
paul718e3742002-12-13 20:15:29 +0000308rip_timeout_update (struct rip_info *rinfo)
309{
310 if (rinfo->metric != RIP_METRIC_INFINITY)
311 {
312 RIP_TIMER_OFF (rinfo->t_timeout);
313 RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
314 }
315}
316
pauldc63bfd2005-10-25 23:31:05 +0000317static int
paul718e3742002-12-13 20:15:29 +0000318rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
319{
320 struct distribute *dist;
321 struct access_list *alist;
322 struct prefix_list *plist;
323
324 /* Input distribute-list filtering. */
325 if (ri->list[RIP_FILTER_IN])
326 {
327 if (access_list_apply (ri->list[RIP_FILTER_IN],
328 (struct prefix *) p) == FILTER_DENY)
329 {
330 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000331 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000332 inet_ntoa (p->prefix), p->prefixlen);
333 return -1;
334 }
335 }
336 if (ri->prefix[RIP_FILTER_IN])
337 {
338 if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
339 (struct prefix *) p) == PREFIX_DENY)
340 {
341 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000342 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000343 inet_ntoa (p->prefix), p->prefixlen);
344 return -1;
345 }
346 }
347
348 /* All interface filter check. */
349 dist = distribute_lookup (NULL);
350 if (dist)
351 {
352 if (dist->list[DISTRIBUTE_IN])
353 {
354 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
355
356 if (alist)
357 {
358 if (access_list_apply (alist,
359 (struct prefix *) p) == FILTER_DENY)
360 {
361 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000362 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000363 inet_ntoa (p->prefix), p->prefixlen);
364 return -1;
365 }
366 }
367 }
368 if (dist->prefix[DISTRIBUTE_IN])
369 {
370 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
371
372 if (plist)
373 {
374 if (prefix_list_apply (plist,
375 (struct prefix *) p) == PREFIX_DENY)
376 {
377 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000378 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000379 inet_ntoa (p->prefix), p->prefixlen);
380 return -1;
381 }
382 }
383 }
384 }
385 return 0;
386}
387
pauldc63bfd2005-10-25 23:31:05 +0000388static int
paul718e3742002-12-13 20:15:29 +0000389rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
390{
391 struct distribute *dist;
392 struct access_list *alist;
393 struct prefix_list *plist;
394
395 if (ri->list[RIP_FILTER_OUT])
396 {
397 if (access_list_apply (ri->list[RIP_FILTER_OUT],
398 (struct prefix *) p) == FILTER_DENY)
399 {
400 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000401 zlog_debug ("%s/%d is filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000402 inet_ntoa (p->prefix), p->prefixlen);
403 return -1;
404 }
405 }
406 if (ri->prefix[RIP_FILTER_OUT])
407 {
408 if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
409 (struct prefix *) p) == PREFIX_DENY)
410 {
411 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000412 zlog_debug ("%s/%d is filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000413 inet_ntoa (p->prefix), p->prefixlen);
414 return -1;
415 }
416 }
417
418 /* All interface filter check. */
419 dist = distribute_lookup (NULL);
420 if (dist)
421 {
422 if (dist->list[DISTRIBUTE_OUT])
423 {
424 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
425
426 if (alist)
427 {
428 if (access_list_apply (alist,
429 (struct prefix *) p) == FILTER_DENY)
430 {
431 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000432 zlog_debug ("%s/%d filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000433 inet_ntoa (p->prefix), p->prefixlen);
434 return -1;
435 }
436 }
437 }
438 if (dist->prefix[DISTRIBUTE_OUT])
439 {
440 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
441
442 if (plist)
443 {
444 if (prefix_list_apply (plist,
445 (struct prefix *) p) == PREFIX_DENY)
446 {
447 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000448 zlog_debug ("%s/%d filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000449 inet_ntoa (p->prefix), p->prefixlen);
450 return -1;
451 }
452 }
453 }
454 }
455 return 0;
456}
457
458/* Check nexthop address validity. */
459static int
460rip_nexthop_check (struct in_addr *addr)
461{
hasso52dc7ee2004-09-23 19:18:23 +0000462 struct listnode *node;
463 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000464 struct interface *ifp;
465 struct connected *ifc;
466 struct prefix *p;
467
468 /* If nexthop address matches local configured address then it is
469 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000470 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000471 {
paul1eb8ef22005-04-07 07:30:20 +0000472 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000473 {
paul718e3742002-12-13 20:15:29 +0000474 p = ifc->address;
475
476 if (p->family == AF_INET
477 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
478 return -1;
479 }
480 }
481 return 0;
482}
483
484/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000485static void
paul718e3742002-12-13 20:15:29 +0000486rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000487 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000488{
489 int ret;
490 struct prefix_ipv4 p;
491 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +0000492 struct rip_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000493 struct rip_interface *ri;
494 struct in_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000495 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000496 unsigned char old_dist, new_dist;
Lu Fengb397cf42014-07-18 06:13:18 +0000497 struct list *list = NULL;
498 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000499
500 /* Make prefix structure. */
501 memset (&p, 0, sizeof (struct prefix_ipv4));
502 p.family = AF_INET;
503 p.prefix = rte->prefix;
504 p.prefixlen = ip_masklen (rte->mask);
505
506 /* Make sure mask is applied. */
507 apply_mask_ipv4 (&p);
508
509 /* Apply input filters. */
510 ri = ifp->info;
511
512 ret = rip_incoming_filter (&p, ri);
513 if (ret < 0)
514 return;
515
Lu Fengb397cf42014-07-18 06:13:18 +0000516 memset (&newinfo, 0, sizeof (newinfo));
517 newinfo.type = ZEBRA_ROUTE_RIP;
518 newinfo.sub_type = RIP_ROUTE_RTE;
519 newinfo.nexthop = rte->nexthop;
520 newinfo.from = from->sin_addr;
521 newinfo.ifindex = ifp->ifindex;
522 newinfo.metric = rte->metric;
523 newinfo.metric_out = rte->metric; /* XXX */
524 newinfo.tag = ntohs (rte->tag); /* XXX */
525
hasso16705132003-05-25 14:49:19 +0000526 /* Modify entry according to the interface routemap. */
527 if (ri->routemap[RIP_FILTER_IN])
528 {
529 int ret;
hasso16705132003-05-25 14:49:19 +0000530
531 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000532 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
533 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000534
535 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000536 {
537 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000538 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000539 inet_ntoa (p.prefix), p.prefixlen);
540 return;
541 }
hasso16705132003-05-25 14:49:19 +0000542
543 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000544 rte->nexthop = newinfo.nexthop_out;
545 rte->tag = htons (newinfo.tag_out); /* XXX */
546 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000547 }
548
paul718e3742002-12-13 20:15:29 +0000549 /* Once the entry has been validated, update the metric by
550 adding the cost of the network on wich the message
551 arrived. If the result is greater than infinity, use infinity
552 (RFC2453 Sec. 3.9.2) */
553 /* Zebra ripd can handle offset-list in. */
554 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
555
556 /* If offset-list does not modify the metric use interface's
557 metric. */
paula87552c2004-05-03 20:00:17 +0000558 if (!ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000559 rte->metric += ifp->metric ? ifp->metric : 1;
paul718e3742002-12-13 20:15:29 +0000560
561 if (rte->metric > RIP_METRIC_INFINITY)
562 rte->metric = RIP_METRIC_INFINITY;
563
564 /* Set nexthop pointer. */
565 if (rte->nexthop.s_addr == 0)
566 nexthop = &from->sin_addr;
567 else
568 nexthop = &rte->nexthop;
569
hasso16705132003-05-25 14:49:19 +0000570 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000571 if (rip_nexthop_check (nexthop) < 0)
572 {
573 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000574 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000575 return;
576 }
577
578 /* Get index for the prefix. */
579 rp = route_node_get (rip->table, (struct prefix *) &p);
580
Lu Fengb397cf42014-07-18 06:13:18 +0000581 newinfo.rp = rp;
582 newinfo.nexthop = *nexthop;
583 newinfo.metric = rte->metric;
584 newinfo.tag = ntohs (rte->tag);
585 newinfo.distance = rip_distance_apply (&newinfo);
586
587 new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT;
588
paul718e3742002-12-13 20:15:29 +0000589 /* Check to see whether there is already RIP route on the table. */
Lu Fengb397cf42014-07-18 06:13:18 +0000590 if ((list = rp->info) != NULL)
591 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
592 {
593 /* Need to compare with redistributed entry or local entry */
594 if (!rip_route_rte (rinfo))
595 break;
596
597 if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) &&
598 IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
599 break;
600
601 if (!listnextnode (node))
602 {
603 /* Not found in the list */
604
605 if (rte->metric > rinfo->metric)
606 {
607 /* New route has a greater metric. Discard it. */
608 route_unlock_node (rp);
609 return;
610 }
611
612 if (rte->metric < rinfo->metric)
613 /* New route has a smaller metric. Replace the ECMP list
614 * with the new one in below. */
615 break;
616
617 /* Metrics are same. We compare the distances. */
618 old_dist = rinfo->distance ? \
619 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
620
621 if (new_dist > old_dist)
622 {
623 /* New route has a greater distance. Discard it. */
624 route_unlock_node (rp);
625 return;
626 }
627
628 if (new_dist < old_dist)
629 /* New route has a smaller distance. Replace the ECMP list
630 * with the new one in below. */
631 break;
632
633 /* Metrics and distances are both same. Keep "rinfo" null and
634 * the new route is added in the ECMP list in below. */
635 }
636 }
paul718e3742002-12-13 20:15:29 +0000637
638 if (rinfo)
639 {
paul718e3742002-12-13 20:15:29 +0000640 /* Local static route. */
641 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000642 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
643 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
644 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000645 {
646 route_unlock_node (rp);
647 return;
648 }
649
650 /* Redistributed route check. */
651 if (rinfo->type != ZEBRA_ROUTE_RIP
652 && rinfo->metric != RIP_METRIC_INFINITY)
653 {
vincentfbf5d032005-09-29 11:25:50 +0000654 old_dist = rinfo->distance;
David Lamparterb68da442013-02-28 22:17:00 +0100655 /* Only routes directly connected to an interface (nexthop == 0)
656 * may have a valid NULL distance */
657 if (rinfo->nexthop.s_addr != 0)
vincent7a383332006-01-30 18:12:42 +0000658 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000659 /* If imported route does not have STRICT precedence,
660 mark it as a ghost */
Lu Fengb397cf42014-07-18 06:13:18 +0000661 if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY)
662 rip_ecmp_replace (&newinfo);
663
664 route_unlock_node (rp);
665 return;
vincentfbf5d032005-09-29 11:25:50 +0000666 }
paul718e3742002-12-13 20:15:29 +0000667 }
paula87552c2004-05-03 20:00:17 +0000668
669 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000670 {
Lu Fengb397cf42014-07-18 06:13:18 +0000671 if (rp->info)
672 route_unlock_node (rp);
673
paul718e3742002-12-13 20:15:29 +0000674 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000675 for the destination prefix. If there is no such route, add
676 this route to the routing table, unless the metric is
677 infinity (there is no point in adding a route which
678 unusable). */
paul718e3742002-12-13 20:15:29 +0000679 if (rte->metric != RIP_METRIC_INFINITY)
Lu Fengb397cf42014-07-18 06:13:18 +0000680 rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000681 }
682 else
683 {
684 /* Route is there but we are not sure the route is RIP or not. */
paula87552c2004-05-03 20:00:17 +0000685
paul718e3742002-12-13 20:15:29 +0000686 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000687 to the address of the router from which the datagram came.
688 If this datagram is from the same router as the existing
689 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000690 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000691 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000692
Lu Fengb397cf42014-07-18 06:13:18 +0000693 old_dist = rinfo->distance ? \
694 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
paulb94f9db2004-05-01 20:45:38 +0000695
paul718e3742002-12-13 20:15:29 +0000696 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000697 router as the existing route, and the new metric is different
698 than the old one; or, if the new metric is lower than the old
699 one, or if the tag has been changed; or if there is a route
700 with a lower administrave distance; or an update of the
701 distance on the actual route; do the following actions: */
702 if ((same && rinfo->metric != rte->metric)
703 || (rte->metric < rinfo->metric)
704 || ((same)
705 && (rinfo->metric == rte->metric)
Lu Fengb397cf42014-07-18 06:13:18 +0000706 && (newinfo.tag != rinfo->tag))
707 || (old_dist > new_dist)
708 || ((old_dist != new_dist) && same))
paula87552c2004-05-03 20:00:17 +0000709 {
Lu Fengb397cf42014-07-18 06:13:18 +0000710 if (listcount (list) == 1)
paula87552c2004-05-03 20:00:17 +0000711 {
Lu Fengb397cf42014-07-18 06:13:18 +0000712 if (newinfo.metric != RIP_METRIC_INFINITY)
713 rip_ecmp_replace (&newinfo);
714 else
715 rip_ecmp_delete (rinfo);
paula87552c2004-05-03 20:00:17 +0000716 }
717 else
718 {
Lu Fengb397cf42014-07-18 06:13:18 +0000719 if (newinfo.metric < rinfo->metric)
720 rip_ecmp_replace (&newinfo);
721 else if (newinfo.metric > rinfo->metric)
722 rip_ecmp_delete (rinfo);
723 else if (new_dist < old_dist)
724 rip_ecmp_replace (&newinfo);
725 else if (new_dist > old_dist)
726 rip_ecmp_delete (rinfo);
727 else
728 {
729 int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0;
730
731 assert (newinfo.metric != RIP_METRIC_INFINITY);
732
733 RIP_TIMER_OFF (rinfo->t_timeout);
734 RIP_TIMER_OFF (rinfo->t_garbage_collect);
735 memcpy (rinfo, &newinfo, sizeof (struct rip_info));
736 rip_timeout_update (rinfo);
737
738 if (update)
739 rip_zebra_ipv4_add (rp);
740
741 /* - Set the route change flag on the first entry. */
742 rinfo = listgetdata (listhead (list));
743 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
744 rip_event (RIP_TRIGGERED_UPDATE, 0);
745 }
paula87552c2004-05-03 20:00:17 +0000746 }
747 }
Lu Fengb397cf42014-07-18 06:13:18 +0000748 else /* same & no change */
749 rip_timeout_update (rinfo);
750
paul718e3742002-12-13 20:15:29 +0000751 /* Unlock tempolary lock of the route. */
752 route_unlock_node (rp);
753 }
754}
755
756/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000757static void
hasso8a676be2004-10-08 06:36:38 +0000758rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000759{
760 caddr_t lim;
761 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000762 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000763 char pbuf[BUFSIZ], nbuf[BUFSIZ];
764 u_char netmask = 0;
765 u_char *p;
766
767 /* Set command string. */
768 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
769 command_str = lookup (rip_msg, packet->command);
770 else
771 command_str = "unknown";
772
773 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000774 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000775 sndrcv, command_str, packet->version, size);
776
777 /* Dump each routing table entry. */
778 rte = packet->rte;
779
780 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
781 {
782 if (packet->version == RIPv2)
783 {
784 netmask = ip_masklen (rte->mask);
785
paulca5e5162004-06-06 22:06:33 +0000786 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000787 {
paulca5e5162004-06-06 22:06:33 +0000788 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000789 {
790 p = (u_char *)&rte->prefix;
791
ajs5d6c3772004-12-08 19:24:06 +0000792 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000793 ntohs (rte->family), ntohs (rte->tag), p);
794 }
paulca5e5162004-06-06 22:06:33 +0000795 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000796 {
797 struct rip_md5_info *md5;
798
799 md5 = (struct rip_md5_info *) &packet->rte;
800
ajs5d6c3772004-12-08 19:24:06 +0000801 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000802 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000803 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000804 " Auth Data len %d",
805 ntohs (md5->packet_len), md5->keyid,
806 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000807 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000808 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000809 }
paulca5e5162004-06-06 22:06:33 +0000810 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000811 {
812 p = (u_char *)&rte->prefix;
813
ajs5d6c3772004-12-08 19:24:06 +0000814 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000815 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000816 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000817 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000818 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
819 p[7], p[9], p[10], p[11], p[12], p[13],
820 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000821 }
822 else
823 {
ajs5d6c3772004-12-08 19:24:06 +0000824 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000825 ntohs (rte->family), ntohs (rte->tag));
826 }
827 }
828 else
ajs5d6c3772004-12-08 19:24:06 +0000829 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000830 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
831 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
832 BUFSIZ), ntohs (rte->family),
833 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000834 }
835 else
836 {
ajs5d6c3772004-12-08 19:24:06 +0000837 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000838 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
839 ntohs (rte->family), ntohs (rte->tag),
840 (u_long)ntohl (rte->metric));
841 }
842 }
843}
844
845/* Check if the destination address is valid (unicast; not net 0
846 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
847 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000848static int
paul718e3742002-12-13 20:15:29 +0000849rip_destination_check (struct in_addr addr)
850{
851 u_int32_t destination;
852
853 /* Convert to host byte order. */
854 destination = ntohl (addr.s_addr);
855
856 if (IPV4_NET127 (destination))
857 return 0;
858
859 /* Net 0 may match to the default route. */
860 if (IPV4_NET0 (destination) && destination != 0)
861 return 0;
862
863 /* Unicast address must belong to class A, B, C. */
864 if (IN_CLASSA (destination))
865 return 1;
866 if (IN_CLASSB (destination))
867 return 1;
868 if (IN_CLASSC (destination))
869 return 1;
870
871 return 0;
872}
873
874/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000875static int
paul718e3742002-12-13 20:15:29 +0000876rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
877 struct interface *ifp)
878{
879 struct rip_interface *ri;
880 char *auth_str;
881
882 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000883 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000884 inet_ntoa (from->sin_addr));
885
886 ri = ifp->info;
887
888 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000889 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000890 return 0;
891
892 /* Simple password authentication. */
893 if (ri->auth_str)
894 {
895 auth_str = (char *) &rte->prefix;
896
897 if (strncmp (auth_str, ri->auth_str, 16) == 0)
898 return 1;
899 }
900 if (ri->key_chain)
901 {
902 struct keychain *keychain;
903 struct key *key;
904
905 keychain = keychain_lookup (ri->key_chain);
906 if (keychain == NULL)
907 return 0;
908
909 key = key_match_for_accept (keychain, (char *) &rte->prefix);
910 if (key)
911 return 1;
912 }
913 return 0;
914}
915
916/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000917static int
paul718e3742002-12-13 20:15:29 +0000918rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000919 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000920{
921 struct rip_interface *ri;
922 struct rip_md5_info *md5;
923 struct rip_md5_data *md5data;
924 struct keychain *keychain;
925 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000926 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000927 u_char digest[RIP_AUTH_MD5_SIZE];
928 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000929 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000930
931 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000932 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000933 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000934
935 ri = ifp->info;
936 md5 = (struct rip_md5_info *) &packet->rte;
937
938 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000939 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000940 return 0;
941
paulca5e5162004-06-06 22:06:33 +0000942 /* If the authentication length is less than 16, then it must be wrong for
943 * any interpretation of rfc2082. Some implementations also interpret
944 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000945 */
paulca5e5162004-06-06 22:06:33 +0000946 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
947 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000948 {
949 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000950 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000951 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000952 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000953 }
paul718e3742002-12-13 20:15:29 +0000954
paulca5e5162004-06-06 22:06:33 +0000955 /* grab and verify check packet length */
956 packet_len = ntohs (md5->packet_len);
957
958 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
959 {
960 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000961 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000962 "greater than received length %d!",
963 md5->packet_len, length);
964 return 0;
965 }
966
967 /* retrieve authentication data */
968 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000969
970 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000971
paul718e3742002-12-13 20:15:29 +0000972 if (ri->key_chain)
973 {
974 keychain = keychain_lookup (ri->key_chain);
975 if (keychain == NULL)
976 return 0;
977
978 key = key_lookup_for_accept (keychain, md5->keyid);
979 if (key == NULL)
980 return 0;
981
paul98fd1e62006-01-17 17:26:25 +0000982 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000983 }
paul98fd1e62006-01-17 17:26:25 +0000984 else if (ri->auth_str)
985 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000986
Paul Jakmafa93b162008-05-29 19:03:08 +0000987 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000988 return 0;
paul98fd1e62006-01-17 17:26:25 +0000989
paul718e3742002-12-13 20:15:29 +0000990 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000991 memset (&ctx, 0, sizeof(ctx));
992 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000993 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
994 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000995 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000996
997 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000998 return packet_len;
999 else
1000 return 0;
1001}
1002
paulb14ee002005-02-04 23:42:41 +00001003/* Pick correct auth string for sends, prepare auth_str buffer for use.
1004 * (left justified and padded).
1005 *
1006 * presumes one of ri or key is valid, and that the auth strings they point
1007 * to are nul terminated. If neither are present, auth_str will be fully
1008 * zero padded.
1009 *
1010 */
1011static void
1012rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
1013 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +00001014{
paulb14ee002005-02-04 23:42:41 +00001015 assert (ri || key);
paul718e3742002-12-13 20:15:29 +00001016
paulb14ee002005-02-04 23:42:41 +00001017 memset (auth_str, 0, len);
1018 if (key && key->string)
1019 strncpy (auth_str, key->string, len);
1020 else if (ri->auth_str)
1021 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +00001022
paulb14ee002005-02-04 23:42:41 +00001023 return;
1024}
paul718e3742002-12-13 20:15:29 +00001025
paulb14ee002005-02-04 23:42:41 +00001026/* Write RIPv2 simple password authentication information
1027 *
1028 * auth_str is presumed to be 2 bytes and correctly prepared
1029 * (left justified and zero padded).
1030 */
1031static void
1032rip_auth_simple_write (struct stream *s, char *auth_str, int len)
1033{
1034 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00001035
paulb14ee002005-02-04 23:42:41 +00001036 stream_putw (s, RIP_FAMILY_AUTH);
1037 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
1038 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
1039
1040 return;
1041}
1042
1043/* write RIPv2 MD5 "authentication header"
1044 * (uses the auth key data field)
1045 *
1046 * Digest offset field is set to 0.
1047 *
1048 * returns: offset of the digest offset field, which must be set when
1049 * length to the auth-data MD5 digest is known.
1050 */
1051static size_t
1052rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
1053 struct key *key)
1054{
paul98fd1e62006-01-17 17:26:25 +00001055 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +00001056
1057 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +00001058
1059 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +00001060 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +00001061 stream_putw (s, RIP_AUTH_MD5);
1062
paulb14ee002005-02-04 23:42:41 +00001063 /* MD5 AH digest offset field.
1064 *
1065 * Set to placeholder value here, to true value when RIP-2 Packet length
1066 * is known. Actual value is set in .....().
1067 */
paul98fd1e62006-01-17 17:26:25 +00001068 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001069 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001070
1071 /* Key ID. */
1072 if (key)
1073 stream_putc (s, key->index % 256);
1074 else
1075 stream_putc (s, 1);
1076
paulca5e5162004-06-06 22:06:33 +00001077 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1078 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1079 * to be configurable.
1080 */
1081 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001082
1083 /* Sequence Number (non-decreasing). */
1084 /* RFC2080: The value used in the sequence number is
1085 arbitrary, but two suggestions are the time of the
1086 message's creation or a simple message counter. */
1087 stream_putl (s, time (NULL));
1088
1089 /* Reserved field must be zero. */
1090 stream_putl (s, 0);
1091 stream_putl (s, 0);
1092
paul98fd1e62006-01-17 17:26:25 +00001093 return doff;
paulb14ee002005-02-04 23:42:41 +00001094}
paul718e3742002-12-13 20:15:29 +00001095
paulb14ee002005-02-04 23:42:41 +00001096/* If authentication is in used, write the appropriate header
1097 * returns stream offset to which length must later be written
1098 * or 0 if this is not required
1099 */
1100static size_t
1101rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1102 struct key *key, char *auth_str, int len)
1103{
1104 assert (ri->auth_type != RIP_NO_AUTH);
1105
1106 switch (ri->auth_type)
1107 {
1108 case RIP_AUTH_SIMPLE_PASSWORD:
1109 rip_auth_prepare_str_send (ri, key, auth_str, len);
1110 rip_auth_simple_write (s, auth_str, len);
1111 return 0;
1112 case RIP_AUTH_MD5:
1113 return rip_auth_md5_ah_write (s, ri, key);
1114 }
1115 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001116 return 0;
paulb14ee002005-02-04 23:42:41 +00001117}
1118
1119/* Write RIPv2 MD5 authentication data trailer */
1120static void
1121rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1122 char *auth_str, int authlen)
1123{
1124 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001125 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001126 unsigned char digest[RIP_AUTH_MD5_SIZE];
1127
1128 /* Make it sure this interface is configured as MD5
1129 authentication. */
1130 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1131 assert (doff > 0);
1132
1133 /* Get packet length. */
1134 len = stream_get_endp(s);
1135
1136 /* Check packet length. */
1137 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1138 {
1139 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1140 return;
1141 }
1142
1143 /* Set the digest offset length in the header */
1144 stream_putw_at (s, doff, len);
1145
paul718e3742002-12-13 20:15:29 +00001146 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001147 stream_putw (s, RIP_FAMILY_AUTH);
1148 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001149
1150 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001151 memset(&ctx, 0, sizeof(ctx));
1152 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001153 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001154 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1155 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001156
1157 /* Copy the digest to the packet. */
1158 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1159}
1160
1161/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001162static void
paul718e3742002-12-13 20:15:29 +00001163rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001164 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001165{
1166 caddr_t lim;
1167 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001168 struct prefix_ipv4 ifaddr;
1169 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001170 int subnetted;
Donald Sharp26a18eb2015-09-29 09:25:10 -04001171
1172 memset(&ifaddr, 0, sizeof(ifaddr));
paul727d1042002-12-13 20:50:29 +00001173 /* We don't know yet. */
1174 subnetted = -1;
1175
paul718e3742002-12-13 20:15:29 +00001176 /* The Response must be ignored if it is not from the RIP
1177 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001178 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001179 {
1180 zlog_info ("response doesn't come from RIP port: %d",
1181 from->sin_port);
1182 rip_peer_bad_packet (from);
1183 return;
1184 }
1185
1186 /* The datagram's IPv4 source address should be checked to see
1187 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001188 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1189 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001190 {
1191 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1192 inet_ntoa (from->sin_addr));
1193 rip_peer_bad_packet (from);
1194 return;
1195 }
1196
1197 /* It is also worth checking to see whether the response is from one
1198 of the router's own addresses. */
1199
1200 ; /* Alredy done in rip_read () */
1201
1202 /* Update RIP peer. */
1203 rip_peer_update (from, packet->version);
1204
1205 /* Set RTE pointer. */
1206 rte = packet->rte;
1207
1208 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1209 {
1210 /* RIPv2 authentication check. */
1211 /* If the Address Family Identifier of the first (and only the
1212 first) entry in the message is 0xFFFF, then the remainder of
1213 the entry contains the authentication. */
1214 /* If the packet gets here it means authentication enabled */
1215 /* Check is done in rip_read(). So, just skipping it */
1216 if (packet->version == RIPv2 &&
1217 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001218 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001219 continue;
1220
paulca5e5162004-06-06 22:06:33 +00001221 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001222 {
1223 /* Address family check. RIP only supports AF_INET. */
1224 zlog_info ("Unsupported family %d from %s.",
1225 ntohs (rte->family), inet_ntoa (from->sin_addr));
1226 continue;
1227 }
1228
1229 /* - is the destination address valid (e.g., unicast; not net 0
1230 or 127) */
1231 if (! rip_destination_check (rte->prefix))
1232 {
1233 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1234 rip_peer_bad_route (from);
1235 continue;
1236 }
1237
1238 /* Convert metric value to host byte order. */
1239 rte->metric = ntohl (rte->metric);
1240
1241 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1242 if (! (rte->metric >= 1 && rte->metric <= 16))
1243 {
1244 zlog_info ("Route's metric is not in the 1-16 range.");
1245 rip_peer_bad_route (from);
1246 continue;
1247 }
1248
1249 /* RIPv1 does not have nexthop value. */
1250 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1251 {
1252 zlog_info ("RIPv1 packet with nexthop value %s",
1253 inet_ntoa (rte->nexthop));
1254 rip_peer_bad_route (from);
1255 continue;
1256 }
1257
1258 /* That is, if the provided information is ignored, a possibly
1259 sub-optimal, but absolutely valid, route may be taken. If
1260 the received Next Hop is not directly reachable, it should be
1261 treated as 0.0.0.0. */
1262 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1263 {
1264 u_int32_t addrval;
1265
1266 /* Multicast address check. */
1267 addrval = ntohl (rte->nexthop.s_addr);
1268 if (IN_CLASSD (addrval))
1269 {
1270 zlog_info ("Nexthop %s is multicast address, skip this rte",
1271 inet_ntoa (rte->nexthop));
1272 continue;
1273 }
1274
1275 if (! if_lookup_address (rte->nexthop))
1276 {
1277 struct route_node *rn;
1278 struct rip_info *rinfo;
1279
1280 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1281
1282 if (rn)
1283 {
1284 rinfo = rn->info;
1285
1286 if (rinfo->type == ZEBRA_ROUTE_RIP
1287 && rinfo->sub_type == RIP_ROUTE_RTE)
1288 {
1289 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001290 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 +00001291 rte->nexthop = rinfo->from;
1292 }
1293 else
1294 {
1295 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001296 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 +00001297 rte->nexthop.s_addr = 0;
1298 }
1299
1300 route_unlock_node (rn);
1301 }
1302 else
1303 {
1304 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001305 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 +00001306 rte->nexthop.s_addr = 0;
1307 }
1308
1309 }
1310 }
1311
1312 /* For RIPv1, there won't be a valid netmask.
1313
1314 This is a best guess at the masks. If everyone was using old
1315 Ciscos before the 'ip subnet zero' option, it would be almost
1316 right too :-)
1317
1318 Cisco summarize ripv1 advertisments to the classful boundary
1319 (/16 for class B's) except when the RIP packet does to inside
1320 the classful network in question. */
1321
1322 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1323 || (packet->version == RIPv2
1324 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1325 {
1326 u_int32_t destination;
1327
paul727d1042002-12-13 20:50:29 +00001328 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001329 {
1330 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1331 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1332 apply_classful_mask_ipv4 (&ifaddrclass);
1333 subnetted = 0;
1334 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1335 subnetted = 1;
1336 }
paul727d1042002-12-13 20:50:29 +00001337
paul718e3742002-12-13 20:15:29 +00001338 destination = ntohl (rte->prefix.s_addr);
1339
paul727d1042002-12-13 20:50:29 +00001340 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001341 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001342 else if (IN_CLASSB (destination))
1343 masklen2ip (16, &rte->mask);
1344 else if (IN_CLASSC (destination))
1345 masklen2ip (24, &rte->mask);
1346
1347 if (subnetted == 1)
1348 masklen2ip (ifaddrclass.prefixlen,
1349 (struct in_addr *) &destination);
1350 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1351 ifaddrclass.prefix.s_addr))
1352 {
1353 masklen2ip (ifaddr.prefixlen, &rte->mask);
1354 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1355 masklen2ip (32, &rte->mask);
1356 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001357 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001358 }
1359 else
1360 {
1361 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1362 continue;
1363 }
1364
1365 if (IS_RIP_DEBUG_EVENT)
1366 {
ajs5d6c3772004-12-08 19:24:06 +00001367 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1368 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001369 }
1370 }
1371
1372 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1373 ignore the entry. */
1374 if ((packet->version == RIPv2)
1375 && (rte->mask.s_addr != 0)
1376 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1377 {
1378 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1379 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1380 rip_peer_bad_route (from);
1381 continue;
1382 }
1383
1384 /* Default route's netmask is ignored. */
1385 if (packet->version == RIPv2
1386 && (rte->prefix.s_addr == 0)
1387 && (rte->mask.s_addr != 0))
1388 {
1389 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001390 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001391 rte->mask.s_addr = 0;
1392 }
1393
1394 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001395 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001396 }
1397}
1398
paula4e987e2005-06-03 17:46:49 +00001399/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001400static int
paul2c61ae32005-08-16 15:22:14 +00001401rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001402{
1403 int ret;
1404 int sock;
1405 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001406
paul2c61ae32005-08-16 15:22:14 +00001407 memset (&addr, 0, sizeof (struct sockaddr_in));
1408
1409 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001410 {
paulf69bd9d2005-06-03 18:01:50 +00001411 addr.sin_family = AF_INET;
1412 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001413#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001414 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001415#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001416 } else {
1417 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001418 }
1419
paul2c61ae32005-08-16 15:22:14 +00001420 /* sending port must always be the RIP port */
1421 addr.sin_port = htons (RIP_PORT_DEFAULT);
1422
paula4e987e2005-06-03 17:46:49 +00001423 /* Make datagram socket. */
1424 sock = socket (AF_INET, SOCK_DGRAM, 0);
1425 if (sock < 0)
1426 {
1427 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1428 exit (1);
1429 }
1430
1431 sockopt_broadcast (sock);
1432 sockopt_reuseaddr (sock);
1433 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001434#ifdef RIP_RECVMSG
1435 setsockopt_pktinfo (sock);
1436#endif /* RIP_RECVMSG */
Stephen Hemminger78b31d52009-07-21 16:27:26 -07001437#ifdef IPTOS_PREC_INTERNETCONTROL
1438 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
1439#endif
paula4e987e2005-06-03 17:46:49 +00001440
1441 if (ripd_privs.change (ZPRIVS_RAISE))
1442 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001443 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1444 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1445
paula4e987e2005-06-03 17:46:49 +00001446 {
1447 int save_errno = errno;
1448 if (ripd_privs.change (ZPRIVS_LOWER))
1449 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001450
1451 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1452 sock, inet_ntoa(addr.sin_addr),
1453 (int) ntohs(addr.sin_port),
1454 safe_strerror(save_errno));
1455
paulf69bd9d2005-06-03 18:01:50 +00001456 close (sock);
paula4e987e2005-06-03 17:46:49 +00001457 return ret;
1458 }
paulf69bd9d2005-06-03 18:01:50 +00001459
paula4e987e2005-06-03 17:46:49 +00001460 if (ripd_privs.change (ZPRIVS_LOWER))
1461 zlog_err ("rip_create_socket: could not lower privs");
1462
1463 return sock;
1464}
1465
paulc49ad8f2004-10-22 10:27:28 +00001466/* RIP packet send to destination address, on interface denoted by
1467 * by connected argument. NULL to argument denotes destination should be
1468 * should be RIP multicast group
1469 */
pauldc63bfd2005-10-25 23:31:05 +00001470static int
paulc49ad8f2004-10-22 10:27:28 +00001471rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1472 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001473{
paul931cd542004-01-23 15:31:42 +00001474 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001475 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001476
1477 assert (ifc != NULL);
1478
paul931cd542004-01-23 15:31:42 +00001479 if (IS_RIP_DEBUG_PACKET)
1480 {
paulf69bd9d2005-06-03 18:01:50 +00001481#define ADDRESS_SIZE 20
1482 char dst[ADDRESS_SIZE];
1483 dst[ADDRESS_SIZE - 1] = '\0';
1484
paul931cd542004-01-23 15:31:42 +00001485 if (to)
1486 {
paulf69bd9d2005-06-03 18:01:50 +00001487 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001488 }
1489 else
1490 {
1491 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001492 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001493 }
paulf69bd9d2005-06-03 18:01:50 +00001494#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001495 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001496 inet_ntoa(ifc->address->u.prefix4),
1497 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001498 }
paulf69bd9d2005-06-03 18:01:50 +00001499
paulc49ad8f2004-10-22 10:27:28 +00001500 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001501 {
1502 /*
1503 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1504 * with multiple addresses on the same subnet: the first address
1505 * on the subnet is configured "primary", and all subsequent addresses
1506 * on that subnet are treated as "secondary" addresses.
1507 * In order to avoid routing-table bloat on other rip listeners,
1508 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1509 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1510 * flag is set, we would end up sending a packet for a "secondary"
1511 * source address on non-linux systems.
1512 */
1513 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001514 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001515 return 0;
1516 }
1517
paul718e3742002-12-13 20:15:29 +00001518 /* Make destination address. */
1519 memset (&sin, 0, sizeof (struct sockaddr_in));
1520 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001521#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001522 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001523#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001524
1525 /* When destination is specified, use it's port and address. */
1526 if (to)
1527 {
paul718e3742002-12-13 20:15:29 +00001528 sin.sin_port = to->sin_port;
1529 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001530 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001531 }
1532 else
1533 {
paul2c61ae32005-08-16 15:22:14 +00001534 struct sockaddr_in from;
1535
paul718e3742002-12-13 20:15:29 +00001536 sin.sin_port = htons (RIP_PORT_DEFAULT);
1537 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001538
1539 /* multicast send should bind to local interface address */
Nick Hilliardbb2315f2012-08-18 15:10:57 +00001540 memset (&from, 0, sizeof (from));
paul2c61ae32005-08-16 15:22:14 +00001541 from.sin_family = AF_INET;
1542 from.sin_port = htons (RIP_PORT_DEFAULT);
1543 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001544#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001545 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001546#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001547
paul931cd542004-01-23 15:31:42 +00001548 /*
1549 * we have to open a new socket for each packet because this
1550 * is the most portable way to bind to a different source
1551 * ipv4 address for each packet.
1552 */
paul2c61ae32005-08-16 15:22:14 +00001553 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001554 {
paulf69bd9d2005-06-03 18:01:50 +00001555 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001556 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001557 }
paulc49ad8f2004-10-22 10:27:28 +00001558 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001559 }
1560
paul931cd542004-01-23 15:31:42 +00001561 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001562 sizeof (struct sockaddr_in));
1563
1564 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001565 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001566 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001567
1568 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001569 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001570
paul931cd542004-01-23 15:31:42 +00001571 if (!to)
1572 close(send_sock);
1573
paul718e3742002-12-13 20:15:29 +00001574 return ret;
1575}
1576
1577/* Add redistributed route to RIP table. */
1578void
1579rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001580 ifindex_t ifindex, struct in_addr *nexthop,
vincentfbf5d032005-09-29 11:25:50 +00001581 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001582{
1583 int ret;
Lu Fengb397cf42014-07-18 06:13:18 +00001584 struct route_node *rp = NULL;
1585 struct rip_info *rinfo = NULL, newinfo;
1586 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001587
1588 /* Redistribute route */
1589 ret = rip_destination_check (p->prefix);
1590 if (! ret)
1591 return;
1592
1593 rp = route_node_get (rip->table, (struct prefix *) p);
1594
Lu Fengb397cf42014-07-18 06:13:18 +00001595 memset (&newinfo, 0, sizeof (struct rip_info));
1596 newinfo.type = type;
1597 newinfo.sub_type = sub_type;
1598 newinfo.ifindex = ifindex;
1599 newinfo.metric = 1;
1600 newinfo.external_metric = metric;
1601 newinfo.distance = distance;
1602 newinfo.rp = rp;
1603 if (nexthop)
1604 newinfo.nexthop = *nexthop;
paul718e3742002-12-13 20:15:29 +00001605
Lu Fengb397cf42014-07-18 06:13:18 +00001606 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00001607 {
Lu Fengb397cf42014-07-18 06:13:18 +00001608 rinfo = listgetdata (listhead (list));
1609
paul718e3742002-12-13 20:15:29 +00001610 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1611 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1612 && rinfo->metric != RIP_METRIC_INFINITY)
1613 {
1614 route_unlock_node (rp);
1615 return;
1616 }
1617
1618 /* Manually configured RIP route check. */
1619 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001620 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1621 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001622 {
hasso16705132003-05-25 14:49:19 +00001623 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1624 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001625 {
1626 route_unlock_node (rp);
1627 return;
1628 }
1629 }
1630
Lu Fengb397cf42014-07-18 06:13:18 +00001631 rinfo = rip_ecmp_replace (&newinfo);
1632 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001633 }
Lu Fengb397cf42014-07-18 06:13:18 +00001634 else
1635 rinfo = rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +00001636
hasso16705132003-05-25 14:49:19 +00001637 if (IS_RIP_DEBUG_EVENT) {
1638 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001639 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001640 inet_ntoa(p->prefix), p->prefixlen,
1641 ifindex2ifname(ifindex));
1642 else
ajs5d6c3772004-12-08 19:24:06 +00001643 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001644 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1645 ifindex2ifname(ifindex));
1646 }
1647
paul718e3742002-12-13 20:15:29 +00001648 rip_event (RIP_TRIGGERED_UPDATE, 0);
1649}
1650
1651/* Delete redistributed route from RIP table. */
1652void
1653rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001654 ifindex_t ifindex)
paul718e3742002-12-13 20:15:29 +00001655{
1656 int ret;
1657 struct route_node *rp;
1658 struct rip_info *rinfo;
1659
1660 ret = rip_destination_check (p->prefix);
1661 if (! ret)
1662 return;
1663
1664 rp = route_node_lookup (rip->table, (struct prefix *) p);
1665 if (rp)
1666 {
Lu Fengb397cf42014-07-18 06:13:18 +00001667 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +00001668
Lu Fengb397cf42014-07-18 06:13:18 +00001669 if (list != NULL && listcount (list) != 0)
1670 {
1671 rinfo = listgetdata (listhead (list));
1672 if (rinfo != NULL
1673 && rinfo->type == type
1674 && rinfo->sub_type == sub_type
1675 && rinfo->ifindex == ifindex)
1676 {
1677 /* Perform poisoned reverse. */
1678 rinfo->metric = RIP_METRIC_INFINITY;
1679 RIP_TIMER_ON (rinfo->t_garbage_collect,
1680 rip_garbage_collect, rip->garbage_time);
1681 RIP_TIMER_OFF (rinfo->t_timeout);
1682 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001683
Lu Fengb397cf42014-07-18 06:13:18 +00001684 if (IS_RIP_DEBUG_EVENT)
1685 zlog_debug ("Poisone %s/%d on the interface %s with an "
1686 "infinity metric [delete]",
1687 inet_ntoa(p->prefix), p->prefixlen,
1688 ifindex2ifname(ifindex));
hasso16705132003-05-25 14:49:19 +00001689
Lu Fengb397cf42014-07-18 06:13:18 +00001690 rip_event (RIP_TRIGGERED_UPDATE, 0);
1691 }
1692 }
1693 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001694 }
1695}
1696
1697/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001698static void
paul718e3742002-12-13 20:15:29 +00001699rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001700 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001701{
1702 caddr_t lim;
1703 struct rte *rte;
1704 struct prefix_ipv4 p;
1705 struct route_node *rp;
1706 struct rip_info *rinfo;
1707 struct rip_interface *ri;
1708
hasso16705132003-05-25 14:49:19 +00001709 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001710 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001711 return;
1712
hasso429a0f82004-02-22 23:42:22 +00001713 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001714 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001715 if (! ri->running)
1716 return;
paul718e3742002-12-13 20:15:29 +00001717
1718 /* When passive interface is specified, suppress responses */
1719 if (ri->passive)
1720 return;
paulc49ad8f2004-10-22 10:27:28 +00001721
paul718e3742002-12-13 20:15:29 +00001722 /* RIP peer update. */
1723 rip_peer_update (from, packet->version);
1724
1725 lim = ((caddr_t) packet) + size;
1726 rte = packet->rte;
1727
1728 /* The Request is processed entry by entry. If there are no
1729 entries, no response is given. */
1730 if (lim == (caddr_t) rte)
1731 return;
1732
1733 /* There is one special case. If there is exactly one entry in the
1734 request, and it has an address family identifier of zero and a
1735 metric of infinity (i.e., 16), then this is a request to send the
1736 entire routing table. */
1737 if (lim == ((caddr_t) (rte + 1)) &&
1738 ntohs (rte->family) == 0 &&
1739 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1740 {
1741 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001742 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001743 }
1744 else
1745 {
1746 /* Examine the list of RTEs in the Request one by one. For each
1747 entry, look up the destination in the router's routing
1748 database and, if there is a route, put that route's metric in
1749 the metric field of the RTE. If there is no explicit route
1750 to the specified destination, put infinity in the metric
1751 field. Once all the entries have been filled in, change the
1752 command from Request to Response and send the datagram back
1753 to the requestor. */
1754 p.family = AF_INET;
1755
1756 for (; ((caddr_t) rte) < lim; rte++)
1757 {
1758 p.prefix = rte->prefix;
1759 p.prefixlen = ip_masklen (rte->mask);
1760 apply_mask_ipv4 (&p);
1761
1762 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1763 if (rp)
1764 {
Lu Fengb397cf42014-07-18 06:13:18 +00001765 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001766 rte->metric = htonl (rinfo->metric);
1767 route_unlock_node (rp);
1768 }
1769 else
1770 rte->metric = htonl (RIP_METRIC_INFINITY);
1771 }
1772 packet->command = RIP_RESPONSE;
1773
paulc49ad8f2004-10-22 10:27:28 +00001774 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001775 }
1776 rip_global_queries++;
1777}
1778
1779#if RIP_RECVMSG
1780/* Set IPv6 packet info to the socket. */
1781static int
1782setsockopt_pktinfo (int sock)
1783{
1784 int ret;
1785 int val = 1;
1786
1787 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1788 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001789 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001790 return ret;
1791}
1792
1793/* Read RIP packet by recvmsg function. */
1794int
1795rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001796 ifindex_t *ifindex)
paul718e3742002-12-13 20:15:29 +00001797{
1798 int ret;
1799 struct msghdr msg;
1800 struct iovec iov;
1801 struct cmsghdr *ptr;
1802 char adata[1024];
1803
1804 msg.msg_name = (void *) from;
1805 msg.msg_namelen = sizeof (struct sockaddr_in);
1806 msg.msg_iov = &iov;
1807 msg.msg_iovlen = 1;
1808 msg.msg_control = (void *) adata;
1809 msg.msg_controllen = sizeof adata;
1810 iov.iov_base = buf;
1811 iov.iov_len = size;
1812
1813 ret = recvmsg (sock, &msg, 0);
1814 if (ret < 0)
1815 return ret;
1816
ajsb99760a2005-01-04 16:24:43 +00001817 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001818 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1819 {
1820 struct in_pktinfo *pktinfo;
1821 int i;
1822
1823 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1824 i = pktinfo->ipi_ifindex;
1825 }
1826 return ret;
1827}
1828
1829/* RIP packet read function. */
1830int
1831rip_read_new (struct thread *t)
1832{
1833 int ret;
1834 int sock;
1835 char buf[RIP_PACKET_MAXSIZ];
1836 struct sockaddr_in from;
Paul Jakma9099f9b2016-01-18 10:12:10 +00001837 ifindex_t ifindex;
paul718e3742002-12-13 20:15:29 +00001838
1839 /* Fetch socket then register myself. */
1840 sock = THREAD_FD (t);
1841 rip_event (RIP_READ, sock);
1842
1843 /* Read RIP packet. */
1844 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1845 if (ret < 0)
1846 {
ajs6099b3b2004-11-20 02:06:59 +00001847 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001848 return ret;
1849 }
1850
1851 return ret;
1852}
1853#endif /* RIP_RECVMSG */
1854
1855/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001856static int
paul718e3742002-12-13 20:15:29 +00001857rip_read (struct thread *t)
1858{
1859 int sock;
1860 int ret;
1861 int rtenum;
1862 union rip_buf rip_buf;
1863 struct rip_packet *packet;
1864 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001865 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001866 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001867 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001868 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001869 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001870 struct rip_interface *ri;
1871
1872 /* Fetch socket then register myself. */
1873 sock = THREAD_FD (t);
1874 rip->t_read = NULL;
1875
1876 /* Add myself to tne next event */
1877 rip_event (RIP_READ, sock);
1878
1879 /* RIPd manages only IPv4. */
1880 memset (&from, 0, sizeof (struct sockaddr_in));
1881 fromlen = sizeof (struct sockaddr_in);
1882
1883 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1884 (struct sockaddr *) &from, &fromlen);
1885 if (len < 0)
1886 {
ajs6099b3b2004-11-20 02:06:59 +00001887 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001888 return len;
1889 }
1890
1891 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001892 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001893 {
1894 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001895 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001896 return -1;
1897 }
1898
1899 /* Which interface is this packet comes from. */
1900 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001901
paul718e3742002-12-13 20:15:29 +00001902 /* RIP packet received */
1903 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001904 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001905 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1906 ifp ? ifp->name : "unknown");
1907
1908 /* If this packet come from unknown interface, ignore it. */
1909 if (ifp == NULL)
1910 {
ajs766a0ca2004-12-15 14:55:51 +00001911 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1912 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001913 return -1;
1914 }
1915
1916 ifc = connected_lookup_address (ifp, from.sin_addr);
1917
1918 if (ifc == NULL)
1919 {
ajs766a0ca2004-12-15 14:55:51 +00001920 zlog_info ("rip_read: cannot find connected address for packet from %s "
1921 "port %d on interface %s",
1922 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001923 return -1;
1924 }
1925
1926 /* Packet length check. */
1927 if (len < RIP_PACKET_MINSIZ)
1928 {
1929 zlog_warn ("packet size %d is smaller than minimum size %d",
1930 len, RIP_PACKET_MINSIZ);
1931 rip_peer_bad_packet (&from);
1932 return len;
1933 }
1934 if (len > RIP_PACKET_MAXSIZ)
1935 {
1936 zlog_warn ("packet size %d is larger than max size %d",
1937 len, RIP_PACKET_MAXSIZ);
1938 rip_peer_bad_packet (&from);
1939 return len;
1940 }
1941
1942 /* Packet alignment check. */
1943 if ((len - RIP_PACKET_MINSIZ) % 20)
1944 {
1945 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1946 rip_peer_bad_packet (&from);
1947 return len;
1948 }
1949
1950 /* Set RTE number. */
1951 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1952
1953 /* For easy to handle. */
1954 packet = &rip_buf.rip_packet;
1955
1956 /* RIP version check. */
1957 if (packet->version == 0)
1958 {
1959 zlog_info ("version 0 with command %d received.", packet->command);
1960 rip_peer_bad_packet (&from);
1961 return -1;
1962 }
1963
1964 /* Dump RIP packet. */
1965 if (IS_RIP_DEBUG_RECV)
1966 rip_packet_dump (packet, len, "RECV");
1967
1968 /* RIP version adjust. This code should rethink now. RFC1058 says
1969 that "Version 1 implementations are to ignore this extra data and
1970 process only the fields specified in this document.". So RIPv3
1971 packet should be treated as RIPv1 ignoring must be zero field. */
1972 if (packet->version > RIPv2)
1973 packet->version = RIPv2;
1974
1975 /* Is RIP running or is this RIP neighbor ?*/
1976 ri = ifp->info;
1977 if (! ri->running && ! rip_neighbor_lookup (&from))
1978 {
1979 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001980 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001981 rip_peer_bad_packet (&from);
1982 return -1;
1983 }
1984
Paul Jakma15a2b082006-05-04 07:36:34 +00001985 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001986 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1987 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001988 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001989 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001990 if (IS_RIP_DEBUG_PACKET)
1991 zlog_debug (" packet's v%d doesn't fit to if version spec",
1992 packet->version);
1993 rip_peer_bad_packet (&from);
1994 return -1;
paul718e3742002-12-13 20:15:29 +00001995 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001996 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1997 {
1998 if (IS_RIP_DEBUG_PACKET)
1999 zlog_debug (" packet's v%d doesn't fit to if version spec",
2000 packet->version);
2001 rip_peer_bad_packet (&from);
2002 return -1;
2003 }
2004
paul718e3742002-12-13 20:15:29 +00002005 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
2006 messages, then RIP-1 and unauthenticated RIP-2 messages will be
2007 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00002008 if ((ri->auth_type == RIP_NO_AUTH)
2009 && rtenum
paulca5e5162004-06-06 22:06:33 +00002010 && (packet->version == RIPv2)
2011 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00002012 {
2013 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002014 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00002015 packet->version);
2016 rip_peer_bad_packet (&from);
2017 return -1;
2018 }
Paul Jakma15a2b082006-05-04 07:36:34 +00002019
2020 /* RFC:
2021 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00002022 RIP-1 messages and RIP-2 messages which pass authentication
2023 testing shall be accepted; unauthenticated and failed
2024 authentication RIP-2 messages shall be discarded. For maximum
2025 security, RIP-1 messages should be ignored when authentication is
2026 in use (see section 4.1); otherwise, the routing information from
2027 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00002028 unauthenticated manner.
2029 */
2030 /* We make an exception for RIPv1 REQUEST packets, to which we'll
2031 * always reply regardless of authentication settings, because:
2032 *
2033 * - if there other authorised routers on-link, the REQUESTor can
2034 * passively obtain the routing updates anyway
2035 * - if there are no other authorised routers on-link, RIP can
2036 * easily be disabled for the link to prevent giving out information
2037 * on state of this routers RIP routing table..
2038 *
2039 * I.e. if RIPv1 has any place anymore these days, it's as a very
2040 * simple way to distribute routing information (e.g. to embedded
2041 * hosts / appliances) and the ability to give out RIPv1
2042 * routing-information freely, while still requiring RIPv2
2043 * authentication for any RESPONSEs might be vaguely useful.
2044 */
2045 if (ri->auth_type != RIP_NO_AUTH
2046 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002047 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002048 /* Discard RIPv1 messages other than REQUESTs */
2049 if (packet->command != RIP_REQUEST)
2050 {
2051 if (IS_RIP_DEBUG_PACKET)
2052 zlog_debug ("RIPv1" " dropped because authentication enabled");
2053 rip_peer_bad_packet (&from);
2054 return -1;
2055 }
2056 }
2057 else if (ri->auth_type != RIP_NO_AUTH)
2058 {
2059 const char *auth_desc;
2060
2061 if (rtenum == 0)
2062 {
2063 /* There definitely is no authentication in the packet. */
2064 if (IS_RIP_DEBUG_PACKET)
2065 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2066 rip_peer_bad_packet (&from);
2067 return -1;
2068 }
2069
2070 /* First RTE must be an Authentication Family RTE */
2071 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2072 {
2073 if (IS_RIP_DEBUG_PACKET)
2074 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002075 rip_peer_bad_packet (&from);
2076 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002077 }
2078
paul718e3742002-12-13 20:15:29 +00002079 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002080 switch (ntohs(packet->rte->tag))
2081 {
2082 case RIP_AUTH_SIMPLE_PASSWORD:
2083 auth_desc = "simple";
2084 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2085 break;
2086
2087 case RIP_AUTH_MD5:
2088 auth_desc = "MD5";
2089 ret = rip_auth_md5 (packet, &from, len, ifp);
2090 /* Reset RIP packet length to trim MD5 data. */
2091 len = ret;
2092 break;
2093
2094 default:
2095 ret = 0;
2096 auth_desc = "unknown type";
2097 if (IS_RIP_DEBUG_PACKET)
2098 zlog_debug ("RIPv2 Unknown authentication type %d",
2099 ntohs (packet->rte->tag));
2100 }
2101
2102 if (ret)
2103 {
2104 if (IS_RIP_DEBUG_PACKET)
2105 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2106 }
2107 else
2108 {
2109 if (IS_RIP_DEBUG_PACKET)
2110 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2111 rip_peer_bad_packet (&from);
2112 return -1;
2113 }
paul718e3742002-12-13 20:15:29 +00002114 }
2115
2116 /* Process each command. */
2117 switch (packet->command)
2118 {
2119 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002120 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002121 break;
2122 case RIP_REQUEST:
2123 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002124 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002125 break;
2126 case RIP_TRACEON:
2127 case RIP_TRACEOFF:
2128 zlog_info ("Obsolete command %s received, please sent it to routed",
2129 lookup (rip_msg, packet->command));
2130 rip_peer_bad_packet (&from);
2131 break;
2132 case RIP_POLL_ENTRY:
2133 zlog_info ("Obsolete command %s received",
2134 lookup (rip_msg, packet->command));
2135 rip_peer_bad_packet (&from);
2136 break;
2137 default:
2138 zlog_info ("Unknown RIP command %d received", packet->command);
2139 rip_peer_bad_packet (&from);
2140 break;
2141 }
2142
2143 return len;
2144}
2145
paul718e3742002-12-13 20:15:29 +00002146/* Write routing table entry to the stream and return next index of
2147 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002148static int
paul718e3742002-12-13 20:15:29 +00002149rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002150 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002151{
2152 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002153
2154 /* Write routing table entry. */
2155 if (version == RIPv1)
2156 {
2157 stream_putw (s, AF_INET);
2158 stream_putw (s, 0);
2159 stream_put_ipv4 (s, p->prefix.s_addr);
2160 stream_put_ipv4 (s, 0);
2161 stream_put_ipv4 (s, 0);
2162 stream_putl (s, rinfo->metric_out);
2163 }
2164 else
2165 {
2166 masklen2ip (p->prefixlen, &mask);
2167
2168 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002169 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002170 stream_put_ipv4 (s, p->prefix.s_addr);
2171 stream_put_ipv4 (s, mask.s_addr);
2172 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2173 stream_putl (s, rinfo->metric_out);
2174 }
2175
2176 return ++num;
2177}
2178
2179/* Send update to the ifp or spcified neighbor. */
2180void
paulc49ad8f2004-10-22 10:27:28 +00002181rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2182 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002183{
2184 int ret;
2185 struct stream *s;
2186 struct route_node *rp;
2187 struct rip_info *rinfo;
2188 struct rip_interface *ri;
2189 struct prefix_ipv4 *p;
2190 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002191 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002192 struct key *key = NULL;
2193 /* this might need to made dynamic if RIP ever supported auth methods
2194 with larger key string sizes */
2195 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002196 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002197 int num = 0;
paul718e3742002-12-13 20:15:29 +00002198 int rtemax;
paul01d09082003-06-08 21:22:18 +00002199 int subnetted = 0;
Lu Fengb397cf42014-07-18 06:13:18 +00002200 struct list *list = NULL;
2201 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002202
2203 /* Logging output event. */
2204 if (IS_RIP_DEBUG_EVENT)
2205 {
2206 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002207 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002208 else
ajs5d6c3772004-12-08 19:24:06 +00002209 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002210 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002211 }
2212
2213 /* Set output stream. */
2214 s = rip->obuf;
2215
2216 /* Reset stream and RTE counter. */
2217 stream_reset (s);
Lu Feng342a31b2014-06-25 07:43:15 +00002218 rtemax = RIP_MAX_RTE;
paul718e3742002-12-13 20:15:29 +00002219
2220 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002221 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002222
2223 /* If output interface is in simple password authentication mode, we
2224 need space for authentication data. */
2225 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2226 rtemax -= 1;
2227
2228 /* If output interface is in MD5 authentication mode, we need space
2229 for authentication header and data. */
2230 if (ri->auth_type == RIP_AUTH_MD5)
2231 rtemax -= 2;
2232
2233 /* If output interface is in simple password authentication mode
2234 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002235 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002236 {
2237 if (ri->key_chain)
2238 {
2239 struct keychain *keychain;
2240
2241 keychain = keychain_lookup (ri->key_chain);
2242 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002243 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002244 }
paulb14ee002005-02-04 23:42:41 +00002245 /* to be passed to auth functions later */
2246 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002247 }
2248
paul727d1042002-12-13 20:50:29 +00002249 if (version == RIPv1)
2250 {
paulc49ad8f2004-10-22 10:27:28 +00002251 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002252 apply_classful_mask_ipv4 (&ifaddrclass);
2253 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002254 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002255 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002256 }
2257
paul718e3742002-12-13 20:15:29 +00002258 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002259 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00002260 {
Lu Fengb397cf42014-07-18 06:13:18 +00002261 rinfo = listgetdata (listhead (list));
paul727d1042002-12-13 20:50:29 +00002262 /* For RIPv1, if we are subnetted, output subnets in our network */
2263 /* that have the same mask as the output "interface". For other */
2264 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002265
2266 if (version == RIPv1)
2267 {
paul727d1042002-12-13 20:50:29 +00002268 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002269
2270 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002271 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002272 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002273
paul727d1042002-12-13 20:50:29 +00002274 if (subnetted &&
2275 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2276 {
paulc49ad8f2004-10-22 10:27:28 +00002277 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002278 (rp->p.prefixlen != 32))
2279 continue;
2280 }
2281 else
2282 {
2283 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2284 apply_classful_mask_ipv4(&classfull);
2285 if (rp->p.u.prefix4.s_addr != 0 &&
2286 classfull.prefixlen != rp->p.prefixlen)
2287 continue;
2288 }
paul718e3742002-12-13 20:15:29 +00002289 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002290 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002291 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002292 }
2293 else
2294 p = (struct prefix_ipv4 *) &rp->p;
2295
2296 /* Apply output filters. */
2297 ret = rip_outgoing_filter (p, ri);
2298 if (ret < 0)
2299 continue;
2300
2301 /* Changed route only output. */
2302 if (route_type == rip_changed_route &&
2303 (! (rinfo->flags & RIP_RTF_CHANGED)))
2304 continue;
2305
2306 /* Split horizon. */
2307 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002308 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002309 {
paul42d14d92003-11-17 09:15:18 +00002310 /*
2311 * We perform split horizon for RIP and connected route.
2312 * For rip routes, we want to suppress the route if we would
2313 * end up sending the route back on the interface that we
2314 * learned it from, with a higher metric. For connected routes,
2315 * we suppress the route if the prefix is a subset of the
2316 * source address that we are going to use for the packet
2317 * (in order to handle the case when multiple subnets are
2318 * configured on the same interface).
2319 */
Lu Fengb397cf42014-07-18 06:13:18 +00002320 int suppress = 0;
2321 struct rip_info *tmp_rinfo = NULL;
2322
2323 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2324 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2325 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2326 {
2327 suppress = 1;
2328 break;
2329 }
2330
2331 if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002332 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002333 suppress = 1;
2334
2335 if (suppress)
paul718e3742002-12-13 20:15:29 +00002336 continue;
2337 }
2338
2339 /* Preparation for route-map. */
2340 rinfo->metric_set = 0;
2341 rinfo->nexthop_out.s_addr = 0;
2342 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002343 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002344 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002345
hasso16705132003-05-25 14:49:19 +00002346 /* In order to avoid some local loops,
2347 * if the RIP route has a nexthop via this interface, keep the nexthop,
2348 * otherwise set it to 0. The nexthop should not be propagated
2349 * beyond the local broadcast/multicast area in order
2350 * to avoid an IGP multi-level recursive look-up.
2351 * see (4.4)
2352 */
paulc49ad8f2004-10-22 10:27:28 +00002353 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002354 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002355
2356 /* Interface route-map */
2357 if (ri->routemap[RIP_FILTER_OUT])
2358 {
2359 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2360 (struct prefix *) p, RMAP_RIP,
2361 rinfo);
2362
2363 if (ret == RMAP_DENYMATCH)
2364 {
2365 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002366 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002367 inet_ntoa (p->prefix), p->prefixlen);
2368 continue;
2369 }
2370 }
paul718e3742002-12-13 20:15:29 +00002371
hasso16705132003-05-25 14:49:19 +00002372 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002373 if (rip->route_map[rinfo->type].name
2374 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2375 {
2376 ret = route_map_apply (rip->route_map[rinfo->type].map,
2377 (struct prefix *)p, RMAP_RIP, rinfo);
2378
2379 if (ret == RMAP_DENYMATCH)
2380 {
2381 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002382 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002383 inet_ntoa (p->prefix), p->prefixlen);
2384 continue;
2385 }
2386 }
2387
2388 /* When route-map does not set metric. */
2389 if (! rinfo->metric_set)
2390 {
2391 /* If redistribute metric is set. */
2392 if (rip->route_map[rinfo->type].metric_config
2393 && rinfo->metric != RIP_METRIC_INFINITY)
2394 {
2395 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2396 }
2397 else
2398 {
2399 /* If the route is not connected or localy generated
2400 one, use default-metric value*/
2401 if (rinfo->type != ZEBRA_ROUTE_RIP
2402 && rinfo->type != ZEBRA_ROUTE_CONNECT
2403 && rinfo->metric != RIP_METRIC_INFINITY)
2404 rinfo->metric_out = rip->default_metric;
2405 }
2406 }
2407
2408 /* Apply offset-list */
2409 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002410 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002411
2412 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2413 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002414
2415 /* Perform split-horizon with poisoned reverse
2416 * for RIP and connected routes.
2417 **/
2418 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002419 /*
2420 * We perform split horizon for RIP and connected route.
2421 * For rip routes, we want to suppress the route if we would
2422 * end up sending the route back on the interface that we
2423 * learned it from, with a higher metric. For connected routes,
2424 * we suppress the route if the prefix is a subset of the
2425 * source address that we are going to use for the packet
2426 * (in order to handle the case when multiple subnets are
2427 * configured on the same interface).
2428 */
Lu Fengb397cf42014-07-18 06:13:18 +00002429 struct rip_info *tmp_rinfo = NULL;
2430
2431 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2432 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2433 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2434 rinfo->metric_out = RIP_METRIC_INFINITY;
2435 if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002436 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002437 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002438 }
paulb14ee002005-02-04 23:42:41 +00002439
2440 /* Prepare preamble, auth headers, if needs be */
2441 if (num == 0)
2442 {
2443 stream_putc (s, RIP_RESPONSE);
2444 stream_putc (s, version);
2445 stream_putw (s, 0);
2446
paul0cb8a012005-05-29 11:27:24 +00002447 /* auth header for !v1 && !no_auth */
2448 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002449 doff = rip_auth_header_write (s, ri, key, auth_str,
2450 RIP_AUTH_SIMPLE_SIZE);
2451 }
2452
paul718e3742002-12-13 20:15:29 +00002453 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002454 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002455 if (num == rtemax)
2456 {
2457 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002458 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002459
2460 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002461 to, ifc);
paul718e3742002-12-13 20:15:29 +00002462
2463 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2464 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2465 stream_get_endp(s), "SEND");
2466 num = 0;
2467 stream_reset (s);
2468 }
2469 }
2470
2471 /* Flush unwritten RTE. */
2472 if (num != 0)
2473 {
2474 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002475 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002476
paulc49ad8f2004-10-22 10:27:28 +00002477 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002478
2479 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2480 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2481 stream_get_endp (s), "SEND");
2482 num = 0;
2483 stream_reset (s);
2484 }
2485
2486 /* Statistics updates. */
2487 ri->sent_updates++;
2488}
2489
2490/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002491static void
paulc49ad8f2004-10-22 10:27:28 +00002492rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002493{
paul718e3742002-12-13 20:15:29 +00002494 struct sockaddr_in to;
2495
2496 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002497 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002498 {
2499 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002500 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002501
paulc49ad8f2004-10-22 10:27:28 +00002502 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002503 return;
2504 }
paulc49ad8f2004-10-22 10:27:28 +00002505
paul718e3742002-12-13 20:15:29 +00002506 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002507 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002508 {
paulc49ad8f2004-10-22 10:27:28 +00002509 if (ifc->address->family == AF_INET)
2510 {
2511 /* Destination address and port setting. */
2512 memset (&to, 0, sizeof (struct sockaddr_in));
2513 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002514 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002515 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002516 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002517 /* calculate the appropriate broadcast address */
2518 to.sin_addr.s_addr =
2519 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2520 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002521 else
2522 /* do not know where to send the packet */
2523 return;
paulc49ad8f2004-10-22 10:27:28 +00002524 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002525
paulc49ad8f2004-10-22 10:27:28 +00002526 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002527 zlog_debug("%s announce to %s on %s",
2528 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2529 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002530
paulc49ad8f2004-10-22 10:27:28 +00002531 rip_output_process (ifc, &to, route_type, version);
2532 }
paul718e3742002-12-13 20:15:29 +00002533 }
2534}
2535
2536/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002537static void
paul718e3742002-12-13 20:15:29 +00002538rip_update_process (int route_type)
2539{
paul1eb8ef22005-04-07 07:30:20 +00002540 struct listnode *node;
2541 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002542 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002543 struct interface *ifp;
2544 struct rip_interface *ri;
2545 struct route_node *rp;
2546 struct sockaddr_in to;
2547 struct prefix_ipv4 *p;
2548
2549 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002550 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002551 {
paul718e3742002-12-13 20:15:29 +00002552 if (if_is_loopback (ifp))
2553 continue;
2554
paul2e3b2e42002-12-13 21:03:13 +00002555 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002556 continue;
2557
2558 /* Fetch RIP interface information. */
2559 ri = ifp->info;
2560
2561 /* When passive interface is specified, suppress announce to the
2562 interface. */
2563 if (ri->passive)
2564 continue;
2565
2566 if (ri->running)
2567 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002568 /*
2569 * If there is no version configuration in the interface,
2570 * use rip's version setting.
2571 */
2572 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2573 rip->version_send : ri->ri_send);
2574
paul718e3742002-12-13 20:15:29 +00002575 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002576 zlog_debug("SEND UPDATE to %s ifindex %d",
Christian Franke1ca8d402015-11-10 17:45:03 +01002577 ifp->name, ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002578
paulcc1131a2003-10-15 23:20:17 +00002579 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002580 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002581 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002582 if (connected->address->family == AF_INET)
2583 {
2584 if (vsend & RIPv1)
2585 rip_update_interface (connected, RIPv1, route_type);
2586 if ((vsend & RIPv2) && if_is_multicast(ifp))
2587 rip_update_interface (connected, RIPv2, route_type);
2588 }
2589 }
paul718e3742002-12-13 20:15:29 +00002590 }
2591 }
2592
2593 /* RIP send updates to each neighbor. */
2594 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2595 if (rp->info != NULL)
2596 {
2597 p = (struct prefix_ipv4 *) &rp->p;
2598
2599 ifp = if_lookup_address (p->prefix);
2600 if (! ifp)
2601 {
paulc49ad8f2004-10-22 10:27:28 +00002602 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002603 inet_ntoa (p->prefix));
2604 continue;
2605 }
paulc49ad8f2004-10-22 10:27:28 +00002606
2607 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2608 {
2609 zlog_warn ("Neighbor %s doesnt have connected network",
2610 inet_ntoa (p->prefix));
2611 continue;
2612 }
2613
paul718e3742002-12-13 20:15:29 +00002614 /* Set destination address and port */
2615 memset (&to, 0, sizeof (struct sockaddr_in));
2616 to.sin_addr = p->prefix;
2617 to.sin_port = htons (RIP_PORT_DEFAULT);
2618
2619 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002620 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002621 }
2622}
2623
2624/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002625static int
paul718e3742002-12-13 20:15:29 +00002626rip_update (struct thread *t)
2627{
2628 /* Clear timer pointer. */
2629 rip->t_update = NULL;
2630
2631 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002632 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002633
2634 /* Process update output. */
2635 rip_update_process (rip_all_route);
2636
2637 /* Triggered updates may be suppressed if a regular update is due by
2638 the time the triggered update would be sent. */
2639 if (rip->t_triggered_interval)
2640 {
2641 thread_cancel (rip->t_triggered_interval);
2642 rip->t_triggered_interval = NULL;
2643 }
2644 rip->trigger = 0;
2645
2646 /* Register myself. */
2647 rip_event (RIP_UPDATE_EVENT, 0);
2648
2649 return 0;
2650}
2651
2652/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002653static void
paul216565a2005-10-25 23:35:28 +00002654rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002655{
2656 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002657 struct rip_info *rinfo = NULL;
2658 struct list *list = NULL;
2659 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002660
2661 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002662 if ((list = rp->info) != NULL)
2663 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2664 {
2665 UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
2666 /* This flag can be set only on the first entry. */
2667 break;
2668 }
paul718e3742002-12-13 20:15:29 +00002669}
2670
2671/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002672static int
paul718e3742002-12-13 20:15:29 +00002673rip_triggered_interval (struct thread *t)
2674{
2675 int rip_triggered_update (struct thread *);
2676
2677 rip->t_triggered_interval = NULL;
2678
2679 if (rip->trigger)
2680 {
2681 rip->trigger = 0;
2682 rip_triggered_update (t);
2683 }
2684 return 0;
2685}
2686
2687/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002688static int
paul718e3742002-12-13 20:15:29 +00002689rip_triggered_update (struct thread *t)
2690{
2691 int interval;
2692
2693 /* Clear thred pointer. */
2694 rip->t_triggered_update = NULL;
2695
2696 /* Cancel interval timer. */
2697 if (rip->t_triggered_interval)
2698 {
2699 thread_cancel (rip->t_triggered_interval);
2700 rip->t_triggered_interval = NULL;
2701 }
2702 rip->trigger = 0;
2703
2704 /* Logging triggered update. */
2705 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002706 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002707
2708 /* Split Horizon processing is done when generating triggered
2709 updates as well as normal updates (see section 2.6). */
2710 rip_update_process (rip_changed_route);
2711
2712 /* Once all of the triggered updates have been generated, the route
2713 change flags should be cleared. */
2714 rip_clear_changed_flag ();
2715
2716 /* After a triggered update is sent, a timer should be set for a
2717 random interval between 1 and 5 seconds. If other changes that
2718 would trigger updates occur before the timer expires, a single
2719 update is triggered when the timer expires. */
2720 interval = (random () % 5) + 1;
2721
2722 rip->t_triggered_interval =
2723 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2724
2725 return 0;
2726}
2727
2728/* Withdraw redistributed route. */
2729void
2730rip_redistribute_withdraw (int type)
2731{
2732 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002733 struct rip_info *rinfo = NULL;
2734 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00002735
2736 if (!rip)
2737 return;
2738
2739 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002740 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00002741 {
Lu Fengb397cf42014-07-18 06:13:18 +00002742 rinfo = listgetdata (listhead (list));
paul718e3742002-12-13 20:15:29 +00002743 if (rinfo->type == type
2744 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2745 {
2746 /* Perform poisoned reverse. */
2747 rinfo->metric = RIP_METRIC_INFINITY;
2748 RIP_TIMER_ON (rinfo->t_garbage_collect,
2749 rip_garbage_collect, rip->garbage_time);
2750 RIP_TIMER_OFF (rinfo->t_timeout);
2751 rinfo->flags |= RIP_RTF_CHANGED;
2752
hasso16705132003-05-25 14:49:19 +00002753 if (IS_RIP_DEBUG_EVENT) {
2754 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2755
ajs5d6c3772004-12-08 19:24:06 +00002756 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002757 inet_ntoa(p->prefix), p->prefixlen,
2758 ifindex2ifname(rinfo->ifindex));
2759 }
2760
paul718e3742002-12-13 20:15:29 +00002761 rip_event (RIP_TRIGGERED_UPDATE, 0);
2762 }
2763 }
2764}
2765
2766/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002767static int
2768rip_create (void)
paul718e3742002-12-13 20:15:29 +00002769{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002770 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002771
2772 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002773 rip->version_send = RI_RIP_VERSION_2;
2774 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002775 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2776 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2777 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2778 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2779
2780 /* Initialize RIP routig table. */
2781 rip->table = route_table_init ();
2782 rip->route = route_table_init ();
2783 rip->neighbor = route_table_init ();
2784
2785 /* Make output stream. */
2786 rip->obuf = stream_new (1500);
2787
2788 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002789 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002790 if (rip->sock < 0)
2791 return rip->sock;
2792
2793 /* Create read and timer thread. */
2794 rip_event (RIP_READ, rip->sock);
2795 rip_event (RIP_UPDATE_EVENT, 1);
2796
2797 return 0;
2798}
2799
2800/* Sned RIP request to the destination. */
2801int
2802rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002803 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002804{
2805 struct rte *rte;
2806 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002807 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002808
2809 memset (&rip_packet, 0, sizeof (rip_packet));
2810
2811 rip_packet.command = RIP_REQUEST;
2812 rip_packet.version = version;
2813 rte = rip_packet.rte;
2814 rte->metric = htonl (RIP_METRIC_INFINITY);
2815
paul931cd542004-01-23 15:31:42 +00002816 if (connected)
2817 {
2818 /*
2819 * connected is only sent for ripv1 case, or when
2820 * interface does not support multicast. Caller loops
2821 * over each connected address for this case.
2822 */
paul11dde9c2004-05-31 14:00:00 +00002823 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002824 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002825 return -1;
2826 else
2827 return sizeof (rip_packet);
2828 }
2829
paulcc1131a2003-10-15 23:20:17 +00002830 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002831 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002832 {
2833 struct prefix_ipv4 *p;
2834
2835 p = (struct prefix_ipv4 *) connected->address;
2836
2837 if (p->family != AF_INET)
2838 continue;
2839
paul11dde9c2004-05-31 14:00:00 +00002840 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002841 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002842 return -1;
2843 }
2844 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002845}
David Lamparter6b0655a2014-06-04 06:53:35 +02002846
pauldc63bfd2005-10-25 23:31:05 +00002847static int
paul718e3742002-12-13 20:15:29 +00002848rip_update_jitter (unsigned long time)
2849{
paul239389b2004-05-05 14:09:37 +00002850#define JITTER_BOUND 4
2851 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2852 Given that, we cannot let time be less than JITTER_BOUND seconds.
2853 The RIPv2 RFC says jitter should be small compared to
2854 update_time. We consider 1/JITTER_BOUND to be small.
2855 */
2856
2857 int jitter_input = time;
2858 int jitter;
2859
2860 if (jitter_input < JITTER_BOUND)
2861 jitter_input = JITTER_BOUND;
2862
Donald Sharpf31bab42015-06-19 19:26:19 -04002863 jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input));
paul239389b2004-05-05 14:09:37 +00002864
2865 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002866}
2867
2868void
2869rip_event (enum rip_event event, int sock)
2870{
2871 int jitter = 0;
2872
2873 switch (event)
2874 {
2875 case RIP_READ:
2876 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2877 break;
2878 case RIP_UPDATE_EVENT:
2879 if (rip->t_update)
2880 {
2881 thread_cancel (rip->t_update);
2882 rip->t_update = NULL;
2883 }
2884 jitter = rip_update_jitter (rip->update_time);
2885 rip->t_update =
2886 thread_add_timer (master, rip_update, NULL,
2887 sock ? 2 : rip->update_time + jitter);
2888 break;
2889 case RIP_TRIGGERED_UPDATE:
2890 if (rip->t_triggered_interval)
2891 rip->trigger = 1;
2892 else if (! rip->t_triggered_update)
2893 rip->t_triggered_update =
2894 thread_add_event (master, rip_triggered_update, NULL, 0);
2895 break;
2896 default:
2897 break;
2898 }
2899}
David Lamparter6b0655a2014-06-04 06:53:35 +02002900
paul718e3742002-12-13 20:15:29 +00002901DEFUN (router_rip,
2902 router_rip_cmd,
2903 "router rip",
2904 "Enable a routing process\n"
2905 "Routing Information Protocol (RIP)\n")
2906{
2907 int ret;
2908
2909 /* If rip is not enabled before. */
2910 if (! rip)
2911 {
2912 ret = rip_create ();
2913 if (ret < 0)
2914 {
2915 zlog_info ("Can't create RIP");
2916 return CMD_WARNING;
2917 }
2918 }
2919 vty->node = RIP_NODE;
2920 vty->index = rip;
2921
2922 return CMD_SUCCESS;
2923}
2924
2925DEFUN (no_router_rip,
2926 no_router_rip_cmd,
2927 "no router rip",
2928 NO_STR
2929 "Enable a routing process\n"
2930 "Routing Information Protocol (RIP)\n")
2931{
2932 if (rip)
2933 rip_clean ();
2934 return CMD_SUCCESS;
2935}
2936
2937DEFUN (rip_version,
2938 rip_version_cmd,
2939 "version <1-2>",
2940 "Set routing protocol version\n"
2941 "version\n")
2942{
2943 int version;
2944
2945 version = atoi (argv[0]);
2946 if (version != RIPv1 && version != RIPv2)
2947 {
2948 vty_out (vty, "invalid rip version %d%s", version,
2949 VTY_NEWLINE);
2950 return CMD_WARNING;
2951 }
paulf38a4712003-06-07 01:10:00 +00002952 rip->version_send = version;
2953 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002954
2955 return CMD_SUCCESS;
2956}
2957
2958DEFUN (no_rip_version,
2959 no_rip_version_cmd,
2960 "no version",
2961 NO_STR
2962 "Set routing protocol version\n")
2963{
2964 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002965 rip->version_send = RI_RIP_VERSION_2;
2966 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002967
2968 return CMD_SUCCESS;
2969}
2970
2971ALIAS (no_rip_version,
2972 no_rip_version_val_cmd,
2973 "no version <1-2>",
2974 NO_STR
2975 "Set routing protocol version\n"
2976 "version\n")
2977
2978DEFUN (rip_route,
2979 rip_route_cmd,
2980 "route A.B.C.D/M",
2981 "RIP static route configuration\n"
2982 "IP prefix <network>/<length>\n")
2983{
2984 int ret;
2985 struct prefix_ipv4 p;
2986 struct route_node *node;
2987
2988 ret = str2prefix_ipv4 (argv[0], &p);
2989 if (ret < 0)
2990 {
2991 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2992 return CMD_WARNING;
2993 }
2994 apply_mask_ipv4 (&p);
2995
2996 /* For router rip configuration. */
2997 node = route_node_get (rip->route, (struct prefix *) &p);
2998
2999 if (node->info)
3000 {
3001 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
3002 route_unlock_node (node);
3003 return CMD_WARNING;
3004 }
3005
hasso8a676be2004-10-08 06:36:38 +00003006 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00003007
vincentfbf5d032005-09-29 11:25:50 +00003008 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00003009
3010 return CMD_SUCCESS;
3011}
3012
3013DEFUN (no_rip_route,
3014 no_rip_route_cmd,
3015 "no route A.B.C.D/M",
3016 NO_STR
3017 "RIP static route configuration\n"
3018 "IP prefix <network>/<length>\n")
3019{
3020 int ret;
3021 struct prefix_ipv4 p;
3022 struct route_node *node;
3023
3024 ret = str2prefix_ipv4 (argv[0], &p);
3025 if (ret < 0)
3026 {
3027 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
3028 return CMD_WARNING;
3029 }
3030 apply_mask_ipv4 (&p);
3031
3032 /* For router rip configuration. */
3033 node = route_node_lookup (rip->route, (struct prefix *) &p);
3034 if (! node)
3035 {
3036 vty_out (vty, "Can't find route %s.%s", argv[0],
3037 VTY_NEWLINE);
3038 return CMD_WARNING;
3039 }
3040
3041 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
3042 route_unlock_node (node);
3043
3044 node->info = NULL;
3045 route_unlock_node (node);
3046
3047 return CMD_SUCCESS;
3048}
3049
Stephen Hemminger2c239702009-12-10 19:16:05 +03003050#if 0
pauldc63bfd2005-10-25 23:31:05 +00003051static void
paul216565a2005-10-25 23:35:28 +00003052rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00003053{
3054 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003055 struct rip_info *rinfo = NULL;
3056 struct list *list = NULL;
3057 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003058
3059 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003060 if ((list = np->info) != NULL)
3061 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3062 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
3063 rinfo->metric = rip->default_metric;
paul718e3742002-12-13 20:15:29 +00003064}
Stephen Hemminger2c239702009-12-10 19:16:05 +03003065#endif
paul718e3742002-12-13 20:15:29 +00003066
3067DEFUN (rip_default_metric,
3068 rip_default_metric_cmd,
3069 "default-metric <1-16>",
3070 "Set a metric of redistribute routes\n"
3071 "Default metric\n")
3072{
3073 if (rip)
3074 {
3075 rip->default_metric = atoi (argv[0]);
3076 /* rip_update_default_metric (); */
3077 }
3078 return CMD_SUCCESS;
3079}
3080
3081DEFUN (no_rip_default_metric,
3082 no_rip_default_metric_cmd,
3083 "no default-metric",
3084 NO_STR
3085 "Set a metric of redistribute routes\n"
3086 "Default metric\n")
3087{
3088 if (rip)
3089 {
3090 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3091 /* rip_update_default_metric (); */
3092 }
3093 return CMD_SUCCESS;
3094}
3095
3096ALIAS (no_rip_default_metric,
3097 no_rip_default_metric_val_cmd,
3098 "no default-metric <1-16>",
3099 NO_STR
3100 "Set a metric of redistribute routes\n"
3101 "Default metric\n")
3102
3103DEFUN (rip_timers,
3104 rip_timers_cmd,
3105 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3106 "Adjust routing timers\n"
3107 "Basic routing protocol update timers\n"
3108 "Routing table update timer value in second. Default is 30.\n"
3109 "Routing information timeout timer. Default is 180.\n"
3110 "Garbage collection timer. Default is 120.\n")
3111{
3112 unsigned long update;
3113 unsigned long timeout;
3114 unsigned long garbage;
3115 char *endptr = NULL;
3116 unsigned long RIP_TIMER_MAX = 2147483647;
3117 unsigned long RIP_TIMER_MIN = 5;
3118
3119 update = strtoul (argv[0], &endptr, 10);
3120 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3121 {
3122 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3123 return CMD_WARNING;
3124 }
3125
3126 timeout = strtoul (argv[1], &endptr, 10);
3127 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3128 {
3129 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3130 return CMD_WARNING;
3131 }
3132
3133 garbage = strtoul (argv[2], &endptr, 10);
3134 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3135 {
3136 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3137 return CMD_WARNING;
3138 }
3139
3140 /* Set each timer value. */
3141 rip->update_time = update;
3142 rip->timeout_time = timeout;
3143 rip->garbage_time = garbage;
3144
3145 /* Reset update timer thread. */
3146 rip_event (RIP_UPDATE_EVENT, 0);
3147
3148 return CMD_SUCCESS;
3149}
3150
3151DEFUN (no_rip_timers,
3152 no_rip_timers_cmd,
3153 "no timers basic",
3154 NO_STR
3155 "Adjust routing timers\n"
3156 "Basic routing protocol update timers\n")
3157{
3158 /* Set each timer value to the default. */
3159 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3160 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3161 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3162
3163 /* Reset update timer thread. */
3164 rip_event (RIP_UPDATE_EVENT, 0);
3165
3166 return CMD_SUCCESS;
3167}
hasso16705132003-05-25 14:49:19 +00003168
3169ALIAS (no_rip_timers,
3170 no_rip_timers_val_cmd,
3171 "no timers basic <0-65535> <0-65535> <0-65535>",
3172 NO_STR
3173 "Adjust routing timers\n"
3174 "Basic routing protocol update timers\n"
3175 "Routing table update timer value in second. Default is 30.\n"
3176 "Routing information timeout timer. Default is 180.\n"
3177 "Garbage collection timer. Default is 120.\n")
3178
David Lamparter6b0655a2014-06-04 06:53:35 +02003179
paul718e3742002-12-13 20:15:29 +00003180struct route_table *rip_distance_table;
3181
3182struct rip_distance
3183{
3184 /* Distance value for the IP source prefix. */
3185 u_char distance;
3186
3187 /* Name of the access-list to be matched. */
3188 char *access_list;
3189};
3190
pauldc63bfd2005-10-25 23:31:05 +00003191static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003192rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003193{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003194 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003195}
3196
pauldc63bfd2005-10-25 23:31:05 +00003197static void
paul718e3742002-12-13 20:15:29 +00003198rip_distance_free (struct rip_distance *rdistance)
3199{
3200 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3201}
3202
pauldc63bfd2005-10-25 23:31:05 +00003203static int
hasso98b718a2004-10-11 12:57:57 +00003204rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3205 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003206{
3207 int ret;
3208 struct prefix_ipv4 p;
3209 u_char distance;
3210 struct route_node *rn;
3211 struct rip_distance *rdistance;
3212
3213 ret = str2prefix_ipv4 (ip_str, &p);
3214 if (ret == 0)
3215 {
3216 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3217 return CMD_WARNING;
3218 }
3219
3220 distance = atoi (distance_str);
3221
3222 /* Get RIP distance node. */
3223 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3224 if (rn->info)
3225 {
3226 rdistance = rn->info;
3227 route_unlock_node (rn);
3228 }
3229 else
3230 {
3231 rdistance = rip_distance_new ();
3232 rn->info = rdistance;
3233 }
3234
3235 /* Set distance value. */
3236 rdistance->distance = distance;
3237
3238 /* Reset access-list configuration. */
3239 if (rdistance->access_list)
3240 {
3241 free (rdistance->access_list);
3242 rdistance->access_list = NULL;
3243 }
3244 if (access_list_str)
3245 rdistance->access_list = strdup (access_list_str);
3246
3247 return CMD_SUCCESS;
3248}
3249
pauldc63bfd2005-10-25 23:31:05 +00003250static int
hasso98b718a2004-10-11 12:57:57 +00003251rip_distance_unset (struct vty *vty, const char *distance_str,
3252 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003253{
3254 int ret;
3255 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +00003256 struct route_node *rn;
3257 struct rip_distance *rdistance;
3258
3259 ret = str2prefix_ipv4 (ip_str, &p);
3260 if (ret == 0)
3261 {
3262 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3263 return CMD_WARNING;
3264 }
3265
paul718e3742002-12-13 20:15:29 +00003266 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3267 if (! rn)
3268 {
3269 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3270 return CMD_WARNING;
3271 }
3272
3273 rdistance = rn->info;
3274
3275 if (rdistance->access_list)
3276 free (rdistance->access_list);
3277 rip_distance_free (rdistance);
3278
3279 rn->info = NULL;
3280 route_unlock_node (rn);
3281 route_unlock_node (rn);
3282
3283 return CMD_SUCCESS;
3284}
3285
pauldc63bfd2005-10-25 23:31:05 +00003286static void
paul216565a2005-10-25 23:35:28 +00003287rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003288{
3289 struct route_node *rn;
3290 struct rip_distance *rdistance;
3291
3292 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3293 if ((rdistance = rn->info) != NULL)
3294 {
3295 if (rdistance->access_list)
3296 free (rdistance->access_list);
3297 rip_distance_free (rdistance);
3298 rn->info = NULL;
3299 route_unlock_node (rn);
3300 }
3301}
3302
3303/* Apply RIP information to distance method. */
3304u_char
3305rip_distance_apply (struct rip_info *rinfo)
3306{
3307 struct route_node *rn;
3308 struct prefix_ipv4 p;
3309 struct rip_distance *rdistance;
3310 struct access_list *alist;
3311
3312 if (! rip)
3313 return 0;
3314
3315 memset (&p, 0, sizeof (struct prefix_ipv4));
3316 p.family = AF_INET;
3317 p.prefix = rinfo->from;
3318 p.prefixlen = IPV4_MAX_BITLEN;
3319
3320 /* Check source address. */
3321 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3322 if (rn)
3323 {
3324 rdistance = rn->info;
3325 route_unlock_node (rn);
3326
3327 if (rdistance->access_list)
3328 {
3329 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3330 if (alist == NULL)
3331 return 0;
3332 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3333 return 0;
3334
3335 return rdistance->distance;
3336 }
3337 else
3338 return rdistance->distance;
3339 }
3340
3341 if (rip->distance)
3342 return rip->distance;
3343
3344 return 0;
3345}
3346
pauldc63bfd2005-10-25 23:31:05 +00003347static void
paul718e3742002-12-13 20:15:29 +00003348rip_distance_show (struct vty *vty)
3349{
3350 struct route_node *rn;
3351 struct rip_distance *rdistance;
3352 int header = 1;
3353 char buf[BUFSIZ];
3354
3355 vty_out (vty, " Distance: (default is %d)%s",
3356 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3357 VTY_NEWLINE);
3358
3359 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3360 if ((rdistance = rn->info) != NULL)
3361 {
3362 if (header)
3363 {
3364 vty_out (vty, " Address Distance List%s",
3365 VTY_NEWLINE);
3366 header = 0;
3367 }
3368 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3369 vty_out (vty, " %-20s %4d %s%s",
3370 buf, rdistance->distance,
3371 rdistance->access_list ? rdistance->access_list : "",
3372 VTY_NEWLINE);
3373 }
3374}
3375
3376DEFUN (rip_distance,
3377 rip_distance_cmd,
3378 "distance <1-255>",
3379 "Administrative distance\n"
3380 "Distance value\n")
3381{
3382 rip->distance = atoi (argv[0]);
3383 return CMD_SUCCESS;
3384}
3385
3386DEFUN (no_rip_distance,
3387 no_rip_distance_cmd,
3388 "no distance <1-255>",
3389 NO_STR
3390 "Administrative distance\n"
3391 "Distance value\n")
3392{
3393 rip->distance = 0;
3394 return CMD_SUCCESS;
3395}
3396
3397DEFUN (rip_distance_source,
3398 rip_distance_source_cmd,
3399 "distance <1-255> A.B.C.D/M",
3400 "Administrative distance\n"
3401 "Distance value\n"
3402 "IP source prefix\n")
3403{
3404 rip_distance_set (vty, argv[0], argv[1], NULL);
3405 return CMD_SUCCESS;
3406}
3407
3408DEFUN (no_rip_distance_source,
3409 no_rip_distance_source_cmd,
3410 "no distance <1-255> A.B.C.D/M",
3411 NO_STR
3412 "Administrative distance\n"
3413 "Distance value\n"
3414 "IP source prefix\n")
3415{
3416 rip_distance_unset (vty, argv[0], argv[1], NULL);
3417 return CMD_SUCCESS;
3418}
3419
3420DEFUN (rip_distance_source_access_list,
3421 rip_distance_source_access_list_cmd,
3422 "distance <1-255> A.B.C.D/M WORD",
3423 "Administrative distance\n"
3424 "Distance value\n"
3425 "IP source prefix\n"
3426 "Access list name\n")
3427{
3428 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3429 return CMD_SUCCESS;
3430}
3431
3432DEFUN (no_rip_distance_source_access_list,
3433 no_rip_distance_source_access_list_cmd,
3434 "no distance <1-255> A.B.C.D/M WORD",
3435 NO_STR
3436 "Administrative distance\n"
3437 "Distance value\n"
3438 "IP source prefix\n"
3439 "Access list name\n")
3440{
3441 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3442 return CMD_SUCCESS;
3443}
David Lamparter6b0655a2014-06-04 06:53:35 +02003444
Lu Feng0b74a0a2014-07-18 06:13:19 +00003445/* Update ECMP routes to zebra when ECMP is disabled. */
3446static void
3447rip_ecmp_disable (void)
3448{
3449 struct route_node *rp;
3450 struct rip_info *rinfo, *tmp_rinfo;
3451 struct list *list;
3452 struct listnode *node, *nextnode;
3453
3454 if (!rip)
3455 return;
3456
3457 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3458 if ((list = rp->info) != NULL && listcount (list) > 1)
3459 {
3460 rinfo = listgetdata (listhead (list));
3461 if (!rip_route_rte (rinfo))
3462 continue;
3463
3464 /* Drop all other entries, except the first one. */
3465 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
3466 if (tmp_rinfo != rinfo)
3467 {
3468 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
3469 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
3470 list_delete_node (list, node);
3471 rip_info_free (tmp_rinfo);
3472 }
3473
3474 /* Update zebra. */
3475 rip_zebra_ipv4_add (rp);
3476
3477 /* Set the route change flag. */
3478 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
3479
3480 /* Signal the output process to trigger an update. */
3481 rip_event (RIP_TRIGGERED_UPDATE, 0);
3482 }
3483}
3484
3485DEFUN (rip_allow_ecmp,
3486 rip_allow_ecmp_cmd,
3487 "allow-ecmp",
3488 "Allow Equal Cost MultiPath\n")
3489{
3490 if (rip->ecmp)
3491 {
3492 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
3493 return CMD_WARNING;
3494 }
3495
3496 rip->ecmp = 1;
3497 zlog_info ("ECMP is enabled.");
3498 return CMD_SUCCESS;
3499}
3500
3501DEFUN (no_rip_allow_ecmp,
3502 no_rip_allow_ecmp_cmd,
3503 "no allow-ecmp",
3504 NO_STR
3505 "Allow Equal Cost MultiPath\n")
3506{
3507 if (!rip->ecmp)
3508 {
3509 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
3510 return CMD_WARNING;
3511 }
3512
3513 rip->ecmp = 0;
3514 zlog_info ("ECMP is disabled.");
3515 rip_ecmp_disable ();
3516 return CMD_SUCCESS;
3517}
3518
paul718e3742002-12-13 20:15:29 +00003519/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003520static void
paul718e3742002-12-13 20:15:29 +00003521rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3522{
paul718e3742002-12-13 20:15:29 +00003523 time_t clock;
3524 struct tm *tm;
3525#define TIME_BUF 25
3526 char timebuf [TIME_BUF];
3527 struct thread *thread;
3528
paul718e3742002-12-13 20:15:29 +00003529 if ((thread = rinfo->t_timeout) != NULL)
3530 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003531 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003532 tm = gmtime (&clock);
3533 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3534 vty_out (vty, "%5s", timebuf);
3535 }
3536 else if ((thread = rinfo->t_garbage_collect) != NULL)
3537 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003538 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003539 tm = gmtime (&clock);
3540 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3541 vty_out (vty, "%5s", timebuf);
3542 }
3543}
3544
pauldc63bfd2005-10-25 23:31:05 +00003545static const char *
paul718e3742002-12-13 20:15:29 +00003546rip_route_type_print (int sub_type)
3547{
3548 switch (sub_type)
3549 {
3550 case RIP_ROUTE_RTE:
3551 return "n";
3552 case RIP_ROUTE_STATIC:
3553 return "s";
3554 case RIP_ROUTE_DEFAULT:
3555 return "d";
3556 case RIP_ROUTE_REDISTRIBUTE:
3557 return "r";
3558 case RIP_ROUTE_INTERFACE:
3559 return "i";
3560 default:
3561 return "?";
3562 }
3563}
3564
3565DEFUN (show_ip_rip,
3566 show_ip_rip_cmd,
3567 "show ip rip",
3568 SHOW_STR
3569 IP_STR
3570 "Show RIP routes\n")
3571{
3572 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003573 struct rip_info *rinfo = NULL;
3574 struct list *list = NULL;
3575 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003576
3577 if (! rip)
3578 return CMD_SUCCESS;
3579
hasso16705132003-05-25 14:49:19 +00003580 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3581 "Sub-codes:%s"
3582 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003583 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003584 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003585 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003586
3587 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003588 if ((list = np->info) != NULL)
3589 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00003590 {
3591 int len;
3592
ajsf52d13c2005-10-01 17:38:06 +00003593 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003594 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003595 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003596 rip_route_type_print (rinfo->sub_type),
3597 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3598
hassoa1455d82004-03-03 19:36:24 +00003599 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003600
3601 if (len > 0)
3602 vty_out (vty, "%*s", len, " ");
3603
3604 if (rinfo->nexthop.s_addr)
3605 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3606 rinfo->metric);
3607 else
3608 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3609
3610 /* Route which exist in kernel routing table. */
3611 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3612 (rinfo->sub_type == RIP_ROUTE_RTE))
3613 {
3614 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003615 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003616 rip_vty_out_uptime (vty, rinfo);
3617 }
3618 else if (rinfo->metric == RIP_METRIC_INFINITY)
3619 {
3620 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003621 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003622 rip_vty_out_uptime (vty, rinfo);
3623 }
3624 else
hasso16705132003-05-25 14:49:19 +00003625 {
vincentfbf5d032005-09-29 11:25:50 +00003626 if (rinfo->external_metric)
3627 {
3628 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003629 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003630 rinfo->external_metric);
3631 len = 16 - len;
3632 if (len > 0)
3633 vty_out (vty, "%*s", len, " ");
3634 }
3635 else
3636 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003637 vty_out (vty, "%3d", rinfo->tag);
3638 }
paul718e3742002-12-13 20:15:29 +00003639
3640 vty_out (vty, "%s", VTY_NEWLINE);
3641 }
3642 return CMD_SUCCESS;
3643}
3644
hasso16705132003-05-25 14:49:19 +00003645/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3646DEFUN (show_ip_rip_status,
3647 show_ip_rip_status_cmd,
3648 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003649 SHOW_STR
3650 IP_STR
hasso16705132003-05-25 14:49:19 +00003651 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003652 "IP routing protocol process parameters and statistics\n")
3653{
hasso52dc7ee2004-09-23 19:18:23 +00003654 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003655 struct interface *ifp;
3656 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003657 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003658 const char *send_version;
3659 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003660
3661 if (! rip)
3662 return CMD_SUCCESS;
3663
3664 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3665 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3666 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003667 vty_out (vty, " next due in %lu seconds%s",
3668 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003669 VTY_NEWLINE);
3670 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3671 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3672 VTY_NEWLINE);
3673
3674 /* Filtering status show. */
3675 config_show_distribute (vty);
3676
3677 /* Default metric information. */
3678 vty_out (vty, " Default redistribution metric is %d%s",
3679 rip->default_metric, VTY_NEWLINE);
3680
3681 /* Redistribute information. */
3682 vty_out (vty, " Redistributing:");
3683 config_write_rip_redistribute (vty, 0);
3684 vty_out (vty, "%s", VTY_NEWLINE);
3685
paulf38a4712003-06-07 01:10:00 +00003686 vty_out (vty, " Default version control: send version %s,",
3687 lookup(ri_version_msg,rip->version_send));
3688 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3689 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3690 else
3691 vty_out (vty, " receive version %s %s",
3692 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003693
3694 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3695
paul1eb8ef22005-04-07 07:30:20 +00003696 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003697 {
paul718e3742002-12-13 20:15:29 +00003698 ri = ifp->info;
3699
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003700 if (!ri->running)
3701 continue;
3702
paul718e3742002-12-13 20:15:29 +00003703 if (ri->enable_network || ri->enable_interface)
3704 {
3705 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003706 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003707 else
3708 send_version = lookup (ri_version_msg, ri->ri_send);
3709
3710 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003711 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003712 else
3713 receive_version = lookup (ri_version_msg, ri->ri_receive);
3714
3715 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3716 send_version,
3717 receive_version,
3718 ri->key_chain ? ri->key_chain : "",
3719 VTY_NEWLINE);
3720 }
3721 }
3722
3723 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3724 config_write_rip_network (vty, 0);
3725
paul4aaff3f2003-06-07 01:04:45 +00003726 {
3727 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003728 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003729 {
paul4aaff3f2003-06-07 01:04:45 +00003730 ri = ifp->info;
3731
3732 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3733 {
3734 if (!found_passive)
3735 {
3736 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3737 found_passive = 1;
3738 }
3739 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3740 }
3741 }
3742 }
3743
paul718e3742002-12-13 20:15:29 +00003744 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3745 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3746 rip_peer_display (vty);
3747
3748 rip_distance_show (vty);
3749
3750 return CMD_SUCCESS;
3751}
3752
3753/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003754static int
paul718e3742002-12-13 20:15:29 +00003755config_write_rip (struct vty *vty)
3756{
3757 int write = 0;
3758 struct route_node *rn;
3759 struct rip_distance *rdistance;
3760
3761 if (rip)
3762 {
3763 /* Router RIP statement. */
3764 vty_out (vty, "router rip%s", VTY_NEWLINE);
3765 write++;
3766
3767 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003768 if (rip->version_send != RI_RIP_VERSION_2
3769 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3770 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003771 VTY_NEWLINE);
3772
3773 /* RIP timer configuration. */
3774 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3775 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3776 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3777 vty_out (vty, " timers basic %lu %lu %lu%s",
3778 rip->update_time,
3779 rip->timeout_time,
3780 rip->garbage_time,
3781 VTY_NEWLINE);
3782
3783 /* Default information configuration. */
3784 if (rip->default_information)
3785 {
3786 if (rip->default_information_route_map)
3787 vty_out (vty, " default-information originate route-map %s%s",
3788 rip->default_information_route_map, VTY_NEWLINE);
3789 else
3790 vty_out (vty, " default-information originate%s",
3791 VTY_NEWLINE);
3792 }
3793
3794 /* Redistribute configuration. */
3795 config_write_rip_redistribute (vty, 1);
3796
3797 /* RIP offset-list configuration. */
3798 config_write_rip_offset_list (vty);
3799
3800 /* RIP enabled network and interface configuration. */
3801 config_write_rip_network (vty, 1);
3802
3803 /* RIP default metric configuration */
3804 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3805 vty_out (vty, " default-metric %d%s",
3806 rip->default_metric, VTY_NEWLINE);
3807
3808 /* Distribute configuration. */
3809 write += config_write_distribute (vty);
3810
hasso16705132003-05-25 14:49:19 +00003811 /* Interface routemap configuration */
3812 write += config_write_if_rmap (vty);
3813
paul718e3742002-12-13 20:15:29 +00003814 /* Distance configuration. */
3815 if (rip->distance)
3816 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3817
3818 /* RIP source IP prefix distance configuration. */
3819 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3820 if ((rdistance = rn->info) != NULL)
3821 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3822 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3823 rdistance->access_list ? rdistance->access_list : "",
3824 VTY_NEWLINE);
3825
Lu Feng0b74a0a2014-07-18 06:13:19 +00003826 /* ECMP configuration. */
3827 if (rip->ecmp)
3828 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
3829
paul718e3742002-12-13 20:15:29 +00003830 /* RIP static route configuration. */
3831 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3832 if (rn->info)
3833 vty_out (vty, " route %s/%d%s",
3834 inet_ntoa (rn->p.u.prefix4),
3835 rn->p.prefixlen,
3836 VTY_NEWLINE);
3837
3838 }
3839 return write;
3840}
3841
3842/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003843static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003844{
3845 RIP_NODE,
3846 "%s(config-router)# ",
3847 1
3848};
David Lamparter6b0655a2014-06-04 06:53:35 +02003849
paul718e3742002-12-13 20:15:29 +00003850/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003851static void
paul718e3742002-12-13 20:15:29 +00003852rip_distribute_update (struct distribute *dist)
3853{
3854 struct interface *ifp;
3855 struct rip_interface *ri;
3856 struct access_list *alist;
3857 struct prefix_list *plist;
3858
3859 if (! dist->ifname)
3860 return;
3861
3862 ifp = if_lookup_by_name (dist->ifname);
3863 if (ifp == NULL)
3864 return;
3865
3866 ri = ifp->info;
3867
3868 if (dist->list[DISTRIBUTE_IN])
3869 {
3870 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3871 if (alist)
3872 ri->list[RIP_FILTER_IN] = alist;
3873 else
3874 ri->list[RIP_FILTER_IN] = NULL;
3875 }
3876 else
3877 ri->list[RIP_FILTER_IN] = NULL;
3878
3879 if (dist->list[DISTRIBUTE_OUT])
3880 {
3881 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3882 if (alist)
3883 ri->list[RIP_FILTER_OUT] = alist;
3884 else
3885 ri->list[RIP_FILTER_OUT] = NULL;
3886 }
3887 else
3888 ri->list[RIP_FILTER_OUT] = NULL;
3889
3890 if (dist->prefix[DISTRIBUTE_IN])
3891 {
3892 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3893 if (plist)
3894 ri->prefix[RIP_FILTER_IN] = plist;
3895 else
3896 ri->prefix[RIP_FILTER_IN] = NULL;
3897 }
3898 else
3899 ri->prefix[RIP_FILTER_IN] = NULL;
3900
3901 if (dist->prefix[DISTRIBUTE_OUT])
3902 {
3903 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3904 if (plist)
3905 ri->prefix[RIP_FILTER_OUT] = plist;
3906 else
3907 ri->prefix[RIP_FILTER_OUT] = NULL;
3908 }
3909 else
3910 ri->prefix[RIP_FILTER_OUT] = NULL;
3911}
3912
3913void
3914rip_distribute_update_interface (struct interface *ifp)
3915{
3916 struct distribute *dist;
3917
3918 dist = distribute_lookup (ifp->name);
3919 if (dist)
3920 rip_distribute_update (dist);
3921}
3922
3923/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003924/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003925static void
paul02ff83c2004-06-11 11:27:03 +00003926rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003927{
3928 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003929 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003930
paul1eb8ef22005-04-07 07:30:20 +00003931 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3932 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003933}
paul11dde9c2004-05-31 14:00:00 +00003934/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003935static void
paul11dde9c2004-05-31 14:00:00 +00003936rip_distribute_update_all_wrapper(struct access_list *notused)
3937{
paul02ff83c2004-06-11 11:27:03 +00003938 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003939}
David Lamparter6b0655a2014-06-04 06:53:35 +02003940
paul718e3742002-12-13 20:15:29 +00003941/* Delete all added rip route. */
3942void
paul216565a2005-10-25 23:35:28 +00003943rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003944{
3945 int i;
3946 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00003947 struct rip_info *rinfo = NULL;
3948 struct list *list = NULL;
3949 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003950
3951 if (rip)
3952 {
3953 /* Clear RIP routes */
3954 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00003955 if ((list = rp->info) != NULL)
3956 {
3957 rinfo = listgetdata (listhead (list));
3958 if (rip_route_rte (rinfo))
3959 rip_zebra_ipv4_delete (rp);
paul718e3742002-12-13 20:15:29 +00003960
Lu Fengb397cf42014-07-18 06:13:18 +00003961 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3962 {
3963 RIP_TIMER_OFF (rinfo->t_timeout);
3964 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3965 rip_info_free (rinfo);
3966 }
3967 list_delete (list);
3968 rp->info = NULL;
3969 route_unlock_node (rp);
3970 }
paul718e3742002-12-13 20:15:29 +00003971
3972 /* Cancel RIP related timers. */
3973 RIP_TIMER_OFF (rip->t_update);
3974 RIP_TIMER_OFF (rip->t_triggered_update);
3975 RIP_TIMER_OFF (rip->t_triggered_interval);
3976
3977 /* Cancel read thread. */
3978 if (rip->t_read)
3979 {
3980 thread_cancel (rip->t_read);
3981 rip->t_read = NULL;
3982 }
3983
3984 /* Close RIP socket. */
3985 if (rip->sock >= 0)
3986 {
3987 close (rip->sock);
3988 rip->sock = -1;
3989 }
3990
3991 /* Static RIP route configuration. */
3992 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3993 if (rp->info)
3994 {
3995 rp->info = NULL;
3996 route_unlock_node (rp);
3997 }
3998
3999 /* RIP neighbor configuration. */
4000 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
4001 if (rp->info)
4002 {
4003 rp->info = NULL;
4004 route_unlock_node (rp);
4005 }
4006
4007 /* Redistribute related clear. */
4008 if (rip->default_information_route_map)
4009 free (rip->default_information_route_map);
4010
4011 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4012 if (rip->route_map[i].name)
4013 free (rip->route_map[i].name);
4014
4015 XFREE (MTYPE_ROUTE_TABLE, rip->table);
4016 XFREE (MTYPE_ROUTE_TABLE, rip->route);
4017 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
4018
4019 XFREE (MTYPE_RIP, rip);
4020 rip = NULL;
4021 }
4022
4023 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00004024 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00004025 rip_offset_clean ();
4026 rip_interface_clean ();
4027 rip_distance_reset ();
4028 rip_redistribute_clean ();
4029}
4030
4031/* Reset all values to the default settings. */
4032void
paul216565a2005-10-25 23:35:28 +00004033rip_reset (void)
paul718e3742002-12-13 20:15:29 +00004034{
4035 /* Reset global counters. */
4036 rip_global_route_changes = 0;
4037 rip_global_queries = 0;
4038
4039 /* Call ripd related reset functions. */
4040 rip_debug_reset ();
4041 rip_route_map_reset ();
4042
4043 /* Call library reset functions. */
4044 vty_reset ();
4045 access_list_reset ();
4046 prefix_list_reset ();
4047
4048 distribute_list_reset ();
4049
4050 rip_interface_reset ();
4051 rip_distance_reset ();
4052
4053 rip_zclient_reset ();
4054}
4055
pauldc63bfd2005-10-25 23:31:05 +00004056static void
hasso16705132003-05-25 14:49:19 +00004057rip_if_rmap_update (struct if_rmap *if_rmap)
4058{
4059 struct interface *ifp;
4060 struct rip_interface *ri;
4061 struct route_map *rmap;
4062
4063 ifp = if_lookup_by_name (if_rmap->ifname);
4064 if (ifp == NULL)
4065 return;
4066
4067 ri = ifp->info;
4068
4069 if (if_rmap->routemap[IF_RMAP_IN])
4070 {
4071 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
4072 if (rmap)
4073 ri->routemap[IF_RMAP_IN] = rmap;
4074 else
4075 ri->routemap[IF_RMAP_IN] = NULL;
4076 }
4077 else
4078 ri->routemap[RIP_FILTER_IN] = NULL;
4079
4080 if (if_rmap->routemap[IF_RMAP_OUT])
4081 {
4082 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
4083 if (rmap)
4084 ri->routemap[IF_RMAP_OUT] = rmap;
4085 else
4086 ri->routemap[IF_RMAP_OUT] = NULL;
4087 }
4088 else
4089 ri->routemap[RIP_FILTER_OUT] = NULL;
4090}
4091
4092void
4093rip_if_rmap_update_interface (struct interface *ifp)
4094{
4095 struct if_rmap *if_rmap;
4096
4097 if_rmap = if_rmap_lookup (ifp->name);
4098 if (if_rmap)
4099 rip_if_rmap_update (if_rmap);
4100}
4101
pauldc63bfd2005-10-25 23:31:05 +00004102static void
hasso16705132003-05-25 14:49:19 +00004103rip_routemap_update_redistribute (void)
4104{
4105 int i;
4106
4107 if (rip)
4108 {
4109 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4110 {
4111 if (rip->route_map[i].name)
4112 rip->route_map[i].map =
4113 route_map_lookup_by_name (rip->route_map[i].name);
4114 }
4115 }
4116}
4117
paul11dde9c2004-05-31 14:00:00 +00004118/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00004119static void
hasso98b718a2004-10-11 12:57:57 +00004120rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00004121{
4122 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00004123 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00004124
paul1eb8ef22005-04-07 07:30:20 +00004125 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
4126 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00004127
4128 rip_routemap_update_redistribute ();
4129}
4130
paul718e3742002-12-13 20:15:29 +00004131/* Allocate new rip structure and set default value. */
4132void
pauldc63bfd2005-10-25 23:31:05 +00004133rip_init (void)
paul718e3742002-12-13 20:15:29 +00004134{
4135 /* Randomize for triggered update random(). */
Donald Sharpf31bab42015-06-19 19:26:19 -04004136 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00004137
4138 /* Install top nodes. */
4139 install_node (&rip_node, config_write_rip);
4140
4141 /* Install rip commands. */
4142 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004143 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004144 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004145 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004146 install_element (CONFIG_NODE, &router_rip_cmd);
4147 install_element (CONFIG_NODE, &no_router_rip_cmd);
4148
4149 install_default (RIP_NODE);
4150 install_element (RIP_NODE, &rip_version_cmd);
4151 install_element (RIP_NODE, &no_rip_version_cmd);
4152 install_element (RIP_NODE, &no_rip_version_val_cmd);
4153 install_element (RIP_NODE, &rip_default_metric_cmd);
4154 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4155 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4156 install_element (RIP_NODE, &rip_timers_cmd);
4157 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004158 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004159 install_element (RIP_NODE, &rip_route_cmd);
4160 install_element (RIP_NODE, &no_rip_route_cmd);
4161 install_element (RIP_NODE, &rip_distance_cmd);
4162 install_element (RIP_NODE, &no_rip_distance_cmd);
4163 install_element (RIP_NODE, &rip_distance_source_cmd);
4164 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4165 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4166 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
Lu Feng0b74a0a2014-07-18 06:13:19 +00004167 install_element (RIP_NODE, &rip_allow_ecmp_cmd);
4168 install_element (RIP_NODE, &no_rip_allow_ecmp_cmd);
paul718e3742002-12-13 20:15:29 +00004169
4170 /* Debug related init. */
4171 rip_debug_init ();
4172
paul718e3742002-12-13 20:15:29 +00004173 /* SNMP init. */
4174#ifdef HAVE_SNMP
4175 rip_snmp_init ();
4176#endif /* HAVE_SNMP */
4177
4178 /* Access list install. */
4179 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004180 access_list_add_hook (rip_distribute_update_all_wrapper);
4181 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004182
4183 /* Prefix list initialize.*/
4184 prefix_list_init ();
4185 prefix_list_add_hook (rip_distribute_update_all);
4186 prefix_list_delete_hook (rip_distribute_update_all);
4187
4188 /* Distribute list install. */
4189 distribute_list_init (RIP_NODE);
4190 distribute_list_add_hook (rip_distribute_update);
4191 distribute_list_delete_hook (rip_distribute_update);
4192
hasso16705132003-05-25 14:49:19 +00004193 /* Route-map */
4194 rip_route_map_init ();
4195 rip_offset_init ();
4196
4197 route_map_add_hook (rip_routemap_update);
4198 route_map_delete_hook (rip_routemap_update);
4199
4200 if_rmap_init (RIP_NODE);
4201 if_rmap_hook_add (rip_if_rmap_update);
4202 if_rmap_hook_delete (rip_if_rmap_update);
4203
paul718e3742002-12-13 20:15:29 +00004204 /* Distance control. */
4205 rip_distance_table = route_table_init ();
4206}