blob: 0beb0e6285ab8ef4216380d7bf38aaceb13431aa [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))
Donald Sharp7e7a1012016-04-08 22:03:22 -04002432 {
2433 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2434 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2435 rinfo->metric_out = RIP_METRIC_INFINITY;
2436 if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT &&
2437 prefix_match((struct prefix *)p, ifc->address))
2438 rinfo->metric_out = RIP_METRIC_INFINITY;
2439 }
hasso16705132003-05-25 14:49:19 +00002440 }
paulb14ee002005-02-04 23:42:41 +00002441
2442 /* Prepare preamble, auth headers, if needs be */
2443 if (num == 0)
2444 {
2445 stream_putc (s, RIP_RESPONSE);
2446 stream_putc (s, version);
2447 stream_putw (s, 0);
2448
paul0cb8a012005-05-29 11:27:24 +00002449 /* auth header for !v1 && !no_auth */
2450 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002451 doff = rip_auth_header_write (s, ri, key, auth_str,
2452 RIP_AUTH_SIMPLE_SIZE);
2453 }
2454
paul718e3742002-12-13 20:15:29 +00002455 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002456 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002457 if (num == rtemax)
2458 {
2459 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002460 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002461
2462 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002463 to, ifc);
paul718e3742002-12-13 20:15:29 +00002464
2465 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2466 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2467 stream_get_endp(s), "SEND");
2468 num = 0;
2469 stream_reset (s);
2470 }
2471 }
2472
2473 /* Flush unwritten RTE. */
2474 if (num != 0)
2475 {
2476 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002477 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002478
paulc49ad8f2004-10-22 10:27:28 +00002479 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002480
2481 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2482 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2483 stream_get_endp (s), "SEND");
2484 num = 0;
2485 stream_reset (s);
2486 }
2487
2488 /* Statistics updates. */
2489 ri->sent_updates++;
2490}
2491
2492/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002493static void
paulc49ad8f2004-10-22 10:27:28 +00002494rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002495{
paul718e3742002-12-13 20:15:29 +00002496 struct sockaddr_in to;
2497
2498 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002499 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002500 {
2501 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002502 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002503
paulc49ad8f2004-10-22 10:27:28 +00002504 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002505 return;
2506 }
paulc49ad8f2004-10-22 10:27:28 +00002507
paul718e3742002-12-13 20:15:29 +00002508 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002509 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002510 {
paulc49ad8f2004-10-22 10:27:28 +00002511 if (ifc->address->family == AF_INET)
2512 {
2513 /* Destination address and port setting. */
2514 memset (&to, 0, sizeof (struct sockaddr_in));
2515 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002516 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002517 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002518 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002519 /* calculate the appropriate broadcast address */
2520 to.sin_addr.s_addr =
2521 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2522 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002523 else
2524 /* do not know where to send the packet */
2525 return;
paulc49ad8f2004-10-22 10:27:28 +00002526 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002527
paulc49ad8f2004-10-22 10:27:28 +00002528 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002529 zlog_debug("%s announce to %s on %s",
2530 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2531 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002532
paulc49ad8f2004-10-22 10:27:28 +00002533 rip_output_process (ifc, &to, route_type, version);
2534 }
paul718e3742002-12-13 20:15:29 +00002535 }
2536}
2537
2538/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002539static void
paul718e3742002-12-13 20:15:29 +00002540rip_update_process (int route_type)
2541{
paul1eb8ef22005-04-07 07:30:20 +00002542 struct listnode *node;
2543 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002544 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002545 struct interface *ifp;
2546 struct rip_interface *ri;
2547 struct route_node *rp;
2548 struct sockaddr_in to;
2549 struct prefix_ipv4 *p;
2550
2551 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002552 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002553 {
paul718e3742002-12-13 20:15:29 +00002554 if (if_is_loopback (ifp))
2555 continue;
2556
paul2e3b2e42002-12-13 21:03:13 +00002557 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002558 continue;
2559
2560 /* Fetch RIP interface information. */
2561 ri = ifp->info;
2562
2563 /* When passive interface is specified, suppress announce to the
2564 interface. */
2565 if (ri->passive)
2566 continue;
2567
2568 if (ri->running)
2569 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002570 /*
2571 * If there is no version configuration in the interface,
2572 * use rip's version setting.
2573 */
2574 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2575 rip->version_send : ri->ri_send);
2576
paul718e3742002-12-13 20:15:29 +00002577 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002578 zlog_debug("SEND UPDATE to %s ifindex %d",
Christian Franke1ca8d402015-11-10 17:45:03 +01002579 ifp->name, ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002580
paulcc1131a2003-10-15 23:20:17 +00002581 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002582 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002583 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002584 if (connected->address->family == AF_INET)
2585 {
2586 if (vsend & RIPv1)
2587 rip_update_interface (connected, RIPv1, route_type);
2588 if ((vsend & RIPv2) && if_is_multicast(ifp))
2589 rip_update_interface (connected, RIPv2, route_type);
2590 }
2591 }
paul718e3742002-12-13 20:15:29 +00002592 }
2593 }
2594
2595 /* RIP send updates to each neighbor. */
2596 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2597 if (rp->info != NULL)
2598 {
2599 p = (struct prefix_ipv4 *) &rp->p;
2600
2601 ifp = if_lookup_address (p->prefix);
2602 if (! ifp)
2603 {
paulc49ad8f2004-10-22 10:27:28 +00002604 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002605 inet_ntoa (p->prefix));
2606 continue;
2607 }
paulc49ad8f2004-10-22 10:27:28 +00002608
2609 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2610 {
2611 zlog_warn ("Neighbor %s doesnt have connected network",
2612 inet_ntoa (p->prefix));
2613 continue;
2614 }
2615
paul718e3742002-12-13 20:15:29 +00002616 /* Set destination address and port */
2617 memset (&to, 0, sizeof (struct sockaddr_in));
2618 to.sin_addr = p->prefix;
2619 to.sin_port = htons (RIP_PORT_DEFAULT);
2620
2621 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002622 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002623 }
2624}
2625
2626/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002627static int
paul718e3742002-12-13 20:15:29 +00002628rip_update (struct thread *t)
2629{
2630 /* Clear timer pointer. */
2631 rip->t_update = NULL;
2632
2633 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002634 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002635
2636 /* Process update output. */
2637 rip_update_process (rip_all_route);
2638
2639 /* Triggered updates may be suppressed if a regular update is due by
2640 the time the triggered update would be sent. */
2641 if (rip->t_triggered_interval)
2642 {
2643 thread_cancel (rip->t_triggered_interval);
2644 rip->t_triggered_interval = NULL;
2645 }
2646 rip->trigger = 0;
2647
2648 /* Register myself. */
2649 rip_event (RIP_UPDATE_EVENT, 0);
2650
2651 return 0;
2652}
2653
2654/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002655static void
paul216565a2005-10-25 23:35:28 +00002656rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002657{
2658 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002659 struct rip_info *rinfo = NULL;
2660 struct list *list = NULL;
2661 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002662
2663 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002664 if ((list = rp->info) != NULL)
2665 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2666 {
2667 UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
2668 /* This flag can be set only on the first entry. */
2669 break;
2670 }
paul718e3742002-12-13 20:15:29 +00002671}
2672
2673/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002674static int
paul718e3742002-12-13 20:15:29 +00002675rip_triggered_interval (struct thread *t)
2676{
2677 int rip_triggered_update (struct thread *);
2678
2679 rip->t_triggered_interval = NULL;
2680
2681 if (rip->trigger)
2682 {
2683 rip->trigger = 0;
2684 rip_triggered_update (t);
2685 }
2686 return 0;
2687}
2688
2689/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002690static int
paul718e3742002-12-13 20:15:29 +00002691rip_triggered_update (struct thread *t)
2692{
2693 int interval;
2694
2695 /* Clear thred pointer. */
2696 rip->t_triggered_update = NULL;
2697
2698 /* Cancel interval timer. */
2699 if (rip->t_triggered_interval)
2700 {
2701 thread_cancel (rip->t_triggered_interval);
2702 rip->t_triggered_interval = NULL;
2703 }
2704 rip->trigger = 0;
2705
2706 /* Logging triggered update. */
2707 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002708 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002709
2710 /* Split Horizon processing is done when generating triggered
2711 updates as well as normal updates (see section 2.6). */
2712 rip_update_process (rip_changed_route);
2713
2714 /* Once all of the triggered updates have been generated, the route
2715 change flags should be cleared. */
2716 rip_clear_changed_flag ();
2717
2718 /* After a triggered update is sent, a timer should be set for a
2719 random interval between 1 and 5 seconds. If other changes that
2720 would trigger updates occur before the timer expires, a single
2721 update is triggered when the timer expires. */
2722 interval = (random () % 5) + 1;
2723
2724 rip->t_triggered_interval =
2725 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2726
2727 return 0;
2728}
2729
2730/* Withdraw redistributed route. */
2731void
2732rip_redistribute_withdraw (int type)
2733{
2734 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002735 struct rip_info *rinfo = NULL;
2736 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00002737
2738 if (!rip)
2739 return;
2740
2741 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002742 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00002743 {
Lu Fengb397cf42014-07-18 06:13:18 +00002744 rinfo = listgetdata (listhead (list));
paul718e3742002-12-13 20:15:29 +00002745 if (rinfo->type == type
2746 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2747 {
2748 /* Perform poisoned reverse. */
2749 rinfo->metric = RIP_METRIC_INFINITY;
2750 RIP_TIMER_ON (rinfo->t_garbage_collect,
2751 rip_garbage_collect, rip->garbage_time);
2752 RIP_TIMER_OFF (rinfo->t_timeout);
2753 rinfo->flags |= RIP_RTF_CHANGED;
2754
hasso16705132003-05-25 14:49:19 +00002755 if (IS_RIP_DEBUG_EVENT) {
2756 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2757
ajs5d6c3772004-12-08 19:24:06 +00002758 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002759 inet_ntoa(p->prefix), p->prefixlen,
2760 ifindex2ifname(rinfo->ifindex));
2761 }
2762
paul718e3742002-12-13 20:15:29 +00002763 rip_event (RIP_TRIGGERED_UPDATE, 0);
2764 }
2765 }
2766}
2767
2768/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002769static int
2770rip_create (void)
paul718e3742002-12-13 20:15:29 +00002771{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002772 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002773
2774 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002775 rip->version_send = RI_RIP_VERSION_2;
2776 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002777 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2778 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2779 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2780 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2781
2782 /* Initialize RIP routig table. */
2783 rip->table = route_table_init ();
2784 rip->route = route_table_init ();
2785 rip->neighbor = route_table_init ();
2786
2787 /* Make output stream. */
2788 rip->obuf = stream_new (1500);
2789
2790 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002791 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002792 if (rip->sock < 0)
2793 return rip->sock;
2794
2795 /* Create read and timer thread. */
2796 rip_event (RIP_READ, rip->sock);
2797 rip_event (RIP_UPDATE_EVENT, 1);
2798
2799 return 0;
2800}
2801
2802/* Sned RIP request to the destination. */
2803int
2804rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002805 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002806{
2807 struct rte *rte;
2808 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002809 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002810
2811 memset (&rip_packet, 0, sizeof (rip_packet));
2812
2813 rip_packet.command = RIP_REQUEST;
2814 rip_packet.version = version;
2815 rte = rip_packet.rte;
2816 rte->metric = htonl (RIP_METRIC_INFINITY);
2817
paul931cd542004-01-23 15:31:42 +00002818 if (connected)
2819 {
2820 /*
2821 * connected is only sent for ripv1 case, or when
2822 * interface does not support multicast. Caller loops
2823 * over each connected address for this case.
2824 */
paul11dde9c2004-05-31 14:00:00 +00002825 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002826 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002827 return -1;
2828 else
2829 return sizeof (rip_packet);
2830 }
2831
paulcc1131a2003-10-15 23:20:17 +00002832 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002833 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002834 {
2835 struct prefix_ipv4 *p;
2836
2837 p = (struct prefix_ipv4 *) connected->address;
2838
2839 if (p->family != AF_INET)
2840 continue;
2841
paul11dde9c2004-05-31 14:00:00 +00002842 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002843 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002844 return -1;
2845 }
2846 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002847}
David Lamparter6b0655a2014-06-04 06:53:35 +02002848
pauldc63bfd2005-10-25 23:31:05 +00002849static int
paul718e3742002-12-13 20:15:29 +00002850rip_update_jitter (unsigned long time)
2851{
paul239389b2004-05-05 14:09:37 +00002852#define JITTER_BOUND 4
2853 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2854 Given that, we cannot let time be less than JITTER_BOUND seconds.
2855 The RIPv2 RFC says jitter should be small compared to
2856 update_time. We consider 1/JITTER_BOUND to be small.
2857 */
2858
2859 int jitter_input = time;
2860 int jitter;
2861
2862 if (jitter_input < JITTER_BOUND)
2863 jitter_input = JITTER_BOUND;
2864
Donald Sharpf31bab42015-06-19 19:26:19 -04002865 jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input));
paul239389b2004-05-05 14:09:37 +00002866
2867 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002868}
2869
2870void
2871rip_event (enum rip_event event, int sock)
2872{
2873 int jitter = 0;
2874
2875 switch (event)
2876 {
2877 case RIP_READ:
2878 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2879 break;
2880 case RIP_UPDATE_EVENT:
2881 if (rip->t_update)
2882 {
2883 thread_cancel (rip->t_update);
2884 rip->t_update = NULL;
2885 }
2886 jitter = rip_update_jitter (rip->update_time);
2887 rip->t_update =
2888 thread_add_timer (master, rip_update, NULL,
2889 sock ? 2 : rip->update_time + jitter);
2890 break;
2891 case RIP_TRIGGERED_UPDATE:
2892 if (rip->t_triggered_interval)
2893 rip->trigger = 1;
2894 else if (! rip->t_triggered_update)
2895 rip->t_triggered_update =
2896 thread_add_event (master, rip_triggered_update, NULL, 0);
2897 break;
2898 default:
2899 break;
2900 }
2901}
David Lamparter6b0655a2014-06-04 06:53:35 +02002902
paul718e3742002-12-13 20:15:29 +00002903DEFUN (router_rip,
2904 router_rip_cmd,
2905 "router rip",
2906 "Enable a routing process\n"
2907 "Routing Information Protocol (RIP)\n")
2908{
2909 int ret;
2910
2911 /* If rip is not enabled before. */
2912 if (! rip)
2913 {
2914 ret = rip_create ();
2915 if (ret < 0)
2916 {
2917 zlog_info ("Can't create RIP");
2918 return CMD_WARNING;
2919 }
2920 }
2921 vty->node = RIP_NODE;
2922 vty->index = rip;
2923
2924 return CMD_SUCCESS;
2925}
2926
2927DEFUN (no_router_rip,
2928 no_router_rip_cmd,
2929 "no router rip",
2930 NO_STR
2931 "Enable a routing process\n"
2932 "Routing Information Protocol (RIP)\n")
2933{
2934 if (rip)
2935 rip_clean ();
2936 return CMD_SUCCESS;
2937}
2938
2939DEFUN (rip_version,
2940 rip_version_cmd,
2941 "version <1-2>",
2942 "Set routing protocol version\n"
2943 "version\n")
2944{
2945 int version;
2946
2947 version = atoi (argv[0]);
2948 if (version != RIPv1 && version != RIPv2)
2949 {
2950 vty_out (vty, "invalid rip version %d%s", version,
2951 VTY_NEWLINE);
2952 return CMD_WARNING;
2953 }
paulf38a4712003-06-07 01:10:00 +00002954 rip->version_send = version;
2955 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002956
2957 return CMD_SUCCESS;
2958}
2959
2960DEFUN (no_rip_version,
2961 no_rip_version_cmd,
2962 "no version",
2963 NO_STR
2964 "Set routing protocol version\n")
2965{
2966 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002967 rip->version_send = RI_RIP_VERSION_2;
2968 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002969
2970 return CMD_SUCCESS;
2971}
2972
2973ALIAS (no_rip_version,
2974 no_rip_version_val_cmd,
2975 "no version <1-2>",
2976 NO_STR
2977 "Set routing protocol version\n"
2978 "version\n")
2979
2980DEFUN (rip_route,
2981 rip_route_cmd,
2982 "route A.B.C.D/M",
2983 "RIP static route configuration\n"
2984 "IP prefix <network>/<length>\n")
2985{
2986 int ret;
2987 struct prefix_ipv4 p;
2988 struct route_node *node;
2989
2990 ret = str2prefix_ipv4 (argv[0], &p);
2991 if (ret < 0)
2992 {
2993 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2994 return CMD_WARNING;
2995 }
2996 apply_mask_ipv4 (&p);
2997
2998 /* For router rip configuration. */
2999 node = route_node_get (rip->route, (struct prefix *) &p);
3000
3001 if (node->info)
3002 {
3003 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
3004 route_unlock_node (node);
3005 return CMD_WARNING;
3006 }
3007
hasso8a676be2004-10-08 06:36:38 +00003008 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00003009
vincentfbf5d032005-09-29 11:25:50 +00003010 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00003011
3012 return CMD_SUCCESS;
3013}
3014
3015DEFUN (no_rip_route,
3016 no_rip_route_cmd,
3017 "no route A.B.C.D/M",
3018 NO_STR
3019 "RIP static route configuration\n"
3020 "IP prefix <network>/<length>\n")
3021{
3022 int ret;
3023 struct prefix_ipv4 p;
3024 struct route_node *node;
3025
3026 ret = str2prefix_ipv4 (argv[0], &p);
3027 if (ret < 0)
3028 {
3029 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
3030 return CMD_WARNING;
3031 }
3032 apply_mask_ipv4 (&p);
3033
3034 /* For router rip configuration. */
3035 node = route_node_lookup (rip->route, (struct prefix *) &p);
3036 if (! node)
3037 {
3038 vty_out (vty, "Can't find route %s.%s", argv[0],
3039 VTY_NEWLINE);
3040 return CMD_WARNING;
3041 }
3042
3043 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
3044 route_unlock_node (node);
3045
3046 node->info = NULL;
3047 route_unlock_node (node);
3048
3049 return CMD_SUCCESS;
3050}
3051
Stephen Hemminger2c239702009-12-10 19:16:05 +03003052#if 0
pauldc63bfd2005-10-25 23:31:05 +00003053static void
paul216565a2005-10-25 23:35:28 +00003054rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00003055{
3056 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003057 struct rip_info *rinfo = NULL;
3058 struct list *list = NULL;
3059 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003060
3061 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003062 if ((list = np->info) != NULL)
3063 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3064 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
3065 rinfo->metric = rip->default_metric;
paul718e3742002-12-13 20:15:29 +00003066}
Stephen Hemminger2c239702009-12-10 19:16:05 +03003067#endif
paul718e3742002-12-13 20:15:29 +00003068
3069DEFUN (rip_default_metric,
3070 rip_default_metric_cmd,
3071 "default-metric <1-16>",
3072 "Set a metric of redistribute routes\n"
3073 "Default metric\n")
3074{
3075 if (rip)
3076 {
3077 rip->default_metric = atoi (argv[0]);
3078 /* rip_update_default_metric (); */
3079 }
3080 return CMD_SUCCESS;
3081}
3082
3083DEFUN (no_rip_default_metric,
3084 no_rip_default_metric_cmd,
3085 "no default-metric",
3086 NO_STR
3087 "Set a metric of redistribute routes\n"
3088 "Default metric\n")
3089{
3090 if (rip)
3091 {
3092 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3093 /* rip_update_default_metric (); */
3094 }
3095 return CMD_SUCCESS;
3096}
3097
3098ALIAS (no_rip_default_metric,
3099 no_rip_default_metric_val_cmd,
3100 "no default-metric <1-16>",
3101 NO_STR
3102 "Set a metric of redistribute routes\n"
3103 "Default metric\n")
3104
3105DEFUN (rip_timers,
3106 rip_timers_cmd,
3107 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3108 "Adjust routing timers\n"
3109 "Basic routing protocol update timers\n"
3110 "Routing table update timer value in second. Default is 30.\n"
3111 "Routing information timeout timer. Default is 180.\n"
3112 "Garbage collection timer. Default is 120.\n")
3113{
3114 unsigned long update;
3115 unsigned long timeout;
3116 unsigned long garbage;
3117 char *endptr = NULL;
3118 unsigned long RIP_TIMER_MAX = 2147483647;
3119 unsigned long RIP_TIMER_MIN = 5;
3120
3121 update = strtoul (argv[0], &endptr, 10);
3122 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3123 {
3124 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3125 return CMD_WARNING;
3126 }
3127
3128 timeout = strtoul (argv[1], &endptr, 10);
3129 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3130 {
3131 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3132 return CMD_WARNING;
3133 }
3134
3135 garbage = strtoul (argv[2], &endptr, 10);
3136 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3137 {
3138 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3139 return CMD_WARNING;
3140 }
3141
3142 /* Set each timer value. */
3143 rip->update_time = update;
3144 rip->timeout_time = timeout;
3145 rip->garbage_time = garbage;
3146
3147 /* Reset update timer thread. */
3148 rip_event (RIP_UPDATE_EVENT, 0);
3149
3150 return CMD_SUCCESS;
3151}
3152
3153DEFUN (no_rip_timers,
3154 no_rip_timers_cmd,
3155 "no timers basic",
3156 NO_STR
3157 "Adjust routing timers\n"
3158 "Basic routing protocol update timers\n")
3159{
3160 /* Set each timer value to the default. */
3161 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3162 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3163 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3164
3165 /* Reset update timer thread. */
3166 rip_event (RIP_UPDATE_EVENT, 0);
3167
3168 return CMD_SUCCESS;
3169}
hasso16705132003-05-25 14:49:19 +00003170
3171ALIAS (no_rip_timers,
3172 no_rip_timers_val_cmd,
3173 "no timers basic <0-65535> <0-65535> <0-65535>",
3174 NO_STR
3175 "Adjust routing timers\n"
3176 "Basic routing protocol update timers\n"
3177 "Routing table update timer value in second. Default is 30.\n"
3178 "Routing information timeout timer. Default is 180.\n"
3179 "Garbage collection timer. Default is 120.\n")
3180
David Lamparter6b0655a2014-06-04 06:53:35 +02003181
paul718e3742002-12-13 20:15:29 +00003182struct route_table *rip_distance_table;
3183
3184struct rip_distance
3185{
3186 /* Distance value for the IP source prefix. */
3187 u_char distance;
3188
3189 /* Name of the access-list to be matched. */
3190 char *access_list;
3191};
3192
pauldc63bfd2005-10-25 23:31:05 +00003193static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003194rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003195{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003196 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003197}
3198
pauldc63bfd2005-10-25 23:31:05 +00003199static void
paul718e3742002-12-13 20:15:29 +00003200rip_distance_free (struct rip_distance *rdistance)
3201{
3202 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3203}
3204
pauldc63bfd2005-10-25 23:31:05 +00003205static int
hasso98b718a2004-10-11 12:57:57 +00003206rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3207 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003208{
3209 int ret;
3210 struct prefix_ipv4 p;
3211 u_char distance;
3212 struct route_node *rn;
3213 struct rip_distance *rdistance;
3214
3215 ret = str2prefix_ipv4 (ip_str, &p);
3216 if (ret == 0)
3217 {
3218 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3219 return CMD_WARNING;
3220 }
3221
3222 distance = atoi (distance_str);
3223
3224 /* Get RIP distance node. */
3225 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3226 if (rn->info)
3227 {
3228 rdistance = rn->info;
3229 route_unlock_node (rn);
3230 }
3231 else
3232 {
3233 rdistance = rip_distance_new ();
3234 rn->info = rdistance;
3235 }
3236
3237 /* Set distance value. */
3238 rdistance->distance = distance;
3239
3240 /* Reset access-list configuration. */
3241 if (rdistance->access_list)
3242 {
3243 free (rdistance->access_list);
3244 rdistance->access_list = NULL;
3245 }
3246 if (access_list_str)
3247 rdistance->access_list = strdup (access_list_str);
3248
3249 return CMD_SUCCESS;
3250}
3251
pauldc63bfd2005-10-25 23:31:05 +00003252static int
hasso98b718a2004-10-11 12:57:57 +00003253rip_distance_unset (struct vty *vty, const char *distance_str,
3254 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003255{
3256 int ret;
3257 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +00003258 struct route_node *rn;
3259 struct rip_distance *rdistance;
3260
3261 ret = str2prefix_ipv4 (ip_str, &p);
3262 if (ret == 0)
3263 {
3264 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3265 return CMD_WARNING;
3266 }
3267
paul718e3742002-12-13 20:15:29 +00003268 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3269 if (! rn)
3270 {
3271 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3272 return CMD_WARNING;
3273 }
3274
3275 rdistance = rn->info;
3276
3277 if (rdistance->access_list)
3278 free (rdistance->access_list);
3279 rip_distance_free (rdistance);
3280
3281 rn->info = NULL;
3282 route_unlock_node (rn);
3283 route_unlock_node (rn);
3284
3285 return CMD_SUCCESS;
3286}
3287
pauldc63bfd2005-10-25 23:31:05 +00003288static void
paul216565a2005-10-25 23:35:28 +00003289rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003290{
3291 struct route_node *rn;
3292 struct rip_distance *rdistance;
3293
3294 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3295 if ((rdistance = rn->info) != NULL)
3296 {
3297 if (rdistance->access_list)
3298 free (rdistance->access_list);
3299 rip_distance_free (rdistance);
3300 rn->info = NULL;
3301 route_unlock_node (rn);
3302 }
3303}
3304
3305/* Apply RIP information to distance method. */
3306u_char
3307rip_distance_apply (struct rip_info *rinfo)
3308{
3309 struct route_node *rn;
3310 struct prefix_ipv4 p;
3311 struct rip_distance *rdistance;
3312 struct access_list *alist;
3313
3314 if (! rip)
3315 return 0;
3316
3317 memset (&p, 0, sizeof (struct prefix_ipv4));
3318 p.family = AF_INET;
3319 p.prefix = rinfo->from;
3320 p.prefixlen = IPV4_MAX_BITLEN;
3321
3322 /* Check source address. */
3323 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3324 if (rn)
3325 {
3326 rdistance = rn->info;
3327 route_unlock_node (rn);
3328
3329 if (rdistance->access_list)
3330 {
3331 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3332 if (alist == NULL)
3333 return 0;
3334 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3335 return 0;
3336
3337 return rdistance->distance;
3338 }
3339 else
3340 return rdistance->distance;
3341 }
3342
3343 if (rip->distance)
3344 return rip->distance;
3345
3346 return 0;
3347}
3348
pauldc63bfd2005-10-25 23:31:05 +00003349static void
paul718e3742002-12-13 20:15:29 +00003350rip_distance_show (struct vty *vty)
3351{
3352 struct route_node *rn;
3353 struct rip_distance *rdistance;
3354 int header = 1;
3355 char buf[BUFSIZ];
3356
3357 vty_out (vty, " Distance: (default is %d)%s",
3358 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3359 VTY_NEWLINE);
3360
3361 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3362 if ((rdistance = rn->info) != NULL)
3363 {
3364 if (header)
3365 {
3366 vty_out (vty, " Address Distance List%s",
3367 VTY_NEWLINE);
3368 header = 0;
3369 }
3370 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3371 vty_out (vty, " %-20s %4d %s%s",
3372 buf, rdistance->distance,
3373 rdistance->access_list ? rdistance->access_list : "",
3374 VTY_NEWLINE);
3375 }
3376}
3377
3378DEFUN (rip_distance,
3379 rip_distance_cmd,
3380 "distance <1-255>",
3381 "Administrative distance\n"
3382 "Distance value\n")
3383{
3384 rip->distance = atoi (argv[0]);
3385 return CMD_SUCCESS;
3386}
3387
3388DEFUN (no_rip_distance,
3389 no_rip_distance_cmd,
3390 "no distance <1-255>",
3391 NO_STR
3392 "Administrative distance\n"
3393 "Distance value\n")
3394{
3395 rip->distance = 0;
3396 return CMD_SUCCESS;
3397}
3398
3399DEFUN (rip_distance_source,
3400 rip_distance_source_cmd,
3401 "distance <1-255> A.B.C.D/M",
3402 "Administrative distance\n"
3403 "Distance value\n"
3404 "IP source prefix\n")
3405{
3406 rip_distance_set (vty, argv[0], argv[1], NULL);
3407 return CMD_SUCCESS;
3408}
3409
3410DEFUN (no_rip_distance_source,
3411 no_rip_distance_source_cmd,
3412 "no distance <1-255> A.B.C.D/M",
3413 NO_STR
3414 "Administrative distance\n"
3415 "Distance value\n"
3416 "IP source prefix\n")
3417{
3418 rip_distance_unset (vty, argv[0], argv[1], NULL);
3419 return CMD_SUCCESS;
3420}
3421
3422DEFUN (rip_distance_source_access_list,
3423 rip_distance_source_access_list_cmd,
3424 "distance <1-255> A.B.C.D/M WORD",
3425 "Administrative distance\n"
3426 "Distance value\n"
3427 "IP source prefix\n"
3428 "Access list name\n")
3429{
3430 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3431 return CMD_SUCCESS;
3432}
3433
3434DEFUN (no_rip_distance_source_access_list,
3435 no_rip_distance_source_access_list_cmd,
3436 "no distance <1-255> A.B.C.D/M WORD",
3437 NO_STR
3438 "Administrative distance\n"
3439 "Distance value\n"
3440 "IP source prefix\n"
3441 "Access list name\n")
3442{
3443 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3444 return CMD_SUCCESS;
3445}
David Lamparter6b0655a2014-06-04 06:53:35 +02003446
Lu Feng0b74a0a2014-07-18 06:13:19 +00003447/* Update ECMP routes to zebra when ECMP is disabled. */
3448static void
3449rip_ecmp_disable (void)
3450{
3451 struct route_node *rp;
3452 struct rip_info *rinfo, *tmp_rinfo;
3453 struct list *list;
3454 struct listnode *node, *nextnode;
3455
3456 if (!rip)
3457 return;
3458
3459 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3460 if ((list = rp->info) != NULL && listcount (list) > 1)
3461 {
3462 rinfo = listgetdata (listhead (list));
3463 if (!rip_route_rte (rinfo))
3464 continue;
3465
3466 /* Drop all other entries, except the first one. */
3467 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
3468 if (tmp_rinfo != rinfo)
3469 {
3470 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
3471 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
3472 list_delete_node (list, node);
3473 rip_info_free (tmp_rinfo);
3474 }
3475
3476 /* Update zebra. */
3477 rip_zebra_ipv4_add (rp);
3478
3479 /* Set the route change flag. */
3480 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
3481
3482 /* Signal the output process to trigger an update. */
3483 rip_event (RIP_TRIGGERED_UPDATE, 0);
3484 }
3485}
3486
3487DEFUN (rip_allow_ecmp,
3488 rip_allow_ecmp_cmd,
3489 "allow-ecmp",
3490 "Allow Equal Cost MultiPath\n")
3491{
3492 if (rip->ecmp)
3493 {
3494 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
3495 return CMD_WARNING;
3496 }
3497
3498 rip->ecmp = 1;
3499 zlog_info ("ECMP is enabled.");
3500 return CMD_SUCCESS;
3501}
3502
3503DEFUN (no_rip_allow_ecmp,
3504 no_rip_allow_ecmp_cmd,
3505 "no allow-ecmp",
3506 NO_STR
3507 "Allow Equal Cost MultiPath\n")
3508{
3509 if (!rip->ecmp)
3510 {
3511 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
3512 return CMD_WARNING;
3513 }
3514
3515 rip->ecmp = 0;
3516 zlog_info ("ECMP is disabled.");
3517 rip_ecmp_disable ();
3518 return CMD_SUCCESS;
3519}
3520
paul718e3742002-12-13 20:15:29 +00003521/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003522static void
paul718e3742002-12-13 20:15:29 +00003523rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3524{
paul718e3742002-12-13 20:15:29 +00003525 time_t clock;
3526 struct tm *tm;
3527#define TIME_BUF 25
3528 char timebuf [TIME_BUF];
3529 struct thread *thread;
3530
paul718e3742002-12-13 20:15:29 +00003531 if ((thread = rinfo->t_timeout) != NULL)
3532 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003533 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003534 tm = gmtime (&clock);
3535 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3536 vty_out (vty, "%5s", timebuf);
3537 }
3538 else if ((thread = rinfo->t_garbage_collect) != NULL)
3539 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003540 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003541 tm = gmtime (&clock);
3542 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3543 vty_out (vty, "%5s", timebuf);
3544 }
3545}
3546
pauldc63bfd2005-10-25 23:31:05 +00003547static const char *
paul718e3742002-12-13 20:15:29 +00003548rip_route_type_print (int sub_type)
3549{
3550 switch (sub_type)
3551 {
3552 case RIP_ROUTE_RTE:
3553 return "n";
3554 case RIP_ROUTE_STATIC:
3555 return "s";
3556 case RIP_ROUTE_DEFAULT:
3557 return "d";
3558 case RIP_ROUTE_REDISTRIBUTE:
3559 return "r";
3560 case RIP_ROUTE_INTERFACE:
3561 return "i";
3562 default:
3563 return "?";
3564 }
3565}
3566
3567DEFUN (show_ip_rip,
3568 show_ip_rip_cmd,
3569 "show ip rip",
3570 SHOW_STR
3571 IP_STR
3572 "Show RIP routes\n")
3573{
3574 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003575 struct rip_info *rinfo = NULL;
3576 struct list *list = NULL;
3577 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003578
3579 if (! rip)
3580 return CMD_SUCCESS;
3581
hasso16705132003-05-25 14:49:19 +00003582 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3583 "Sub-codes:%s"
3584 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003585 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003586 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003587 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003588
3589 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003590 if ((list = np->info) != NULL)
3591 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00003592 {
3593 int len;
3594
ajsf52d13c2005-10-01 17:38:06 +00003595 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003596 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003597 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003598 rip_route_type_print (rinfo->sub_type),
3599 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3600
hassoa1455d82004-03-03 19:36:24 +00003601 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003602
3603 if (len > 0)
3604 vty_out (vty, "%*s", len, " ");
3605
3606 if (rinfo->nexthop.s_addr)
3607 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3608 rinfo->metric);
3609 else
3610 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3611
3612 /* Route which exist in kernel routing table. */
3613 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3614 (rinfo->sub_type == RIP_ROUTE_RTE))
3615 {
3616 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003617 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003618 rip_vty_out_uptime (vty, rinfo);
3619 }
3620 else if (rinfo->metric == RIP_METRIC_INFINITY)
3621 {
3622 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003623 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003624 rip_vty_out_uptime (vty, rinfo);
3625 }
3626 else
hasso16705132003-05-25 14:49:19 +00003627 {
vincentfbf5d032005-09-29 11:25:50 +00003628 if (rinfo->external_metric)
3629 {
3630 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003631 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003632 rinfo->external_metric);
3633 len = 16 - len;
3634 if (len > 0)
3635 vty_out (vty, "%*s", len, " ");
3636 }
3637 else
3638 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003639 vty_out (vty, "%3d", rinfo->tag);
3640 }
paul718e3742002-12-13 20:15:29 +00003641
3642 vty_out (vty, "%s", VTY_NEWLINE);
3643 }
3644 return CMD_SUCCESS;
3645}
3646
hasso16705132003-05-25 14:49:19 +00003647/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3648DEFUN (show_ip_rip_status,
3649 show_ip_rip_status_cmd,
3650 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003651 SHOW_STR
3652 IP_STR
hasso16705132003-05-25 14:49:19 +00003653 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003654 "IP routing protocol process parameters and statistics\n")
3655{
hasso52dc7ee2004-09-23 19:18:23 +00003656 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003657 struct interface *ifp;
3658 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003659 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003660 const char *send_version;
3661 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003662
3663 if (! rip)
3664 return CMD_SUCCESS;
3665
3666 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3667 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3668 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003669 vty_out (vty, " next due in %lu seconds%s",
3670 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003671 VTY_NEWLINE);
3672 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3673 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3674 VTY_NEWLINE);
3675
3676 /* Filtering status show. */
3677 config_show_distribute (vty);
3678
3679 /* Default metric information. */
3680 vty_out (vty, " Default redistribution metric is %d%s",
3681 rip->default_metric, VTY_NEWLINE);
3682
3683 /* Redistribute information. */
3684 vty_out (vty, " Redistributing:");
3685 config_write_rip_redistribute (vty, 0);
3686 vty_out (vty, "%s", VTY_NEWLINE);
3687
paulf38a4712003-06-07 01:10:00 +00003688 vty_out (vty, " Default version control: send version %s,",
3689 lookup(ri_version_msg,rip->version_send));
3690 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3691 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3692 else
3693 vty_out (vty, " receive version %s %s",
3694 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003695
3696 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3697
paul1eb8ef22005-04-07 07:30:20 +00003698 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003699 {
paul718e3742002-12-13 20:15:29 +00003700 ri = ifp->info;
3701
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003702 if (!ri->running)
3703 continue;
3704
paul718e3742002-12-13 20:15:29 +00003705 if (ri->enable_network || ri->enable_interface)
3706 {
3707 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003708 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003709 else
3710 send_version = lookup (ri_version_msg, ri->ri_send);
3711
3712 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003713 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003714 else
3715 receive_version = lookup (ri_version_msg, ri->ri_receive);
3716
3717 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3718 send_version,
3719 receive_version,
3720 ri->key_chain ? ri->key_chain : "",
3721 VTY_NEWLINE);
3722 }
3723 }
3724
3725 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3726 config_write_rip_network (vty, 0);
3727
paul4aaff3f2003-06-07 01:04:45 +00003728 {
3729 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003730 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003731 {
paul4aaff3f2003-06-07 01:04:45 +00003732 ri = ifp->info;
3733
3734 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3735 {
3736 if (!found_passive)
3737 {
3738 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3739 found_passive = 1;
3740 }
3741 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3742 }
3743 }
3744 }
3745
paul718e3742002-12-13 20:15:29 +00003746 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3747 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3748 rip_peer_display (vty);
3749
3750 rip_distance_show (vty);
3751
3752 return CMD_SUCCESS;
3753}
3754
3755/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003756static int
paul718e3742002-12-13 20:15:29 +00003757config_write_rip (struct vty *vty)
3758{
3759 int write = 0;
3760 struct route_node *rn;
3761 struct rip_distance *rdistance;
3762
3763 if (rip)
3764 {
3765 /* Router RIP statement. */
3766 vty_out (vty, "router rip%s", VTY_NEWLINE);
3767 write++;
3768
3769 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003770 if (rip->version_send != RI_RIP_VERSION_2
3771 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3772 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003773 VTY_NEWLINE);
3774
3775 /* RIP timer configuration. */
3776 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3777 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3778 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3779 vty_out (vty, " timers basic %lu %lu %lu%s",
3780 rip->update_time,
3781 rip->timeout_time,
3782 rip->garbage_time,
3783 VTY_NEWLINE);
3784
3785 /* Default information configuration. */
3786 if (rip->default_information)
3787 {
3788 if (rip->default_information_route_map)
3789 vty_out (vty, " default-information originate route-map %s%s",
3790 rip->default_information_route_map, VTY_NEWLINE);
3791 else
3792 vty_out (vty, " default-information originate%s",
3793 VTY_NEWLINE);
3794 }
3795
3796 /* Redistribute configuration. */
3797 config_write_rip_redistribute (vty, 1);
3798
3799 /* RIP offset-list configuration. */
3800 config_write_rip_offset_list (vty);
3801
3802 /* RIP enabled network and interface configuration. */
3803 config_write_rip_network (vty, 1);
3804
3805 /* RIP default metric configuration */
3806 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3807 vty_out (vty, " default-metric %d%s",
3808 rip->default_metric, VTY_NEWLINE);
3809
3810 /* Distribute configuration. */
3811 write += config_write_distribute (vty);
3812
hasso16705132003-05-25 14:49:19 +00003813 /* Interface routemap configuration */
3814 write += config_write_if_rmap (vty);
3815
paul718e3742002-12-13 20:15:29 +00003816 /* Distance configuration. */
3817 if (rip->distance)
3818 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3819
3820 /* RIP source IP prefix distance configuration. */
3821 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3822 if ((rdistance = rn->info) != NULL)
3823 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3824 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3825 rdistance->access_list ? rdistance->access_list : "",
3826 VTY_NEWLINE);
3827
Lu Feng0b74a0a2014-07-18 06:13:19 +00003828 /* ECMP configuration. */
3829 if (rip->ecmp)
3830 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
3831
paul718e3742002-12-13 20:15:29 +00003832 /* RIP static route configuration. */
3833 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3834 if (rn->info)
3835 vty_out (vty, " route %s/%d%s",
3836 inet_ntoa (rn->p.u.prefix4),
3837 rn->p.prefixlen,
3838 VTY_NEWLINE);
3839
3840 }
3841 return write;
3842}
3843
3844/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003845static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003846{
3847 RIP_NODE,
3848 "%s(config-router)# ",
3849 1
3850};
David Lamparter6b0655a2014-06-04 06:53:35 +02003851
paul718e3742002-12-13 20:15:29 +00003852/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003853static void
paul718e3742002-12-13 20:15:29 +00003854rip_distribute_update (struct distribute *dist)
3855{
3856 struct interface *ifp;
3857 struct rip_interface *ri;
3858 struct access_list *alist;
3859 struct prefix_list *plist;
3860
3861 if (! dist->ifname)
3862 return;
3863
3864 ifp = if_lookup_by_name (dist->ifname);
3865 if (ifp == NULL)
3866 return;
3867
3868 ri = ifp->info;
3869
3870 if (dist->list[DISTRIBUTE_IN])
3871 {
3872 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3873 if (alist)
3874 ri->list[RIP_FILTER_IN] = alist;
3875 else
3876 ri->list[RIP_FILTER_IN] = NULL;
3877 }
3878 else
3879 ri->list[RIP_FILTER_IN] = NULL;
3880
3881 if (dist->list[DISTRIBUTE_OUT])
3882 {
3883 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3884 if (alist)
3885 ri->list[RIP_FILTER_OUT] = alist;
3886 else
3887 ri->list[RIP_FILTER_OUT] = NULL;
3888 }
3889 else
3890 ri->list[RIP_FILTER_OUT] = NULL;
3891
3892 if (dist->prefix[DISTRIBUTE_IN])
3893 {
3894 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3895 if (plist)
3896 ri->prefix[RIP_FILTER_IN] = plist;
3897 else
3898 ri->prefix[RIP_FILTER_IN] = NULL;
3899 }
3900 else
3901 ri->prefix[RIP_FILTER_IN] = NULL;
3902
3903 if (dist->prefix[DISTRIBUTE_OUT])
3904 {
3905 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3906 if (plist)
3907 ri->prefix[RIP_FILTER_OUT] = plist;
3908 else
3909 ri->prefix[RIP_FILTER_OUT] = NULL;
3910 }
3911 else
3912 ri->prefix[RIP_FILTER_OUT] = NULL;
3913}
3914
3915void
3916rip_distribute_update_interface (struct interface *ifp)
3917{
3918 struct distribute *dist;
3919
3920 dist = distribute_lookup (ifp->name);
3921 if (dist)
3922 rip_distribute_update (dist);
3923}
3924
3925/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003926/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003927static void
paul02ff83c2004-06-11 11:27:03 +00003928rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003929{
3930 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003931 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003932
paul1eb8ef22005-04-07 07:30:20 +00003933 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3934 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003935}
paul11dde9c2004-05-31 14:00:00 +00003936/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003937static void
paul11dde9c2004-05-31 14:00:00 +00003938rip_distribute_update_all_wrapper(struct access_list *notused)
3939{
paul02ff83c2004-06-11 11:27:03 +00003940 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003941}
David Lamparter6b0655a2014-06-04 06:53:35 +02003942
paul718e3742002-12-13 20:15:29 +00003943/* Delete all added rip route. */
3944void
paul216565a2005-10-25 23:35:28 +00003945rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003946{
3947 int i;
3948 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00003949 struct rip_info *rinfo = NULL;
3950 struct list *list = NULL;
3951 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003952
3953 if (rip)
3954 {
3955 /* Clear RIP routes */
3956 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00003957 if ((list = rp->info) != NULL)
3958 {
3959 rinfo = listgetdata (listhead (list));
3960 if (rip_route_rte (rinfo))
3961 rip_zebra_ipv4_delete (rp);
paul718e3742002-12-13 20:15:29 +00003962
Lu Fengb397cf42014-07-18 06:13:18 +00003963 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3964 {
3965 RIP_TIMER_OFF (rinfo->t_timeout);
3966 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3967 rip_info_free (rinfo);
3968 }
3969 list_delete (list);
3970 rp->info = NULL;
3971 route_unlock_node (rp);
3972 }
paul718e3742002-12-13 20:15:29 +00003973
3974 /* Cancel RIP related timers. */
3975 RIP_TIMER_OFF (rip->t_update);
3976 RIP_TIMER_OFF (rip->t_triggered_update);
3977 RIP_TIMER_OFF (rip->t_triggered_interval);
3978
3979 /* Cancel read thread. */
3980 if (rip->t_read)
3981 {
3982 thread_cancel (rip->t_read);
3983 rip->t_read = NULL;
3984 }
3985
3986 /* Close RIP socket. */
3987 if (rip->sock >= 0)
3988 {
3989 close (rip->sock);
3990 rip->sock = -1;
3991 }
3992
3993 /* Static RIP route configuration. */
3994 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3995 if (rp->info)
3996 {
3997 rp->info = NULL;
3998 route_unlock_node (rp);
3999 }
4000
4001 /* RIP neighbor configuration. */
4002 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
4003 if (rp->info)
4004 {
4005 rp->info = NULL;
4006 route_unlock_node (rp);
4007 }
4008
4009 /* Redistribute related clear. */
4010 if (rip->default_information_route_map)
4011 free (rip->default_information_route_map);
4012
4013 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4014 if (rip->route_map[i].name)
4015 free (rip->route_map[i].name);
4016
4017 XFREE (MTYPE_ROUTE_TABLE, rip->table);
4018 XFREE (MTYPE_ROUTE_TABLE, rip->route);
4019 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
4020
4021 XFREE (MTYPE_RIP, rip);
4022 rip = NULL;
4023 }
4024
4025 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00004026 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00004027 rip_offset_clean ();
4028 rip_interface_clean ();
4029 rip_distance_reset ();
4030 rip_redistribute_clean ();
4031}
4032
4033/* Reset all values to the default settings. */
4034void
paul216565a2005-10-25 23:35:28 +00004035rip_reset (void)
paul718e3742002-12-13 20:15:29 +00004036{
4037 /* Reset global counters. */
4038 rip_global_route_changes = 0;
4039 rip_global_queries = 0;
4040
4041 /* Call ripd related reset functions. */
4042 rip_debug_reset ();
4043 rip_route_map_reset ();
4044
4045 /* Call library reset functions. */
4046 vty_reset ();
4047 access_list_reset ();
4048 prefix_list_reset ();
4049
4050 distribute_list_reset ();
4051
4052 rip_interface_reset ();
4053 rip_distance_reset ();
4054
4055 rip_zclient_reset ();
4056}
4057
pauldc63bfd2005-10-25 23:31:05 +00004058static void
hasso16705132003-05-25 14:49:19 +00004059rip_if_rmap_update (struct if_rmap *if_rmap)
4060{
4061 struct interface *ifp;
4062 struct rip_interface *ri;
4063 struct route_map *rmap;
4064
4065 ifp = if_lookup_by_name (if_rmap->ifname);
4066 if (ifp == NULL)
4067 return;
4068
4069 ri = ifp->info;
4070
4071 if (if_rmap->routemap[IF_RMAP_IN])
4072 {
4073 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
4074 if (rmap)
4075 ri->routemap[IF_RMAP_IN] = rmap;
4076 else
4077 ri->routemap[IF_RMAP_IN] = NULL;
4078 }
4079 else
4080 ri->routemap[RIP_FILTER_IN] = NULL;
4081
4082 if (if_rmap->routemap[IF_RMAP_OUT])
4083 {
4084 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
4085 if (rmap)
4086 ri->routemap[IF_RMAP_OUT] = rmap;
4087 else
4088 ri->routemap[IF_RMAP_OUT] = NULL;
4089 }
4090 else
4091 ri->routemap[RIP_FILTER_OUT] = NULL;
4092}
4093
4094void
4095rip_if_rmap_update_interface (struct interface *ifp)
4096{
4097 struct if_rmap *if_rmap;
4098
4099 if_rmap = if_rmap_lookup (ifp->name);
4100 if (if_rmap)
4101 rip_if_rmap_update (if_rmap);
4102}
4103
pauldc63bfd2005-10-25 23:31:05 +00004104static void
hasso16705132003-05-25 14:49:19 +00004105rip_routemap_update_redistribute (void)
4106{
4107 int i;
4108
4109 if (rip)
4110 {
4111 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4112 {
4113 if (rip->route_map[i].name)
4114 rip->route_map[i].map =
4115 route_map_lookup_by_name (rip->route_map[i].name);
4116 }
4117 }
4118}
4119
paul11dde9c2004-05-31 14:00:00 +00004120/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00004121static void
hasso98b718a2004-10-11 12:57:57 +00004122rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00004123{
4124 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00004125 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00004126
paul1eb8ef22005-04-07 07:30:20 +00004127 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
4128 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00004129
4130 rip_routemap_update_redistribute ();
4131}
4132
paul718e3742002-12-13 20:15:29 +00004133/* Allocate new rip structure and set default value. */
4134void
pauldc63bfd2005-10-25 23:31:05 +00004135rip_init (void)
paul718e3742002-12-13 20:15:29 +00004136{
4137 /* Randomize for triggered update random(). */
Donald Sharpf31bab42015-06-19 19:26:19 -04004138 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00004139
4140 /* Install top nodes. */
4141 install_node (&rip_node, config_write_rip);
4142
4143 /* Install rip commands. */
4144 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004145 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004146 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004147 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004148 install_element (CONFIG_NODE, &router_rip_cmd);
4149 install_element (CONFIG_NODE, &no_router_rip_cmd);
4150
4151 install_default (RIP_NODE);
4152 install_element (RIP_NODE, &rip_version_cmd);
4153 install_element (RIP_NODE, &no_rip_version_cmd);
4154 install_element (RIP_NODE, &no_rip_version_val_cmd);
4155 install_element (RIP_NODE, &rip_default_metric_cmd);
4156 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4157 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4158 install_element (RIP_NODE, &rip_timers_cmd);
4159 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004160 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004161 install_element (RIP_NODE, &rip_route_cmd);
4162 install_element (RIP_NODE, &no_rip_route_cmd);
4163 install_element (RIP_NODE, &rip_distance_cmd);
4164 install_element (RIP_NODE, &no_rip_distance_cmd);
4165 install_element (RIP_NODE, &rip_distance_source_cmd);
4166 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4167 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4168 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
Lu Feng0b74a0a2014-07-18 06:13:19 +00004169 install_element (RIP_NODE, &rip_allow_ecmp_cmd);
4170 install_element (RIP_NODE, &no_rip_allow_ecmp_cmd);
paul718e3742002-12-13 20:15:29 +00004171
4172 /* Debug related init. */
4173 rip_debug_init ();
4174
paul718e3742002-12-13 20:15:29 +00004175 /* SNMP init. */
4176#ifdef HAVE_SNMP
4177 rip_snmp_init ();
4178#endif /* HAVE_SNMP */
4179
4180 /* Access list install. */
4181 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004182 access_list_add_hook (rip_distribute_update_all_wrapper);
4183 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004184
4185 /* Prefix list initialize.*/
4186 prefix_list_init ();
4187 prefix_list_add_hook (rip_distribute_update_all);
4188 prefix_list_delete_hook (rip_distribute_update_all);
4189
4190 /* Distribute list install. */
4191 distribute_list_init (RIP_NODE);
4192 distribute_list_add_hook (rip_distribute_update);
4193 distribute_list_delete_hook (rip_distribute_update);
4194
hasso16705132003-05-25 14:49:19 +00004195 /* Route-map */
4196 rip_route_map_init ();
4197 rip_offset_init ();
4198
4199 route_map_add_hook (rip_routemap_update);
4200 route_map_delete_hook (rip_routemap_update);
4201
4202 if_rmap_init (RIP_NODE);
4203 if_rmap_hook_add (rip_if_rmap_update);
4204 if_rmap_hook_delete (rip_if_rmap_update);
4205
paul718e3742002-12-13 20:15:29 +00004206 /* Distance control. */
4207 rip_distance_table = route_table_init ();
4208}