blob: a5bc067a91e843173857f671da4c729dae571446 [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
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200318rip_filter (int rip_distribute, struct prefix_ipv4 *p, struct rip_interface *ri)
paul718e3742002-12-13 20:15:29 +0000319{
320 struct distribute *dist;
321 struct access_list *alist;
322 struct prefix_list *plist;
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200323 int distribute = rip_distribute == RIP_FILTER_OUT ?
Matthieu Boutierdf2ef242014-09-10 16:50:45 +0200324 DISTRIBUTE_V4_OUT : DISTRIBUTE_V4_IN;
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200325 const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in";
paul718e3742002-12-13 20:15:29 +0000326
327 /* Input distribute-list filtering. */
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200328 if (ri->list[rip_distribute])
paul718e3742002-12-13 20:15:29 +0000329 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200330 if (access_list_apply (ri->list[rip_distribute],
paul718e3742002-12-13 20:15:29 +0000331 (struct prefix *) p) == FILTER_DENY)
332 {
333 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200334 zlog_debug ("%s/%d filtered by distribute %s",
335 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000336 return -1;
337 }
338 }
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200339 if (ri->prefix[rip_distribute])
paul718e3742002-12-13 20:15:29 +0000340 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200341 if (prefix_list_apply (ri->prefix[rip_distribute],
paul718e3742002-12-13 20:15:29 +0000342 (struct prefix *) p) == PREFIX_DENY)
343 {
344 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200345 zlog_debug ("%s/%d filtered by prefix-list %s",
346 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000347 return -1;
348 }
349 }
350
351 /* All interface filter check. */
352 dist = distribute_lookup (NULL);
353 if (dist)
354 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200355 if (dist->list[distribute])
paul718e3742002-12-13 20:15:29 +0000356 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200357 alist = access_list_lookup (AFI_IP, dist->list[distribute]);
358
paul718e3742002-12-13 20:15:29 +0000359 if (alist)
360 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200361 if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY)
paul718e3742002-12-13 20:15:29 +0000362 {
363 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200364 zlog_debug ("%s/%d filtered by distribute %s",
365 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000366 return -1;
367 }
368 }
369 }
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200370 if (dist->prefix[distribute])
paul718e3742002-12-13 20:15:29 +0000371 {
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200372 plist = prefix_list_lookup (AFI_IP, dist->prefix[distribute]);
373
paul718e3742002-12-13 20:15:29 +0000374 if (plist)
375 {
376 if (prefix_list_apply (plist,
377 (struct prefix *) p) == PREFIX_DENY)
378 {
379 if (IS_RIP_DEBUG_PACKET)
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200380 zlog_debug ("%s/%d filtered by prefix-list %s",
381 inet_ntoa (p->prefix), p->prefixlen, inout);
paul718e3742002-12-13 20:15:29 +0000382 return -1;
383 }
384 }
385 }
386 }
387 return 0;
388}
389
390/* Check nexthop address validity. */
391static int
392rip_nexthop_check (struct in_addr *addr)
393{
hasso52dc7ee2004-09-23 19:18:23 +0000394 struct listnode *node;
395 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000396 struct interface *ifp;
397 struct connected *ifc;
398 struct prefix *p;
399
400 /* If nexthop address matches local configured address then it is
401 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000402 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000403 {
paul1eb8ef22005-04-07 07:30:20 +0000404 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000405 {
paul718e3742002-12-13 20:15:29 +0000406 p = ifc->address;
407
408 if (p->family == AF_INET
409 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
410 return -1;
411 }
412 }
413 return 0;
414}
415
416/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000417static void
paul718e3742002-12-13 20:15:29 +0000418rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000419 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000420{
421 int ret;
422 struct prefix_ipv4 p;
423 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +0000424 struct rip_info *rinfo = NULL, newinfo;
paul718e3742002-12-13 20:15:29 +0000425 struct rip_interface *ri;
426 struct in_addr *nexthop;
paul718e3742002-12-13 20:15:29 +0000427 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000428 unsigned char old_dist, new_dist;
Lu Fengb397cf42014-07-18 06:13:18 +0000429 struct list *list = NULL;
430 struct listnode *node = NULL;
paul718e3742002-12-13 20:15:29 +0000431
432 /* Make prefix structure. */
433 memset (&p, 0, sizeof (struct prefix_ipv4));
434 p.family = AF_INET;
435 p.prefix = rte->prefix;
436 p.prefixlen = ip_masklen (rte->mask);
437
438 /* Make sure mask is applied. */
439 apply_mask_ipv4 (&p);
440
441 /* Apply input filters. */
442 ri = ifp->info;
443
Matthieu Boutierfafa8992014-09-10 16:50:43 +0200444 ret = rip_filter (RIP_FILTER_IN, &p, ri);
paul718e3742002-12-13 20:15:29 +0000445 if (ret < 0)
446 return;
447
Lu Fengb397cf42014-07-18 06:13:18 +0000448 memset (&newinfo, 0, sizeof (newinfo));
449 newinfo.type = ZEBRA_ROUTE_RIP;
450 newinfo.sub_type = RIP_ROUTE_RTE;
451 newinfo.nexthop = rte->nexthop;
452 newinfo.from = from->sin_addr;
453 newinfo.ifindex = ifp->ifindex;
454 newinfo.metric = rte->metric;
455 newinfo.metric_out = rte->metric; /* XXX */
456 newinfo.tag = ntohs (rte->tag); /* XXX */
457
hasso16705132003-05-25 14:49:19 +0000458 /* Modify entry according to the interface routemap. */
459 if (ri->routemap[RIP_FILTER_IN])
460 {
461 int ret;
hasso16705132003-05-25 14:49:19 +0000462
463 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000464 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
465 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000466
467 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000468 {
469 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000470 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000471 inet_ntoa (p.prefix), p.prefixlen);
472 return;
473 }
hasso16705132003-05-25 14:49:19 +0000474
475 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000476 rte->nexthop = newinfo.nexthop_out;
477 rte->tag = htons (newinfo.tag_out); /* XXX */
478 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000479 }
480
paul718e3742002-12-13 20:15:29 +0000481 /* Once the entry has been validated, update the metric by
482 adding the cost of the network on wich the message
483 arrived. If the result is greater than infinity, use infinity
484 (RFC2453 Sec. 3.9.2) */
485 /* Zebra ripd can handle offset-list in. */
486 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
487
488 /* If offset-list does not modify the metric use interface's
489 metric. */
paula87552c2004-05-03 20:00:17 +0000490 if (!ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000491 rte->metric += ifp->metric ? ifp->metric : 1;
paul718e3742002-12-13 20:15:29 +0000492
493 if (rte->metric > RIP_METRIC_INFINITY)
494 rte->metric = RIP_METRIC_INFINITY;
495
496 /* Set nexthop pointer. */
497 if (rte->nexthop.s_addr == 0)
498 nexthop = &from->sin_addr;
499 else
500 nexthop = &rte->nexthop;
501
hasso16705132003-05-25 14:49:19 +0000502 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000503 if (rip_nexthop_check (nexthop) < 0)
504 {
505 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000506 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000507 return;
508 }
509
510 /* Get index for the prefix. */
511 rp = route_node_get (rip->table, (struct prefix *) &p);
512
Lu Fengb397cf42014-07-18 06:13:18 +0000513 newinfo.rp = rp;
514 newinfo.nexthop = *nexthop;
515 newinfo.metric = rte->metric;
516 newinfo.tag = ntohs (rte->tag);
517 newinfo.distance = rip_distance_apply (&newinfo);
518
519 new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT;
520
paul718e3742002-12-13 20:15:29 +0000521 /* Check to see whether there is already RIP route on the table. */
Lu Fengb397cf42014-07-18 06:13:18 +0000522 if ((list = rp->info) != NULL)
523 for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
524 {
525 /* Need to compare with redistributed entry or local entry */
526 if (!rip_route_rte (rinfo))
527 break;
528
529 if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) &&
530 IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
531 break;
532
533 if (!listnextnode (node))
534 {
535 /* Not found in the list */
536
537 if (rte->metric > rinfo->metric)
538 {
539 /* New route has a greater metric. Discard it. */
540 route_unlock_node (rp);
541 return;
542 }
543
544 if (rte->metric < rinfo->metric)
545 /* New route has a smaller metric. Replace the ECMP list
546 * with the new one in below. */
547 break;
548
549 /* Metrics are same. We compare the distances. */
550 old_dist = rinfo->distance ? \
551 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
552
553 if (new_dist > old_dist)
554 {
555 /* New route has a greater distance. Discard it. */
556 route_unlock_node (rp);
557 return;
558 }
559
560 if (new_dist < old_dist)
561 /* New route has a smaller distance. Replace the ECMP list
562 * with the new one in below. */
563 break;
564
565 /* Metrics and distances are both same. Keep "rinfo" null and
566 * the new route is added in the ECMP list in below. */
567 }
568 }
paul718e3742002-12-13 20:15:29 +0000569
570 if (rinfo)
571 {
paul718e3742002-12-13 20:15:29 +0000572 /* Local static route. */
573 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000574 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
575 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
576 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000577 {
578 route_unlock_node (rp);
579 return;
580 }
581
582 /* Redistributed route check. */
583 if (rinfo->type != ZEBRA_ROUTE_RIP
584 && rinfo->metric != RIP_METRIC_INFINITY)
585 {
vincentfbf5d032005-09-29 11:25:50 +0000586 old_dist = rinfo->distance;
David Lamparterb68da442013-02-28 22:17:00 +0100587 /* Only routes directly connected to an interface (nexthop == 0)
588 * may have a valid NULL distance */
589 if (rinfo->nexthop.s_addr != 0)
vincent7a383332006-01-30 18:12:42 +0000590 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000591 /* If imported route does not have STRICT precedence,
592 mark it as a ghost */
Lu Fengb397cf42014-07-18 06:13:18 +0000593 if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY)
594 rip_ecmp_replace (&newinfo);
595
596 route_unlock_node (rp);
597 return;
vincentfbf5d032005-09-29 11:25:50 +0000598 }
paul718e3742002-12-13 20:15:29 +0000599 }
paula87552c2004-05-03 20:00:17 +0000600
601 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000602 {
Lu Fengb397cf42014-07-18 06:13:18 +0000603 if (rp->info)
604 route_unlock_node (rp);
605
paul718e3742002-12-13 20:15:29 +0000606 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000607 for the destination prefix. If there is no such route, add
608 this route to the routing table, unless the metric is
609 infinity (there is no point in adding a route which
610 unusable). */
paul718e3742002-12-13 20:15:29 +0000611 if (rte->metric != RIP_METRIC_INFINITY)
Lu Fengb397cf42014-07-18 06:13:18 +0000612 rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +0000613 }
614 else
615 {
616 /* Route is there but we are not sure the route is RIP or not. */
paula87552c2004-05-03 20:00:17 +0000617
paul718e3742002-12-13 20:15:29 +0000618 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000619 to the address of the router from which the datagram came.
620 If this datagram is from the same router as the existing
621 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000622 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000623 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000624
Lu Fengb397cf42014-07-18 06:13:18 +0000625 old_dist = rinfo->distance ? \
626 rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT;
paulb94f9db2004-05-01 20:45:38 +0000627
paul718e3742002-12-13 20:15:29 +0000628 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000629 router as the existing route, and the new metric is different
630 than the old one; or, if the new metric is lower than the old
631 one, or if the tag has been changed; or if there is a route
632 with a lower administrave distance; or an update of the
633 distance on the actual route; do the following actions: */
634 if ((same && rinfo->metric != rte->metric)
635 || (rte->metric < rinfo->metric)
636 || ((same)
637 && (rinfo->metric == rte->metric)
Lu Fengb397cf42014-07-18 06:13:18 +0000638 && (newinfo.tag != rinfo->tag))
639 || (old_dist > new_dist)
640 || ((old_dist != new_dist) && same))
paula87552c2004-05-03 20:00:17 +0000641 {
Lu Fengb397cf42014-07-18 06:13:18 +0000642 if (listcount (list) == 1)
paula87552c2004-05-03 20:00:17 +0000643 {
Lu Fengb397cf42014-07-18 06:13:18 +0000644 if (newinfo.metric != RIP_METRIC_INFINITY)
645 rip_ecmp_replace (&newinfo);
646 else
647 rip_ecmp_delete (rinfo);
paula87552c2004-05-03 20:00:17 +0000648 }
649 else
650 {
Lu Fengb397cf42014-07-18 06:13:18 +0000651 if (newinfo.metric < rinfo->metric)
652 rip_ecmp_replace (&newinfo);
653 else if (newinfo.metric > rinfo->metric)
654 rip_ecmp_delete (rinfo);
655 else if (new_dist < old_dist)
656 rip_ecmp_replace (&newinfo);
657 else if (new_dist > old_dist)
658 rip_ecmp_delete (rinfo);
659 else
660 {
661 int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0;
662
663 assert (newinfo.metric != RIP_METRIC_INFINITY);
664
665 RIP_TIMER_OFF (rinfo->t_timeout);
666 RIP_TIMER_OFF (rinfo->t_garbage_collect);
667 memcpy (rinfo, &newinfo, sizeof (struct rip_info));
668 rip_timeout_update (rinfo);
669
670 if (update)
671 rip_zebra_ipv4_add (rp);
672
673 /* - Set the route change flag on the first entry. */
674 rinfo = listgetdata (listhead (list));
675 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
676 rip_event (RIP_TRIGGERED_UPDATE, 0);
677 }
paula87552c2004-05-03 20:00:17 +0000678 }
679 }
Lu Fengb397cf42014-07-18 06:13:18 +0000680 else /* same & no change */
681 rip_timeout_update (rinfo);
682
paul718e3742002-12-13 20:15:29 +0000683 /* Unlock tempolary lock of the route. */
684 route_unlock_node (rp);
685 }
686}
687
688/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000689static void
hasso8a676be2004-10-08 06:36:38 +0000690rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000691{
692 caddr_t lim;
693 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000694 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000695 char pbuf[BUFSIZ], nbuf[BUFSIZ];
696 u_char netmask = 0;
697 u_char *p;
698
699 /* Set command string. */
700 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
701 command_str = lookup (rip_msg, packet->command);
702 else
703 command_str = "unknown";
704
705 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000706 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000707 sndrcv, command_str, packet->version, size);
708
709 /* Dump each routing table entry. */
710 rte = packet->rte;
711
712 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
713 {
714 if (packet->version == RIPv2)
715 {
716 netmask = ip_masklen (rte->mask);
717
paulca5e5162004-06-06 22:06:33 +0000718 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000719 {
paulca5e5162004-06-06 22:06:33 +0000720 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000721 {
722 p = (u_char *)&rte->prefix;
723
ajs5d6c3772004-12-08 19:24:06 +0000724 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000725 ntohs (rte->family), ntohs (rte->tag), p);
726 }
paulca5e5162004-06-06 22:06:33 +0000727 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000728 {
729 struct rip_md5_info *md5;
730
731 md5 = (struct rip_md5_info *) &packet->rte;
732
ajs5d6c3772004-12-08 19:24:06 +0000733 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000734 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000735 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000736 " Auth Data len %d",
737 ntohs (md5->packet_len), md5->keyid,
738 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000739 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000740 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000741 }
paulca5e5162004-06-06 22:06:33 +0000742 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000743 {
744 p = (u_char *)&rte->prefix;
745
ajs5d6c3772004-12-08 19:24:06 +0000746 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000747 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000748 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000749 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000750 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
751 p[7], p[9], p[10], p[11], p[12], p[13],
752 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000753 }
754 else
755 {
ajs5d6c3772004-12-08 19:24:06 +0000756 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000757 ntohs (rte->family), ntohs (rte->tag));
758 }
759 }
760 else
ajs5d6c3772004-12-08 19:24:06 +0000761 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000762 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
763 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
764 BUFSIZ), ntohs (rte->family),
765 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000766 }
767 else
768 {
ajs5d6c3772004-12-08 19:24:06 +0000769 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000770 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
771 ntohs (rte->family), ntohs (rte->tag),
772 (u_long)ntohl (rte->metric));
773 }
774 }
775}
776
777/* Check if the destination address is valid (unicast; not net 0
778 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
779 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000780static int
paul718e3742002-12-13 20:15:29 +0000781rip_destination_check (struct in_addr addr)
782{
783 u_int32_t destination;
784
785 /* Convert to host byte order. */
786 destination = ntohl (addr.s_addr);
787
788 if (IPV4_NET127 (destination))
789 return 0;
790
791 /* Net 0 may match to the default route. */
792 if (IPV4_NET0 (destination) && destination != 0)
793 return 0;
794
795 /* Unicast address must belong to class A, B, C. */
796 if (IN_CLASSA (destination))
797 return 1;
798 if (IN_CLASSB (destination))
799 return 1;
800 if (IN_CLASSC (destination))
801 return 1;
802
803 return 0;
804}
805
806/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000807static int
paul718e3742002-12-13 20:15:29 +0000808rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
809 struct interface *ifp)
810{
811 struct rip_interface *ri;
812 char *auth_str;
813
814 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000815 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000816 inet_ntoa (from->sin_addr));
817
818 ri = ifp->info;
819
820 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000821 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000822 return 0;
823
824 /* Simple password authentication. */
825 if (ri->auth_str)
826 {
827 auth_str = (char *) &rte->prefix;
828
829 if (strncmp (auth_str, ri->auth_str, 16) == 0)
830 return 1;
831 }
832 if (ri->key_chain)
833 {
834 struct keychain *keychain;
835 struct key *key;
836
837 keychain = keychain_lookup (ri->key_chain);
838 if (keychain == NULL)
839 return 0;
840
841 key = key_match_for_accept (keychain, (char *) &rte->prefix);
842 if (key)
843 return 1;
844 }
845 return 0;
846}
847
848/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000849static int
paul718e3742002-12-13 20:15:29 +0000850rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000851 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000852{
853 struct rip_interface *ri;
854 struct rip_md5_info *md5;
855 struct rip_md5_data *md5data;
856 struct keychain *keychain;
857 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000858 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000859 u_char digest[RIP_AUTH_MD5_SIZE];
860 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000861 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000862
863 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000864 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000865 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000866
867 ri = ifp->info;
868 md5 = (struct rip_md5_info *) &packet->rte;
869
870 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000871 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000872 return 0;
873
paulca5e5162004-06-06 22:06:33 +0000874 /* If the authentication length is less than 16, then it must be wrong for
875 * any interpretation of rfc2082. Some implementations also interpret
876 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000877 */
paulca5e5162004-06-06 22:06:33 +0000878 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
879 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000880 {
881 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000882 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000883 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000884 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000885 }
paul718e3742002-12-13 20:15:29 +0000886
paulca5e5162004-06-06 22:06:33 +0000887 /* grab and verify check packet length */
888 packet_len = ntohs (md5->packet_len);
889
890 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
891 {
892 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000893 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000894 "greater than received length %d!",
895 md5->packet_len, length);
896 return 0;
897 }
898
899 /* retrieve authentication data */
900 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000901
902 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000903
paul718e3742002-12-13 20:15:29 +0000904 if (ri->key_chain)
905 {
906 keychain = keychain_lookup (ri->key_chain);
907 if (keychain == NULL)
908 return 0;
909
910 key = key_lookup_for_accept (keychain, md5->keyid);
911 if (key == NULL)
912 return 0;
913
paul98fd1e62006-01-17 17:26:25 +0000914 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000915 }
paul98fd1e62006-01-17 17:26:25 +0000916 else if (ri->auth_str)
917 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000918
Paul Jakmafa93b162008-05-29 19:03:08 +0000919 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000920 return 0;
paul98fd1e62006-01-17 17:26:25 +0000921
paul718e3742002-12-13 20:15:29 +0000922 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000923 memset (&ctx, 0, sizeof(ctx));
924 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000925 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
926 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000927 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000928
929 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000930 return packet_len;
931 else
932 return 0;
933}
934
paulb14ee002005-02-04 23:42:41 +0000935/* Pick correct auth string for sends, prepare auth_str buffer for use.
936 * (left justified and padded).
937 *
938 * presumes one of ri or key is valid, and that the auth strings they point
939 * to are nul terminated. If neither are present, auth_str will be fully
940 * zero padded.
941 *
942 */
943static void
944rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
945 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +0000946{
paulb14ee002005-02-04 23:42:41 +0000947 assert (ri || key);
paul718e3742002-12-13 20:15:29 +0000948
paulb14ee002005-02-04 23:42:41 +0000949 memset (auth_str, 0, len);
950 if (key && key->string)
951 strncpy (auth_str, key->string, len);
952 else if (ri->auth_str)
953 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +0000954
paulb14ee002005-02-04 23:42:41 +0000955 return;
956}
paul718e3742002-12-13 20:15:29 +0000957
paulb14ee002005-02-04 23:42:41 +0000958/* Write RIPv2 simple password authentication information
959 *
960 * auth_str is presumed to be 2 bytes and correctly prepared
961 * (left justified and zero padded).
962 */
963static void
964rip_auth_simple_write (struct stream *s, char *auth_str, int len)
965{
966 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +0000967
paulb14ee002005-02-04 23:42:41 +0000968 stream_putw (s, RIP_FAMILY_AUTH);
969 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
970 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
971
972 return;
973}
974
975/* write RIPv2 MD5 "authentication header"
976 * (uses the auth key data field)
977 *
978 * Digest offset field is set to 0.
979 *
980 * returns: offset of the digest offset field, which must be set when
981 * length to the auth-data MD5 digest is known.
982 */
983static size_t
984rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
985 struct key *key)
986{
paul98fd1e62006-01-17 17:26:25 +0000987 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +0000988
989 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +0000990
991 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +0000992 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +0000993 stream_putw (s, RIP_AUTH_MD5);
994
paulb14ee002005-02-04 23:42:41 +0000995 /* MD5 AH digest offset field.
996 *
997 * Set to placeholder value here, to true value when RIP-2 Packet length
998 * is known. Actual value is set in .....().
999 */
paul98fd1e62006-01-17 17:26:25 +00001000 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001001 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001002
1003 /* Key ID. */
1004 if (key)
1005 stream_putc (s, key->index % 256);
1006 else
1007 stream_putc (s, 1);
1008
paulca5e5162004-06-06 22:06:33 +00001009 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1010 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1011 * to be configurable.
1012 */
1013 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001014
1015 /* Sequence Number (non-decreasing). */
1016 /* RFC2080: The value used in the sequence number is
1017 arbitrary, but two suggestions are the time of the
1018 message's creation or a simple message counter. */
1019 stream_putl (s, time (NULL));
1020
1021 /* Reserved field must be zero. */
1022 stream_putl (s, 0);
1023 stream_putl (s, 0);
1024
paul98fd1e62006-01-17 17:26:25 +00001025 return doff;
paulb14ee002005-02-04 23:42:41 +00001026}
paul718e3742002-12-13 20:15:29 +00001027
paulb14ee002005-02-04 23:42:41 +00001028/* If authentication is in used, write the appropriate header
1029 * returns stream offset to which length must later be written
1030 * or 0 if this is not required
1031 */
1032static size_t
1033rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1034 struct key *key, char *auth_str, int len)
1035{
1036 assert (ri->auth_type != RIP_NO_AUTH);
1037
1038 switch (ri->auth_type)
1039 {
1040 case RIP_AUTH_SIMPLE_PASSWORD:
1041 rip_auth_prepare_str_send (ri, key, auth_str, len);
1042 rip_auth_simple_write (s, auth_str, len);
1043 return 0;
1044 case RIP_AUTH_MD5:
1045 return rip_auth_md5_ah_write (s, ri, key);
1046 }
1047 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001048 return 0;
paulb14ee002005-02-04 23:42:41 +00001049}
1050
1051/* Write RIPv2 MD5 authentication data trailer */
1052static void
1053rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1054 char *auth_str, int authlen)
1055{
1056 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001057 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001058 unsigned char digest[RIP_AUTH_MD5_SIZE];
1059
1060 /* Make it sure this interface is configured as MD5
1061 authentication. */
1062 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1063 assert (doff > 0);
1064
1065 /* Get packet length. */
1066 len = stream_get_endp(s);
1067
1068 /* Check packet length. */
1069 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1070 {
1071 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1072 return;
1073 }
1074
1075 /* Set the digest offset length in the header */
1076 stream_putw_at (s, doff, len);
1077
paul718e3742002-12-13 20:15:29 +00001078 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001079 stream_putw (s, RIP_FAMILY_AUTH);
1080 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001081
1082 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001083 memset(&ctx, 0, sizeof(ctx));
1084 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001085 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001086 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1087 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001088
1089 /* Copy the digest to the packet. */
1090 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1091}
1092
1093/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001094static void
paul718e3742002-12-13 20:15:29 +00001095rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001096 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001097{
1098 caddr_t lim;
1099 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001100 struct prefix_ipv4 ifaddr;
1101 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001102 int subnetted;
Donald Sharp26a18eb2015-09-29 09:25:10 -04001103
1104 memset(&ifaddr, 0, sizeof(ifaddr));
paul727d1042002-12-13 20:50:29 +00001105 /* We don't know yet. */
1106 subnetted = -1;
1107
paul718e3742002-12-13 20:15:29 +00001108 /* The Response must be ignored if it is not from the RIP
1109 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001110 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001111 {
1112 zlog_info ("response doesn't come from RIP port: %d",
1113 from->sin_port);
1114 rip_peer_bad_packet (from);
1115 return;
1116 }
1117
1118 /* The datagram's IPv4 source address should be checked to see
1119 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001120 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1121 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001122 {
1123 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1124 inet_ntoa (from->sin_addr));
1125 rip_peer_bad_packet (from);
1126 return;
1127 }
1128
1129 /* It is also worth checking to see whether the response is from one
1130 of the router's own addresses. */
1131
1132 ; /* Alredy done in rip_read () */
1133
1134 /* Update RIP peer. */
1135 rip_peer_update (from, packet->version);
1136
1137 /* Set RTE pointer. */
1138 rte = packet->rte;
1139
1140 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1141 {
1142 /* RIPv2 authentication check. */
1143 /* If the Address Family Identifier of the first (and only the
1144 first) entry in the message is 0xFFFF, then the remainder of
1145 the entry contains the authentication. */
1146 /* If the packet gets here it means authentication enabled */
1147 /* Check is done in rip_read(). So, just skipping it */
1148 if (packet->version == RIPv2 &&
1149 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001150 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001151 continue;
1152
paulca5e5162004-06-06 22:06:33 +00001153 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001154 {
1155 /* Address family check. RIP only supports AF_INET. */
1156 zlog_info ("Unsupported family %d from %s.",
1157 ntohs (rte->family), inet_ntoa (from->sin_addr));
1158 continue;
1159 }
1160
1161 /* - is the destination address valid (e.g., unicast; not net 0
1162 or 127) */
1163 if (! rip_destination_check (rte->prefix))
1164 {
1165 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1166 rip_peer_bad_route (from);
1167 continue;
1168 }
1169
1170 /* Convert metric value to host byte order. */
1171 rte->metric = ntohl (rte->metric);
1172
1173 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1174 if (! (rte->metric >= 1 && rte->metric <= 16))
1175 {
1176 zlog_info ("Route's metric is not in the 1-16 range.");
1177 rip_peer_bad_route (from);
1178 continue;
1179 }
1180
1181 /* RIPv1 does not have nexthop value. */
1182 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1183 {
1184 zlog_info ("RIPv1 packet with nexthop value %s",
1185 inet_ntoa (rte->nexthop));
1186 rip_peer_bad_route (from);
1187 continue;
1188 }
1189
1190 /* That is, if the provided information is ignored, a possibly
1191 sub-optimal, but absolutely valid, route may be taken. If
1192 the received Next Hop is not directly reachable, it should be
1193 treated as 0.0.0.0. */
1194 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1195 {
1196 u_int32_t addrval;
1197
1198 /* Multicast address check. */
1199 addrval = ntohl (rte->nexthop.s_addr);
1200 if (IN_CLASSD (addrval))
1201 {
1202 zlog_info ("Nexthop %s is multicast address, skip this rte",
1203 inet_ntoa (rte->nexthop));
1204 continue;
1205 }
1206
1207 if (! if_lookup_address (rte->nexthop))
1208 {
1209 struct route_node *rn;
1210 struct rip_info *rinfo;
1211
1212 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1213
1214 if (rn)
1215 {
1216 rinfo = rn->info;
1217
1218 if (rinfo->type == ZEBRA_ROUTE_RIP
1219 && rinfo->sub_type == RIP_ROUTE_RTE)
1220 {
1221 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001222 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 +00001223 rte->nexthop = rinfo->from;
1224 }
1225 else
1226 {
1227 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001228 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 +00001229 rte->nexthop.s_addr = 0;
1230 }
1231
1232 route_unlock_node (rn);
1233 }
1234 else
1235 {
1236 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001237 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 +00001238 rte->nexthop.s_addr = 0;
1239 }
1240
1241 }
1242 }
1243
1244 /* For RIPv1, there won't be a valid netmask.
1245
1246 This is a best guess at the masks. If everyone was using old
1247 Ciscos before the 'ip subnet zero' option, it would be almost
1248 right too :-)
1249
1250 Cisco summarize ripv1 advertisments to the classful boundary
1251 (/16 for class B's) except when the RIP packet does to inside
1252 the classful network in question. */
1253
1254 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1255 || (packet->version == RIPv2
1256 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1257 {
1258 u_int32_t destination;
1259
paul727d1042002-12-13 20:50:29 +00001260 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001261 {
1262 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1263 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1264 apply_classful_mask_ipv4 (&ifaddrclass);
1265 subnetted = 0;
1266 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1267 subnetted = 1;
1268 }
paul727d1042002-12-13 20:50:29 +00001269
paul718e3742002-12-13 20:15:29 +00001270 destination = ntohl (rte->prefix.s_addr);
1271
paul727d1042002-12-13 20:50:29 +00001272 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001273 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001274 else if (IN_CLASSB (destination))
1275 masklen2ip (16, &rte->mask);
1276 else if (IN_CLASSC (destination))
1277 masklen2ip (24, &rte->mask);
1278
1279 if (subnetted == 1)
1280 masklen2ip (ifaddrclass.prefixlen,
1281 (struct in_addr *) &destination);
1282 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1283 ifaddrclass.prefix.s_addr))
1284 {
1285 masklen2ip (ifaddr.prefixlen, &rte->mask);
1286 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1287 masklen2ip (32, &rte->mask);
1288 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001289 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001290 }
1291 else
1292 {
1293 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1294 continue;
1295 }
1296
1297 if (IS_RIP_DEBUG_EVENT)
1298 {
ajs5d6c3772004-12-08 19:24:06 +00001299 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1300 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001301 }
1302 }
1303
1304 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1305 ignore the entry. */
1306 if ((packet->version == RIPv2)
1307 && (rte->mask.s_addr != 0)
1308 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1309 {
1310 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1311 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1312 rip_peer_bad_route (from);
1313 continue;
1314 }
1315
1316 /* Default route's netmask is ignored. */
1317 if (packet->version == RIPv2
1318 && (rte->prefix.s_addr == 0)
1319 && (rte->mask.s_addr != 0))
1320 {
1321 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001322 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001323 rte->mask.s_addr = 0;
1324 }
1325
1326 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001327 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001328 }
1329}
1330
paula4e987e2005-06-03 17:46:49 +00001331/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001332static int
paul2c61ae32005-08-16 15:22:14 +00001333rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001334{
1335 int ret;
1336 int sock;
1337 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001338
paul2c61ae32005-08-16 15:22:14 +00001339 memset (&addr, 0, sizeof (struct sockaddr_in));
1340
1341 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001342 {
paulf69bd9d2005-06-03 18:01:50 +00001343 addr.sin_family = AF_INET;
1344 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001345#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001346 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001347#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001348 } else {
1349 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001350 }
1351
paul2c61ae32005-08-16 15:22:14 +00001352 /* sending port must always be the RIP port */
1353 addr.sin_port = htons (RIP_PORT_DEFAULT);
1354
paula4e987e2005-06-03 17:46:49 +00001355 /* Make datagram socket. */
1356 sock = socket (AF_INET, SOCK_DGRAM, 0);
1357 if (sock < 0)
1358 {
1359 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1360 exit (1);
1361 }
1362
1363 sockopt_broadcast (sock);
1364 sockopt_reuseaddr (sock);
1365 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001366#ifdef RIP_RECVMSG
1367 setsockopt_pktinfo (sock);
1368#endif /* RIP_RECVMSG */
Stephen Hemminger78b31d52009-07-21 16:27:26 -07001369#ifdef IPTOS_PREC_INTERNETCONTROL
1370 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
1371#endif
paula4e987e2005-06-03 17:46:49 +00001372
1373 if (ripd_privs.change (ZPRIVS_RAISE))
1374 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001375 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1376 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1377
paula4e987e2005-06-03 17:46:49 +00001378 {
1379 int save_errno = errno;
1380 if (ripd_privs.change (ZPRIVS_LOWER))
1381 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001382
1383 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1384 sock, inet_ntoa(addr.sin_addr),
1385 (int) ntohs(addr.sin_port),
1386 safe_strerror(save_errno));
1387
paulf69bd9d2005-06-03 18:01:50 +00001388 close (sock);
paula4e987e2005-06-03 17:46:49 +00001389 return ret;
1390 }
paulf69bd9d2005-06-03 18:01:50 +00001391
paula4e987e2005-06-03 17:46:49 +00001392 if (ripd_privs.change (ZPRIVS_LOWER))
1393 zlog_err ("rip_create_socket: could not lower privs");
1394
1395 return sock;
1396}
1397
paulc49ad8f2004-10-22 10:27:28 +00001398/* RIP packet send to destination address, on interface denoted by
1399 * by connected argument. NULL to argument denotes destination should be
1400 * should be RIP multicast group
1401 */
pauldc63bfd2005-10-25 23:31:05 +00001402static int
paulc49ad8f2004-10-22 10:27:28 +00001403rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1404 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001405{
paul931cd542004-01-23 15:31:42 +00001406 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001407 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001408
1409 assert (ifc != NULL);
1410
paul931cd542004-01-23 15:31:42 +00001411 if (IS_RIP_DEBUG_PACKET)
1412 {
paulf69bd9d2005-06-03 18:01:50 +00001413#define ADDRESS_SIZE 20
1414 char dst[ADDRESS_SIZE];
1415 dst[ADDRESS_SIZE - 1] = '\0';
1416
paul931cd542004-01-23 15:31:42 +00001417 if (to)
1418 {
paulf69bd9d2005-06-03 18:01:50 +00001419 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001420 }
1421 else
1422 {
1423 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001424 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001425 }
paulf69bd9d2005-06-03 18:01:50 +00001426#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001427 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001428 inet_ntoa(ifc->address->u.prefix4),
1429 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001430 }
paulf69bd9d2005-06-03 18:01:50 +00001431
paulc49ad8f2004-10-22 10:27:28 +00001432 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001433 {
1434 /*
1435 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1436 * with multiple addresses on the same subnet: the first address
1437 * on the subnet is configured "primary", and all subsequent addresses
1438 * on that subnet are treated as "secondary" addresses.
1439 * In order to avoid routing-table bloat on other rip listeners,
1440 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1441 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1442 * flag is set, we would end up sending a packet for a "secondary"
1443 * source address on non-linux systems.
1444 */
1445 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001446 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001447 return 0;
1448 }
1449
paul718e3742002-12-13 20:15:29 +00001450 /* Make destination address. */
1451 memset (&sin, 0, sizeof (struct sockaddr_in));
1452 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001453#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001454 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001455#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001456
1457 /* When destination is specified, use it's port and address. */
1458 if (to)
1459 {
paul718e3742002-12-13 20:15:29 +00001460 sin.sin_port = to->sin_port;
1461 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001462 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001463 }
1464 else
1465 {
paul2c61ae32005-08-16 15:22:14 +00001466 struct sockaddr_in from;
1467
paul718e3742002-12-13 20:15:29 +00001468 sin.sin_port = htons (RIP_PORT_DEFAULT);
1469 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001470
1471 /* multicast send should bind to local interface address */
Nick Hilliardbb2315f2012-08-18 15:10:57 +00001472 memset (&from, 0, sizeof (from));
paul2c61ae32005-08-16 15:22:14 +00001473 from.sin_family = AF_INET;
1474 from.sin_port = htons (RIP_PORT_DEFAULT);
1475 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001476#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001477 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001478#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001479
paul931cd542004-01-23 15:31:42 +00001480 /*
1481 * we have to open a new socket for each packet because this
1482 * is the most portable way to bind to a different source
1483 * ipv4 address for each packet.
1484 */
paul2c61ae32005-08-16 15:22:14 +00001485 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001486 {
paulf69bd9d2005-06-03 18:01:50 +00001487 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001488 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001489 }
paulc49ad8f2004-10-22 10:27:28 +00001490 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001491 }
1492
paul931cd542004-01-23 15:31:42 +00001493 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001494 sizeof (struct sockaddr_in));
1495
1496 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001497 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001498 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001499
1500 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001501 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001502
paul931cd542004-01-23 15:31:42 +00001503 if (!to)
1504 close(send_sock);
1505
paul718e3742002-12-13 20:15:29 +00001506 return ret;
1507}
1508
1509/* Add redistributed route to RIP table. */
1510void
1511rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001512 ifindex_t ifindex, struct in_addr *nexthop,
vincentfbf5d032005-09-29 11:25:50 +00001513 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001514{
1515 int ret;
Lu Fengb397cf42014-07-18 06:13:18 +00001516 struct route_node *rp = NULL;
1517 struct rip_info *rinfo = NULL, newinfo;
1518 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00001519
1520 /* Redistribute route */
1521 ret = rip_destination_check (p->prefix);
1522 if (! ret)
1523 return;
1524
1525 rp = route_node_get (rip->table, (struct prefix *) p);
1526
Lu Fengb397cf42014-07-18 06:13:18 +00001527 memset (&newinfo, 0, sizeof (struct rip_info));
1528 newinfo.type = type;
1529 newinfo.sub_type = sub_type;
1530 newinfo.ifindex = ifindex;
1531 newinfo.metric = 1;
1532 newinfo.external_metric = metric;
1533 newinfo.distance = distance;
1534 newinfo.rp = rp;
1535 if (nexthop)
1536 newinfo.nexthop = *nexthop;
paul718e3742002-12-13 20:15:29 +00001537
Lu Fengb397cf42014-07-18 06:13:18 +00001538 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00001539 {
Lu Fengb397cf42014-07-18 06:13:18 +00001540 rinfo = listgetdata (listhead (list));
1541
paul718e3742002-12-13 20:15:29 +00001542 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1543 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1544 && rinfo->metric != RIP_METRIC_INFINITY)
1545 {
1546 route_unlock_node (rp);
1547 return;
1548 }
1549
1550 /* Manually configured RIP route check. */
1551 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001552 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1553 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001554 {
hasso16705132003-05-25 14:49:19 +00001555 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1556 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001557 {
1558 route_unlock_node (rp);
1559 return;
1560 }
1561 }
1562
Lu Fengb397cf42014-07-18 06:13:18 +00001563 rinfo = rip_ecmp_replace (&newinfo);
1564 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001565 }
Lu Fengb397cf42014-07-18 06:13:18 +00001566 else
1567 rinfo = rip_ecmp_add (&newinfo);
paul718e3742002-12-13 20:15:29 +00001568
hasso16705132003-05-25 14:49:19 +00001569 if (IS_RIP_DEBUG_EVENT) {
1570 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001571 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001572 inet_ntoa(p->prefix), p->prefixlen,
1573 ifindex2ifname(ifindex));
1574 else
ajs5d6c3772004-12-08 19:24:06 +00001575 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001576 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1577 ifindex2ifname(ifindex));
1578 }
1579
paul718e3742002-12-13 20:15:29 +00001580 rip_event (RIP_TRIGGERED_UPDATE, 0);
1581}
1582
1583/* Delete redistributed route from RIP table. */
1584void
1585rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001586 ifindex_t ifindex)
paul718e3742002-12-13 20:15:29 +00001587{
1588 int ret;
1589 struct route_node *rp;
1590 struct rip_info *rinfo;
1591
1592 ret = rip_destination_check (p->prefix);
1593 if (! ret)
1594 return;
1595
1596 rp = route_node_lookup (rip->table, (struct prefix *) p);
1597 if (rp)
1598 {
Lu Fengb397cf42014-07-18 06:13:18 +00001599 struct list *list = rp->info;
paul718e3742002-12-13 20:15:29 +00001600
Lu Fengb397cf42014-07-18 06:13:18 +00001601 if (list != NULL && listcount (list) != 0)
1602 {
1603 rinfo = listgetdata (listhead (list));
1604 if (rinfo != NULL
1605 && rinfo->type == type
1606 && rinfo->sub_type == sub_type
1607 && rinfo->ifindex == ifindex)
1608 {
1609 /* Perform poisoned reverse. */
1610 rinfo->metric = RIP_METRIC_INFINITY;
1611 RIP_TIMER_ON (rinfo->t_garbage_collect,
1612 rip_garbage_collect, rip->garbage_time);
1613 RIP_TIMER_OFF (rinfo->t_timeout);
1614 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001615
Lu Fengb397cf42014-07-18 06:13:18 +00001616 if (IS_RIP_DEBUG_EVENT)
1617 zlog_debug ("Poisone %s/%d on the interface %s with an "
1618 "infinity metric [delete]",
1619 inet_ntoa(p->prefix), p->prefixlen,
1620 ifindex2ifname(ifindex));
hasso16705132003-05-25 14:49:19 +00001621
Lu Fengb397cf42014-07-18 06:13:18 +00001622 rip_event (RIP_TRIGGERED_UPDATE, 0);
1623 }
1624 }
1625 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +00001626 }
1627}
1628
1629/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001630static void
paul718e3742002-12-13 20:15:29 +00001631rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001632 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001633{
1634 caddr_t lim;
1635 struct rte *rte;
1636 struct prefix_ipv4 p;
1637 struct route_node *rp;
1638 struct rip_info *rinfo;
1639 struct rip_interface *ri;
1640
hasso16705132003-05-25 14:49:19 +00001641 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001642 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001643 return;
1644
hasso429a0f82004-02-22 23:42:22 +00001645 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001646 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001647 if (! ri->running)
1648 return;
paul718e3742002-12-13 20:15:29 +00001649
1650 /* When passive interface is specified, suppress responses */
1651 if (ri->passive)
1652 return;
paulc49ad8f2004-10-22 10:27:28 +00001653
paul718e3742002-12-13 20:15:29 +00001654 /* RIP peer update. */
1655 rip_peer_update (from, packet->version);
1656
1657 lim = ((caddr_t) packet) + size;
1658 rte = packet->rte;
1659
1660 /* The Request is processed entry by entry. If there are no
1661 entries, no response is given. */
1662 if (lim == (caddr_t) rte)
1663 return;
1664
1665 /* There is one special case. If there is exactly one entry in the
1666 request, and it has an address family identifier of zero and a
1667 metric of infinity (i.e., 16), then this is a request to send the
1668 entire routing table. */
1669 if (lim == ((caddr_t) (rte + 1)) &&
1670 ntohs (rte->family) == 0 &&
1671 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1672 {
1673 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001674 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001675 }
1676 else
1677 {
1678 /* Examine the list of RTEs in the Request one by one. For each
1679 entry, look up the destination in the router's routing
1680 database and, if there is a route, put that route's metric in
1681 the metric field of the RTE. If there is no explicit route
1682 to the specified destination, put infinity in the metric
1683 field. Once all the entries have been filled in, change the
1684 command from Request to Response and send the datagram back
1685 to the requestor. */
1686 p.family = AF_INET;
1687
1688 for (; ((caddr_t) rte) < lim; rte++)
1689 {
1690 p.prefix = rte->prefix;
1691 p.prefixlen = ip_masklen (rte->mask);
1692 apply_mask_ipv4 (&p);
1693
1694 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1695 if (rp)
1696 {
Lu Fengb397cf42014-07-18 06:13:18 +00001697 rinfo = listgetdata (listhead ((struct list *)rp->info));
paul718e3742002-12-13 20:15:29 +00001698 rte->metric = htonl (rinfo->metric);
1699 route_unlock_node (rp);
1700 }
1701 else
1702 rte->metric = htonl (RIP_METRIC_INFINITY);
1703 }
1704 packet->command = RIP_RESPONSE;
1705
paulc49ad8f2004-10-22 10:27:28 +00001706 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001707 }
1708 rip_global_queries++;
1709}
1710
1711#if RIP_RECVMSG
1712/* Set IPv6 packet info to the socket. */
1713static int
1714setsockopt_pktinfo (int sock)
1715{
1716 int ret;
1717 int val = 1;
1718
1719 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1720 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001721 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001722 return ret;
1723}
1724
1725/* Read RIP packet by recvmsg function. */
1726int
1727rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
Paul Jakma9099f9b2016-01-18 10:12:10 +00001728 ifindex_t *ifindex)
paul718e3742002-12-13 20:15:29 +00001729{
1730 int ret;
1731 struct msghdr msg;
1732 struct iovec iov;
1733 struct cmsghdr *ptr;
1734 char adata[1024];
1735
1736 msg.msg_name = (void *) from;
1737 msg.msg_namelen = sizeof (struct sockaddr_in);
1738 msg.msg_iov = &iov;
1739 msg.msg_iovlen = 1;
1740 msg.msg_control = (void *) adata;
1741 msg.msg_controllen = sizeof adata;
1742 iov.iov_base = buf;
1743 iov.iov_len = size;
1744
1745 ret = recvmsg (sock, &msg, 0);
1746 if (ret < 0)
1747 return ret;
1748
ajsb99760a2005-01-04 16:24:43 +00001749 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001750 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1751 {
1752 struct in_pktinfo *pktinfo;
1753 int i;
1754
1755 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1756 i = pktinfo->ipi_ifindex;
1757 }
1758 return ret;
1759}
1760
1761/* RIP packet read function. */
1762int
1763rip_read_new (struct thread *t)
1764{
1765 int ret;
1766 int sock;
1767 char buf[RIP_PACKET_MAXSIZ];
1768 struct sockaddr_in from;
Paul Jakma9099f9b2016-01-18 10:12:10 +00001769 ifindex_t ifindex;
paul718e3742002-12-13 20:15:29 +00001770
1771 /* Fetch socket then register myself. */
1772 sock = THREAD_FD (t);
1773 rip_event (RIP_READ, sock);
1774
1775 /* Read RIP packet. */
1776 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1777 if (ret < 0)
1778 {
ajs6099b3b2004-11-20 02:06:59 +00001779 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001780 return ret;
1781 }
1782
1783 return ret;
1784}
1785#endif /* RIP_RECVMSG */
1786
1787/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001788static int
paul718e3742002-12-13 20:15:29 +00001789rip_read (struct thread *t)
1790{
1791 int sock;
1792 int ret;
1793 int rtenum;
1794 union rip_buf rip_buf;
1795 struct rip_packet *packet;
1796 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001797 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001798 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001799 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001800 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001801 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001802 struct rip_interface *ri;
1803
1804 /* Fetch socket then register myself. */
1805 sock = THREAD_FD (t);
1806 rip->t_read = NULL;
1807
1808 /* Add myself to tne next event */
1809 rip_event (RIP_READ, sock);
1810
1811 /* RIPd manages only IPv4. */
1812 memset (&from, 0, sizeof (struct sockaddr_in));
1813 fromlen = sizeof (struct sockaddr_in);
1814
1815 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1816 (struct sockaddr *) &from, &fromlen);
1817 if (len < 0)
1818 {
ajs6099b3b2004-11-20 02:06:59 +00001819 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001820 return len;
1821 }
1822
1823 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001824 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001825 {
1826 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001827 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001828 return -1;
1829 }
1830
1831 /* Which interface is this packet comes from. */
1832 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001833
paul718e3742002-12-13 20:15:29 +00001834 /* RIP packet received */
1835 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001836 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001837 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1838 ifp ? ifp->name : "unknown");
1839
1840 /* If this packet come from unknown interface, ignore it. */
1841 if (ifp == NULL)
1842 {
ajs766a0ca2004-12-15 14:55:51 +00001843 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1844 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001845 return -1;
1846 }
1847
1848 ifc = connected_lookup_address (ifp, from.sin_addr);
1849
1850 if (ifc == NULL)
1851 {
ajs766a0ca2004-12-15 14:55:51 +00001852 zlog_info ("rip_read: cannot find connected address for packet from %s "
1853 "port %d on interface %s",
1854 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001855 return -1;
1856 }
1857
1858 /* Packet length check. */
1859 if (len < RIP_PACKET_MINSIZ)
1860 {
1861 zlog_warn ("packet size %d is smaller than minimum size %d",
1862 len, RIP_PACKET_MINSIZ);
1863 rip_peer_bad_packet (&from);
1864 return len;
1865 }
1866 if (len > RIP_PACKET_MAXSIZ)
1867 {
1868 zlog_warn ("packet size %d is larger than max size %d",
1869 len, RIP_PACKET_MAXSIZ);
1870 rip_peer_bad_packet (&from);
1871 return len;
1872 }
1873
1874 /* Packet alignment check. */
1875 if ((len - RIP_PACKET_MINSIZ) % 20)
1876 {
1877 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1878 rip_peer_bad_packet (&from);
1879 return len;
1880 }
1881
1882 /* Set RTE number. */
1883 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1884
1885 /* For easy to handle. */
1886 packet = &rip_buf.rip_packet;
1887
1888 /* RIP version check. */
1889 if (packet->version == 0)
1890 {
1891 zlog_info ("version 0 with command %d received.", packet->command);
1892 rip_peer_bad_packet (&from);
1893 return -1;
1894 }
1895
1896 /* Dump RIP packet. */
1897 if (IS_RIP_DEBUG_RECV)
1898 rip_packet_dump (packet, len, "RECV");
1899
1900 /* RIP version adjust. This code should rethink now. RFC1058 says
1901 that "Version 1 implementations are to ignore this extra data and
1902 process only the fields specified in this document.". So RIPv3
1903 packet should be treated as RIPv1 ignoring must be zero field. */
1904 if (packet->version > RIPv2)
1905 packet->version = RIPv2;
1906
1907 /* Is RIP running or is this RIP neighbor ?*/
1908 ri = ifp->info;
1909 if (! ri->running && ! rip_neighbor_lookup (&from))
1910 {
1911 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001912 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001913 rip_peer_bad_packet (&from);
1914 return -1;
1915 }
1916
Paul Jakma15a2b082006-05-04 07:36:34 +00001917 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001918 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1919 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001920 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001921 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001922 if (IS_RIP_DEBUG_PACKET)
1923 zlog_debug (" packet's v%d doesn't fit to if version spec",
1924 packet->version);
1925 rip_peer_bad_packet (&from);
1926 return -1;
paul718e3742002-12-13 20:15:29 +00001927 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001928 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1929 {
1930 if (IS_RIP_DEBUG_PACKET)
1931 zlog_debug (" packet's v%d doesn't fit to if version spec",
1932 packet->version);
1933 rip_peer_bad_packet (&from);
1934 return -1;
1935 }
1936
paul718e3742002-12-13 20:15:29 +00001937 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1938 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1939 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001940 if ((ri->auth_type == RIP_NO_AUTH)
1941 && rtenum
paulca5e5162004-06-06 22:06:33 +00001942 && (packet->version == RIPv2)
1943 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001944 {
1945 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001946 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001947 packet->version);
1948 rip_peer_bad_packet (&from);
1949 return -1;
1950 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001951
1952 /* RFC:
1953 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001954 RIP-1 messages and RIP-2 messages which pass authentication
1955 testing shall be accepted; unauthenticated and failed
1956 authentication RIP-2 messages shall be discarded. For maximum
1957 security, RIP-1 messages should be ignored when authentication is
1958 in use (see section 4.1); otherwise, the routing information from
1959 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001960 unauthenticated manner.
1961 */
1962 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1963 * always reply regardless of authentication settings, because:
1964 *
1965 * - if there other authorised routers on-link, the REQUESTor can
1966 * passively obtain the routing updates anyway
1967 * - if there are no other authorised routers on-link, RIP can
1968 * easily be disabled for the link to prevent giving out information
1969 * on state of this routers RIP routing table..
1970 *
1971 * I.e. if RIPv1 has any place anymore these days, it's as a very
1972 * simple way to distribute routing information (e.g. to embedded
1973 * hosts / appliances) and the ability to give out RIPv1
1974 * routing-information freely, while still requiring RIPv2
1975 * authentication for any RESPONSEs might be vaguely useful.
1976 */
1977 if (ri->auth_type != RIP_NO_AUTH
1978 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00001979 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001980 /* Discard RIPv1 messages other than REQUESTs */
1981 if (packet->command != RIP_REQUEST)
1982 {
1983 if (IS_RIP_DEBUG_PACKET)
1984 zlog_debug ("RIPv1" " dropped because authentication enabled");
1985 rip_peer_bad_packet (&from);
1986 return -1;
1987 }
1988 }
1989 else if (ri->auth_type != RIP_NO_AUTH)
1990 {
1991 const char *auth_desc;
1992
1993 if (rtenum == 0)
1994 {
1995 /* There definitely is no authentication in the packet. */
1996 if (IS_RIP_DEBUG_PACKET)
1997 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
1998 rip_peer_bad_packet (&from);
1999 return -1;
2000 }
2001
2002 /* First RTE must be an Authentication Family RTE */
2003 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2004 {
2005 if (IS_RIP_DEBUG_PACKET)
2006 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002007 rip_peer_bad_packet (&from);
2008 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002009 }
2010
paul718e3742002-12-13 20:15:29 +00002011 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002012 switch (ntohs(packet->rte->tag))
2013 {
2014 case RIP_AUTH_SIMPLE_PASSWORD:
2015 auth_desc = "simple";
2016 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2017 break;
2018
2019 case RIP_AUTH_MD5:
2020 auth_desc = "MD5";
2021 ret = rip_auth_md5 (packet, &from, len, ifp);
2022 /* Reset RIP packet length to trim MD5 data. */
2023 len = ret;
2024 break;
2025
2026 default:
2027 ret = 0;
2028 auth_desc = "unknown type";
2029 if (IS_RIP_DEBUG_PACKET)
2030 zlog_debug ("RIPv2 Unknown authentication type %d",
2031 ntohs (packet->rte->tag));
2032 }
2033
2034 if (ret)
2035 {
2036 if (IS_RIP_DEBUG_PACKET)
2037 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2038 }
2039 else
2040 {
2041 if (IS_RIP_DEBUG_PACKET)
2042 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2043 rip_peer_bad_packet (&from);
2044 return -1;
2045 }
paul718e3742002-12-13 20:15:29 +00002046 }
2047
2048 /* Process each command. */
2049 switch (packet->command)
2050 {
2051 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002052 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002053 break;
2054 case RIP_REQUEST:
2055 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002056 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002057 break;
2058 case RIP_TRACEON:
2059 case RIP_TRACEOFF:
2060 zlog_info ("Obsolete command %s received, please sent it to routed",
2061 lookup (rip_msg, packet->command));
2062 rip_peer_bad_packet (&from);
2063 break;
2064 case RIP_POLL_ENTRY:
2065 zlog_info ("Obsolete command %s received",
2066 lookup (rip_msg, packet->command));
2067 rip_peer_bad_packet (&from);
2068 break;
2069 default:
2070 zlog_info ("Unknown RIP command %d received", packet->command);
2071 rip_peer_bad_packet (&from);
2072 break;
2073 }
2074
2075 return len;
2076}
2077
paul718e3742002-12-13 20:15:29 +00002078/* Write routing table entry to the stream and return next index of
2079 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002080static int
paul718e3742002-12-13 20:15:29 +00002081rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002082 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002083{
2084 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002085
2086 /* Write routing table entry. */
2087 if (version == RIPv1)
2088 {
2089 stream_putw (s, AF_INET);
2090 stream_putw (s, 0);
2091 stream_put_ipv4 (s, p->prefix.s_addr);
2092 stream_put_ipv4 (s, 0);
2093 stream_put_ipv4 (s, 0);
2094 stream_putl (s, rinfo->metric_out);
2095 }
2096 else
2097 {
2098 masklen2ip (p->prefixlen, &mask);
2099
2100 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002101 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002102 stream_put_ipv4 (s, p->prefix.s_addr);
2103 stream_put_ipv4 (s, mask.s_addr);
2104 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2105 stream_putl (s, rinfo->metric_out);
2106 }
2107
2108 return ++num;
2109}
2110
2111/* Send update to the ifp or spcified neighbor. */
2112void
paulc49ad8f2004-10-22 10:27:28 +00002113rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2114 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002115{
2116 int ret;
2117 struct stream *s;
2118 struct route_node *rp;
2119 struct rip_info *rinfo;
2120 struct rip_interface *ri;
2121 struct prefix_ipv4 *p;
2122 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002123 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002124 struct key *key = NULL;
2125 /* this might need to made dynamic if RIP ever supported auth methods
2126 with larger key string sizes */
2127 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002128 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002129 int num = 0;
paul718e3742002-12-13 20:15:29 +00002130 int rtemax;
paul01d09082003-06-08 21:22:18 +00002131 int subnetted = 0;
Lu Fengb397cf42014-07-18 06:13:18 +00002132 struct list *list = NULL;
2133 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002134
2135 /* Logging output event. */
2136 if (IS_RIP_DEBUG_EVENT)
2137 {
2138 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002139 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002140 else
ajs5d6c3772004-12-08 19:24:06 +00002141 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002142 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002143 }
2144
2145 /* Set output stream. */
2146 s = rip->obuf;
2147
2148 /* Reset stream and RTE counter. */
2149 stream_reset (s);
Lu Feng342a31b2014-06-25 07:43:15 +00002150 rtemax = RIP_MAX_RTE;
paul718e3742002-12-13 20:15:29 +00002151
2152 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002153 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002154
2155 /* If output interface is in simple password authentication mode, we
2156 need space for authentication data. */
2157 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2158 rtemax -= 1;
2159
2160 /* If output interface is in MD5 authentication mode, we need space
2161 for authentication header and data. */
2162 if (ri->auth_type == RIP_AUTH_MD5)
2163 rtemax -= 2;
2164
2165 /* If output interface is in simple password authentication mode
2166 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002167 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002168 {
2169 if (ri->key_chain)
2170 {
2171 struct keychain *keychain;
2172
2173 keychain = keychain_lookup (ri->key_chain);
2174 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002175 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002176 }
paulb14ee002005-02-04 23:42:41 +00002177 /* to be passed to auth functions later */
2178 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002179 }
2180
paul727d1042002-12-13 20:50:29 +00002181 if (version == RIPv1)
2182 {
paulc49ad8f2004-10-22 10:27:28 +00002183 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002184 apply_classful_mask_ipv4 (&ifaddrclass);
2185 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002186 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002187 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002188 }
2189
paul718e3742002-12-13 20:15:29 +00002190 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002191 if ((list = rp->info) != NULL && listcount (list) != 0)
paul718e3742002-12-13 20:15:29 +00002192 {
Lu Fengb397cf42014-07-18 06:13:18 +00002193 rinfo = listgetdata (listhead (list));
paul727d1042002-12-13 20:50:29 +00002194 /* For RIPv1, if we are subnetted, output subnets in our network */
2195 /* that have the same mask as the output "interface". For other */
2196 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002197
2198 if (version == RIPv1)
2199 {
paul727d1042002-12-13 20:50:29 +00002200 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002201
2202 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002203 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002204 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002205
paul727d1042002-12-13 20:50:29 +00002206 if (subnetted &&
2207 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2208 {
paulc49ad8f2004-10-22 10:27:28 +00002209 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002210 (rp->p.prefixlen != 32))
2211 continue;
2212 }
2213 else
2214 {
2215 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2216 apply_classful_mask_ipv4(&classfull);
2217 if (rp->p.u.prefix4.s_addr != 0 &&
2218 classfull.prefixlen != rp->p.prefixlen)
2219 continue;
2220 }
paul718e3742002-12-13 20:15:29 +00002221 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002222 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002223 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002224 }
2225 else
2226 p = (struct prefix_ipv4 *) &rp->p;
2227
2228 /* Apply output filters. */
Matthieu Boutierfafa8992014-09-10 16:50:43 +02002229 ret = rip_filter (RIP_FILTER_OUT, p, ri);
paul718e3742002-12-13 20:15:29 +00002230 if (ret < 0)
2231 continue;
2232
2233 /* Changed route only output. */
2234 if (route_type == rip_changed_route &&
2235 (! (rinfo->flags & RIP_RTF_CHANGED)))
2236 continue;
2237
2238 /* Split horizon. */
2239 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002240 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002241 {
paul42d14d92003-11-17 09:15:18 +00002242 /*
2243 * We perform split horizon for RIP and connected route.
2244 * For rip routes, we want to suppress the route if we would
2245 * end up sending the route back on the interface that we
2246 * learned it from, with a higher metric. For connected routes,
2247 * we suppress the route if the prefix is a subset of the
2248 * source address that we are going to use for the packet
2249 * (in order to handle the case when multiple subnets are
2250 * configured on the same interface).
2251 */
Lu Fengb397cf42014-07-18 06:13:18 +00002252 int suppress = 0;
2253 struct rip_info *tmp_rinfo = NULL;
2254
2255 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
2256 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2257 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2258 {
2259 suppress = 1;
2260 break;
2261 }
2262
2263 if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002264 prefix_match((struct prefix *)p, ifc->address))
Lu Fengb397cf42014-07-18 06:13:18 +00002265 suppress = 1;
2266
2267 if (suppress)
paul718e3742002-12-13 20:15:29 +00002268 continue;
2269 }
2270
2271 /* Preparation for route-map. */
2272 rinfo->metric_set = 0;
2273 rinfo->nexthop_out.s_addr = 0;
2274 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002275 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002276 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002277
hasso16705132003-05-25 14:49:19 +00002278 /* In order to avoid some local loops,
2279 * if the RIP route has a nexthop via this interface, keep the nexthop,
2280 * otherwise set it to 0. The nexthop should not be propagated
2281 * beyond the local broadcast/multicast area in order
2282 * to avoid an IGP multi-level recursive look-up.
2283 * see (4.4)
2284 */
paulc49ad8f2004-10-22 10:27:28 +00002285 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002286 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002287
2288 /* Interface route-map */
2289 if (ri->routemap[RIP_FILTER_OUT])
2290 {
2291 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2292 (struct prefix *) p, RMAP_RIP,
2293 rinfo);
2294
2295 if (ret == RMAP_DENYMATCH)
2296 {
2297 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002298 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002299 inet_ntoa (p->prefix), p->prefixlen);
2300 continue;
2301 }
2302 }
paul718e3742002-12-13 20:15:29 +00002303
hasso16705132003-05-25 14:49:19 +00002304 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002305 if (rip->route_map[rinfo->type].name
2306 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2307 {
2308 ret = route_map_apply (rip->route_map[rinfo->type].map,
2309 (struct prefix *)p, RMAP_RIP, rinfo);
2310
2311 if (ret == RMAP_DENYMATCH)
2312 {
2313 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002314 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002315 inet_ntoa (p->prefix), p->prefixlen);
2316 continue;
2317 }
2318 }
2319
2320 /* When route-map does not set metric. */
2321 if (! rinfo->metric_set)
2322 {
2323 /* If redistribute metric is set. */
2324 if (rip->route_map[rinfo->type].metric_config
2325 && rinfo->metric != RIP_METRIC_INFINITY)
2326 {
2327 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2328 }
2329 else
2330 {
2331 /* If the route is not connected or localy generated
2332 one, use default-metric value*/
2333 if (rinfo->type != ZEBRA_ROUTE_RIP
2334 && rinfo->type != ZEBRA_ROUTE_CONNECT
2335 && rinfo->metric != RIP_METRIC_INFINITY)
2336 rinfo->metric_out = rip->default_metric;
2337 }
2338 }
2339
2340 /* Apply offset-list */
2341 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002342 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002343
2344 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2345 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002346
2347 /* Perform split-horizon with poisoned reverse
2348 * for RIP and connected routes.
2349 **/
2350 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002351 /*
2352 * We perform split horizon for RIP and connected route.
2353 * For rip routes, we want to suppress the route if we would
2354 * end up sending the route back on the interface that we
2355 * learned it from, with a higher metric. For connected routes,
2356 * we suppress the route if the prefix is a subset of the
2357 * source address that we are going to use for the packet
2358 * (in order to handle the case when multiple subnets are
2359 * configured on the same interface).
2360 */
Lu Fengb397cf42014-07-18 06:13:18 +00002361 struct rip_info *tmp_rinfo = NULL;
2362
2363 for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
Donald Sharp7e7a1012016-04-08 22:03:22 -04002364 {
2365 if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
2366 tmp_rinfo->ifindex == ifc->ifp->ifindex)
2367 rinfo->metric_out = RIP_METRIC_INFINITY;
2368 if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT &&
2369 prefix_match((struct prefix *)p, ifc->address))
2370 rinfo->metric_out = RIP_METRIC_INFINITY;
2371 }
hasso16705132003-05-25 14:49:19 +00002372 }
paulb14ee002005-02-04 23:42:41 +00002373
2374 /* Prepare preamble, auth headers, if needs be */
2375 if (num == 0)
2376 {
2377 stream_putc (s, RIP_RESPONSE);
2378 stream_putc (s, version);
2379 stream_putw (s, 0);
2380
paul0cb8a012005-05-29 11:27:24 +00002381 /* auth header for !v1 && !no_auth */
2382 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002383 doff = rip_auth_header_write (s, ri, key, auth_str,
2384 RIP_AUTH_SIMPLE_SIZE);
2385 }
2386
paul718e3742002-12-13 20:15:29 +00002387 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002388 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002389 if (num == rtemax)
2390 {
2391 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002392 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002393
2394 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002395 to, ifc);
paul718e3742002-12-13 20:15:29 +00002396
2397 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2398 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2399 stream_get_endp(s), "SEND");
2400 num = 0;
2401 stream_reset (s);
2402 }
2403 }
2404
2405 /* Flush unwritten RTE. */
2406 if (num != 0)
2407 {
2408 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002409 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002410
paulc49ad8f2004-10-22 10:27:28 +00002411 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002412
2413 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2414 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2415 stream_get_endp (s), "SEND");
2416 num = 0;
2417 stream_reset (s);
2418 }
2419
2420 /* Statistics updates. */
2421 ri->sent_updates++;
2422}
2423
2424/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002425static void
paulc49ad8f2004-10-22 10:27:28 +00002426rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002427{
paul718e3742002-12-13 20:15:29 +00002428 struct sockaddr_in to;
2429
2430 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002431 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002432 {
2433 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002434 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002435
paulc49ad8f2004-10-22 10:27:28 +00002436 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002437 return;
2438 }
paulc49ad8f2004-10-22 10:27:28 +00002439
paul718e3742002-12-13 20:15:29 +00002440 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002441 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002442 {
paulc49ad8f2004-10-22 10:27:28 +00002443 if (ifc->address->family == AF_INET)
2444 {
2445 /* Destination address and port setting. */
2446 memset (&to, 0, sizeof (struct sockaddr_in));
2447 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002448 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002449 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002450 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002451 /* calculate the appropriate broadcast address */
2452 to.sin_addr.s_addr =
2453 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2454 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002455 else
2456 /* do not know where to send the packet */
2457 return;
paulc49ad8f2004-10-22 10:27:28 +00002458 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002459
paulc49ad8f2004-10-22 10:27:28 +00002460 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002461 zlog_debug("%s announce to %s on %s",
2462 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2463 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002464
paulc49ad8f2004-10-22 10:27:28 +00002465 rip_output_process (ifc, &to, route_type, version);
2466 }
paul718e3742002-12-13 20:15:29 +00002467 }
2468}
2469
2470/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002471static void
paul718e3742002-12-13 20:15:29 +00002472rip_update_process (int route_type)
2473{
paul1eb8ef22005-04-07 07:30:20 +00002474 struct listnode *node;
2475 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002476 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002477 struct interface *ifp;
2478 struct rip_interface *ri;
2479 struct route_node *rp;
2480 struct sockaddr_in to;
2481 struct prefix_ipv4 *p;
2482
2483 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002484 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002485 {
paul718e3742002-12-13 20:15:29 +00002486 if (if_is_loopback (ifp))
2487 continue;
2488
paul2e3b2e42002-12-13 21:03:13 +00002489 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002490 continue;
2491
2492 /* Fetch RIP interface information. */
2493 ri = ifp->info;
2494
2495 /* When passive interface is specified, suppress announce to the
2496 interface. */
2497 if (ri->passive)
2498 continue;
2499
2500 if (ri->running)
2501 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002502 /*
2503 * If there is no version configuration in the interface,
2504 * use rip's version setting.
2505 */
2506 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2507 rip->version_send : ri->ri_send);
2508
paul718e3742002-12-13 20:15:29 +00002509 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002510 zlog_debug("SEND UPDATE to %s ifindex %d",
Christian Franke1ca8d402015-11-10 17:45:03 +01002511 ifp->name, ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002512
paulcc1131a2003-10-15 23:20:17 +00002513 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002514 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002515 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002516 if (connected->address->family == AF_INET)
2517 {
2518 if (vsend & RIPv1)
2519 rip_update_interface (connected, RIPv1, route_type);
2520 if ((vsend & RIPv2) && if_is_multicast(ifp))
2521 rip_update_interface (connected, RIPv2, route_type);
2522 }
2523 }
paul718e3742002-12-13 20:15:29 +00002524 }
2525 }
2526
2527 /* RIP send updates to each neighbor. */
2528 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2529 if (rp->info != NULL)
2530 {
2531 p = (struct prefix_ipv4 *) &rp->p;
2532
2533 ifp = if_lookup_address (p->prefix);
2534 if (! ifp)
2535 {
paulc49ad8f2004-10-22 10:27:28 +00002536 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002537 inet_ntoa (p->prefix));
2538 continue;
2539 }
paulc49ad8f2004-10-22 10:27:28 +00002540
2541 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2542 {
2543 zlog_warn ("Neighbor %s doesnt have connected network",
2544 inet_ntoa (p->prefix));
2545 continue;
2546 }
2547
paul718e3742002-12-13 20:15:29 +00002548 /* Set destination address and port */
2549 memset (&to, 0, sizeof (struct sockaddr_in));
2550 to.sin_addr = p->prefix;
2551 to.sin_port = htons (RIP_PORT_DEFAULT);
2552
2553 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002554 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002555 }
2556}
2557
2558/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002559static int
paul718e3742002-12-13 20:15:29 +00002560rip_update (struct thread *t)
2561{
2562 /* Clear timer pointer. */
2563 rip->t_update = NULL;
2564
2565 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002566 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002567
2568 /* Process update output. */
2569 rip_update_process (rip_all_route);
2570
2571 /* Triggered updates may be suppressed if a regular update is due by
2572 the time the triggered update would be sent. */
2573 if (rip->t_triggered_interval)
2574 {
2575 thread_cancel (rip->t_triggered_interval);
2576 rip->t_triggered_interval = NULL;
2577 }
2578 rip->trigger = 0;
2579
2580 /* Register myself. */
2581 rip_event (RIP_UPDATE_EVENT, 0);
2582
2583 return 0;
2584}
2585
2586/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002587static void
paul216565a2005-10-25 23:35:28 +00002588rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002589{
2590 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002591 struct rip_info *rinfo = NULL;
2592 struct list *list = NULL;
2593 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002594
2595 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002596 if ((list = rp->info) != NULL)
2597 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2598 {
2599 UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
2600 /* This flag can be set only on the first entry. */
2601 break;
2602 }
paul718e3742002-12-13 20:15:29 +00002603}
2604
2605/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002606static int
paul718e3742002-12-13 20:15:29 +00002607rip_triggered_interval (struct thread *t)
2608{
2609 int rip_triggered_update (struct thread *);
2610
2611 rip->t_triggered_interval = NULL;
2612
2613 if (rip->trigger)
2614 {
2615 rip->trigger = 0;
2616 rip_triggered_update (t);
2617 }
2618 return 0;
2619}
2620
2621/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002622static int
paul718e3742002-12-13 20:15:29 +00002623rip_triggered_update (struct thread *t)
2624{
2625 int interval;
2626
2627 /* Clear thred pointer. */
2628 rip->t_triggered_update = NULL;
2629
2630 /* Cancel interval timer. */
2631 if (rip->t_triggered_interval)
2632 {
2633 thread_cancel (rip->t_triggered_interval);
2634 rip->t_triggered_interval = NULL;
2635 }
2636 rip->trigger = 0;
2637
2638 /* Logging triggered update. */
2639 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002640 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002641
2642 /* Split Horizon processing is done when generating triggered
2643 updates as well as normal updates (see section 2.6). */
2644 rip_update_process (rip_changed_route);
2645
2646 /* Once all of the triggered updates have been generated, the route
2647 change flags should be cleared. */
2648 rip_clear_changed_flag ();
2649
2650 /* After a triggered update is sent, a timer should be set for a
2651 random interval between 1 and 5 seconds. If other changes that
2652 would trigger updates occur before the timer expires, a single
2653 update is triggered when the timer expires. */
2654 interval = (random () % 5) + 1;
2655
2656 rip->t_triggered_interval =
2657 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2658
2659 return 0;
2660}
2661
2662/* Withdraw redistributed route. */
2663void
2664rip_redistribute_withdraw (int type)
2665{
2666 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00002667 struct rip_info *rinfo = NULL;
2668 struct list *list = NULL;
paul718e3742002-12-13 20:15:29 +00002669
2670 if (!rip)
2671 return;
2672
2673 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00002674 if ((list = rp->info) != NULL)
paul718e3742002-12-13 20:15:29 +00002675 {
Lu Fengb397cf42014-07-18 06:13:18 +00002676 rinfo = listgetdata (listhead (list));
paul718e3742002-12-13 20:15:29 +00002677 if (rinfo->type == type
2678 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2679 {
2680 /* Perform poisoned reverse. */
2681 rinfo->metric = RIP_METRIC_INFINITY;
2682 RIP_TIMER_ON (rinfo->t_garbage_collect,
2683 rip_garbage_collect, rip->garbage_time);
2684 RIP_TIMER_OFF (rinfo->t_timeout);
2685 rinfo->flags |= RIP_RTF_CHANGED;
2686
hasso16705132003-05-25 14:49:19 +00002687 if (IS_RIP_DEBUG_EVENT) {
2688 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2689
ajs5d6c3772004-12-08 19:24:06 +00002690 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002691 inet_ntoa(p->prefix), p->prefixlen,
2692 ifindex2ifname(rinfo->ifindex));
2693 }
2694
paul718e3742002-12-13 20:15:29 +00002695 rip_event (RIP_TRIGGERED_UPDATE, 0);
2696 }
2697 }
2698}
2699
2700/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002701static int
2702rip_create (void)
paul718e3742002-12-13 20:15:29 +00002703{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002704 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002705
2706 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002707 rip->version_send = RI_RIP_VERSION_2;
2708 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002709 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2710 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2711 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2712 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2713
2714 /* Initialize RIP routig table. */
2715 rip->table = route_table_init ();
2716 rip->route = route_table_init ();
2717 rip->neighbor = route_table_init ();
2718
2719 /* Make output stream. */
2720 rip->obuf = stream_new (1500);
2721
2722 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002723 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002724 if (rip->sock < 0)
2725 return rip->sock;
2726
2727 /* Create read and timer thread. */
2728 rip_event (RIP_READ, rip->sock);
2729 rip_event (RIP_UPDATE_EVENT, 1);
2730
2731 return 0;
2732}
2733
2734/* Sned RIP request to the destination. */
2735int
2736rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002737 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002738{
2739 struct rte *rte;
2740 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002741 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002742
2743 memset (&rip_packet, 0, sizeof (rip_packet));
2744
2745 rip_packet.command = RIP_REQUEST;
2746 rip_packet.version = version;
2747 rte = rip_packet.rte;
2748 rte->metric = htonl (RIP_METRIC_INFINITY);
2749
paul931cd542004-01-23 15:31:42 +00002750 if (connected)
2751 {
2752 /*
2753 * connected is only sent for ripv1 case, or when
2754 * interface does not support multicast. Caller loops
2755 * over each connected address for this case.
2756 */
paul11dde9c2004-05-31 14:00:00 +00002757 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002758 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002759 return -1;
2760 else
2761 return sizeof (rip_packet);
2762 }
2763
paulcc1131a2003-10-15 23:20:17 +00002764 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002765 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002766 {
2767 struct prefix_ipv4 *p;
2768
2769 p = (struct prefix_ipv4 *) connected->address;
2770
2771 if (p->family != AF_INET)
2772 continue;
2773
paul11dde9c2004-05-31 14:00:00 +00002774 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002775 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002776 return -1;
2777 }
2778 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002779}
David Lamparter6b0655a2014-06-04 06:53:35 +02002780
pauldc63bfd2005-10-25 23:31:05 +00002781static int
paul718e3742002-12-13 20:15:29 +00002782rip_update_jitter (unsigned long time)
2783{
paul239389b2004-05-05 14:09:37 +00002784#define JITTER_BOUND 4
2785 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2786 Given that, we cannot let time be less than JITTER_BOUND seconds.
2787 The RIPv2 RFC says jitter should be small compared to
2788 update_time. We consider 1/JITTER_BOUND to be small.
2789 */
2790
2791 int jitter_input = time;
2792 int jitter;
2793
2794 if (jitter_input < JITTER_BOUND)
2795 jitter_input = JITTER_BOUND;
2796
Donald Sharpf31bab42015-06-19 19:26:19 -04002797 jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input));
paul239389b2004-05-05 14:09:37 +00002798
2799 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002800}
2801
2802void
2803rip_event (enum rip_event event, int sock)
2804{
2805 int jitter = 0;
2806
2807 switch (event)
2808 {
2809 case RIP_READ:
2810 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2811 break;
2812 case RIP_UPDATE_EVENT:
2813 if (rip->t_update)
2814 {
2815 thread_cancel (rip->t_update);
2816 rip->t_update = NULL;
2817 }
2818 jitter = rip_update_jitter (rip->update_time);
2819 rip->t_update =
2820 thread_add_timer (master, rip_update, NULL,
2821 sock ? 2 : rip->update_time + jitter);
2822 break;
2823 case RIP_TRIGGERED_UPDATE:
2824 if (rip->t_triggered_interval)
2825 rip->trigger = 1;
2826 else if (! rip->t_triggered_update)
2827 rip->t_triggered_update =
2828 thread_add_event (master, rip_triggered_update, NULL, 0);
2829 break;
2830 default:
2831 break;
2832 }
2833}
David Lamparter6b0655a2014-06-04 06:53:35 +02002834
paul718e3742002-12-13 20:15:29 +00002835DEFUN (router_rip,
2836 router_rip_cmd,
2837 "router rip",
2838 "Enable a routing process\n"
2839 "Routing Information Protocol (RIP)\n")
2840{
2841 int ret;
2842
2843 /* If rip is not enabled before. */
2844 if (! rip)
2845 {
2846 ret = rip_create ();
2847 if (ret < 0)
2848 {
2849 zlog_info ("Can't create RIP");
2850 return CMD_WARNING;
2851 }
2852 }
2853 vty->node = RIP_NODE;
2854 vty->index = rip;
2855
2856 return CMD_SUCCESS;
2857}
2858
2859DEFUN (no_router_rip,
2860 no_router_rip_cmd,
2861 "no router rip",
2862 NO_STR
2863 "Enable a routing process\n"
2864 "Routing Information Protocol (RIP)\n")
2865{
2866 if (rip)
2867 rip_clean ();
2868 return CMD_SUCCESS;
2869}
2870
2871DEFUN (rip_version,
2872 rip_version_cmd,
2873 "version <1-2>",
2874 "Set routing protocol version\n"
2875 "version\n")
2876{
2877 int version;
2878
2879 version = atoi (argv[0]);
2880 if (version != RIPv1 && version != RIPv2)
2881 {
2882 vty_out (vty, "invalid rip version %d%s", version,
2883 VTY_NEWLINE);
2884 return CMD_WARNING;
2885 }
paulf38a4712003-06-07 01:10:00 +00002886 rip->version_send = version;
2887 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002888
2889 return CMD_SUCCESS;
2890}
2891
2892DEFUN (no_rip_version,
2893 no_rip_version_cmd,
2894 "no version",
2895 NO_STR
2896 "Set routing protocol version\n")
2897{
2898 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002899 rip->version_send = RI_RIP_VERSION_2;
2900 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002901
2902 return CMD_SUCCESS;
2903}
2904
2905ALIAS (no_rip_version,
2906 no_rip_version_val_cmd,
2907 "no version <1-2>",
2908 NO_STR
2909 "Set routing protocol version\n"
2910 "version\n")
2911
2912DEFUN (rip_route,
2913 rip_route_cmd,
2914 "route A.B.C.D/M",
2915 "RIP static route configuration\n"
2916 "IP prefix <network>/<length>\n")
2917{
2918 int ret;
2919 struct prefix_ipv4 p;
2920 struct route_node *node;
2921
2922 ret = str2prefix_ipv4 (argv[0], &p);
2923 if (ret < 0)
2924 {
2925 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2926 return CMD_WARNING;
2927 }
2928 apply_mask_ipv4 (&p);
2929
2930 /* For router rip configuration. */
2931 node = route_node_get (rip->route, (struct prefix *) &p);
2932
2933 if (node->info)
2934 {
2935 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2936 route_unlock_node (node);
2937 return CMD_WARNING;
2938 }
2939
hasso8a676be2004-10-08 06:36:38 +00002940 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002941
vincentfbf5d032005-09-29 11:25:50 +00002942 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002943
2944 return CMD_SUCCESS;
2945}
2946
2947DEFUN (no_rip_route,
2948 no_rip_route_cmd,
2949 "no route A.B.C.D/M",
2950 NO_STR
2951 "RIP static route configuration\n"
2952 "IP prefix <network>/<length>\n")
2953{
2954 int ret;
2955 struct prefix_ipv4 p;
2956 struct route_node *node;
2957
2958 ret = str2prefix_ipv4 (argv[0], &p);
2959 if (ret < 0)
2960 {
2961 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2962 return CMD_WARNING;
2963 }
2964 apply_mask_ipv4 (&p);
2965
2966 /* For router rip configuration. */
2967 node = route_node_lookup (rip->route, (struct prefix *) &p);
2968 if (! node)
2969 {
2970 vty_out (vty, "Can't find route %s.%s", argv[0],
2971 VTY_NEWLINE);
2972 return CMD_WARNING;
2973 }
2974
2975 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2976 route_unlock_node (node);
2977
2978 node->info = NULL;
2979 route_unlock_node (node);
2980
2981 return CMD_SUCCESS;
2982}
2983
Stephen Hemminger2c239702009-12-10 19:16:05 +03002984#if 0
pauldc63bfd2005-10-25 23:31:05 +00002985static void
paul216565a2005-10-25 23:35:28 +00002986rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002987{
2988 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00002989 struct rip_info *rinfo = NULL;
2990 struct list *list = NULL;
2991 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00002992
2993 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00002994 if ((list = np->info) != NULL)
2995 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2996 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2997 rinfo->metric = rip->default_metric;
paul718e3742002-12-13 20:15:29 +00002998}
Stephen Hemminger2c239702009-12-10 19:16:05 +03002999#endif
paul718e3742002-12-13 20:15:29 +00003000
3001DEFUN (rip_default_metric,
3002 rip_default_metric_cmd,
3003 "default-metric <1-16>",
3004 "Set a metric of redistribute routes\n"
3005 "Default metric\n")
3006{
3007 if (rip)
3008 {
3009 rip->default_metric = atoi (argv[0]);
3010 /* rip_update_default_metric (); */
3011 }
3012 return CMD_SUCCESS;
3013}
3014
3015DEFUN (no_rip_default_metric,
3016 no_rip_default_metric_cmd,
3017 "no default-metric",
3018 NO_STR
3019 "Set a metric of redistribute routes\n"
3020 "Default metric\n")
3021{
3022 if (rip)
3023 {
3024 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3025 /* rip_update_default_metric (); */
3026 }
3027 return CMD_SUCCESS;
3028}
3029
3030ALIAS (no_rip_default_metric,
3031 no_rip_default_metric_val_cmd,
3032 "no default-metric <1-16>",
3033 NO_STR
3034 "Set a metric of redistribute routes\n"
3035 "Default metric\n")
3036
3037DEFUN (rip_timers,
3038 rip_timers_cmd,
3039 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3040 "Adjust routing timers\n"
3041 "Basic routing protocol update timers\n"
3042 "Routing table update timer value in second. Default is 30.\n"
3043 "Routing information timeout timer. Default is 180.\n"
3044 "Garbage collection timer. Default is 120.\n")
3045{
3046 unsigned long update;
3047 unsigned long timeout;
3048 unsigned long garbage;
3049 char *endptr = NULL;
3050 unsigned long RIP_TIMER_MAX = 2147483647;
3051 unsigned long RIP_TIMER_MIN = 5;
3052
3053 update = strtoul (argv[0], &endptr, 10);
3054 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3055 {
3056 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3057 return CMD_WARNING;
3058 }
3059
3060 timeout = strtoul (argv[1], &endptr, 10);
3061 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3062 {
3063 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3064 return CMD_WARNING;
3065 }
3066
3067 garbage = strtoul (argv[2], &endptr, 10);
3068 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3069 {
3070 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3071 return CMD_WARNING;
3072 }
3073
3074 /* Set each timer value. */
3075 rip->update_time = update;
3076 rip->timeout_time = timeout;
3077 rip->garbage_time = garbage;
3078
3079 /* Reset update timer thread. */
3080 rip_event (RIP_UPDATE_EVENT, 0);
3081
3082 return CMD_SUCCESS;
3083}
3084
3085DEFUN (no_rip_timers,
3086 no_rip_timers_cmd,
3087 "no timers basic",
3088 NO_STR
3089 "Adjust routing timers\n"
3090 "Basic routing protocol update timers\n")
3091{
3092 /* Set each timer value to the default. */
3093 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3094 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3095 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3096
3097 /* Reset update timer thread. */
3098 rip_event (RIP_UPDATE_EVENT, 0);
3099
3100 return CMD_SUCCESS;
3101}
hasso16705132003-05-25 14:49:19 +00003102
3103ALIAS (no_rip_timers,
3104 no_rip_timers_val_cmd,
3105 "no timers basic <0-65535> <0-65535> <0-65535>",
3106 NO_STR
3107 "Adjust routing timers\n"
3108 "Basic routing protocol update timers\n"
3109 "Routing table update timer value in second. Default is 30.\n"
3110 "Routing information timeout timer. Default is 180.\n"
3111 "Garbage collection timer. Default is 120.\n")
3112
David Lamparter6b0655a2014-06-04 06:53:35 +02003113
paul718e3742002-12-13 20:15:29 +00003114struct route_table *rip_distance_table;
3115
3116struct rip_distance
3117{
3118 /* Distance value for the IP source prefix. */
3119 u_char distance;
3120
3121 /* Name of the access-list to be matched. */
3122 char *access_list;
3123};
3124
pauldc63bfd2005-10-25 23:31:05 +00003125static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003126rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003127{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003128 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003129}
3130
pauldc63bfd2005-10-25 23:31:05 +00003131static void
paul718e3742002-12-13 20:15:29 +00003132rip_distance_free (struct rip_distance *rdistance)
3133{
3134 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3135}
3136
pauldc63bfd2005-10-25 23:31:05 +00003137static int
hasso98b718a2004-10-11 12:57:57 +00003138rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3139 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003140{
3141 int ret;
3142 struct prefix_ipv4 p;
3143 u_char distance;
3144 struct route_node *rn;
3145 struct rip_distance *rdistance;
3146
3147 ret = str2prefix_ipv4 (ip_str, &p);
3148 if (ret == 0)
3149 {
3150 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3151 return CMD_WARNING;
3152 }
3153
3154 distance = atoi (distance_str);
3155
3156 /* Get RIP distance node. */
3157 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3158 if (rn->info)
3159 {
3160 rdistance = rn->info;
3161 route_unlock_node (rn);
3162 }
3163 else
3164 {
3165 rdistance = rip_distance_new ();
3166 rn->info = rdistance;
3167 }
3168
3169 /* Set distance value. */
3170 rdistance->distance = distance;
3171
3172 /* Reset access-list configuration. */
3173 if (rdistance->access_list)
3174 {
3175 free (rdistance->access_list);
3176 rdistance->access_list = NULL;
3177 }
3178 if (access_list_str)
3179 rdistance->access_list = strdup (access_list_str);
3180
3181 return CMD_SUCCESS;
3182}
3183
pauldc63bfd2005-10-25 23:31:05 +00003184static int
hasso98b718a2004-10-11 12:57:57 +00003185rip_distance_unset (struct vty *vty, const char *distance_str,
3186 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003187{
3188 int ret;
3189 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +00003190 struct route_node *rn;
3191 struct rip_distance *rdistance;
3192
3193 ret = str2prefix_ipv4 (ip_str, &p);
3194 if (ret == 0)
3195 {
3196 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3197 return CMD_WARNING;
3198 }
3199
paul718e3742002-12-13 20:15:29 +00003200 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3201 if (! rn)
3202 {
3203 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3204 return CMD_WARNING;
3205 }
3206
3207 rdistance = rn->info;
3208
3209 if (rdistance->access_list)
3210 free (rdistance->access_list);
3211 rip_distance_free (rdistance);
3212
3213 rn->info = NULL;
3214 route_unlock_node (rn);
3215 route_unlock_node (rn);
3216
3217 return CMD_SUCCESS;
3218}
3219
pauldc63bfd2005-10-25 23:31:05 +00003220static void
paul216565a2005-10-25 23:35:28 +00003221rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003222{
3223 struct route_node *rn;
3224 struct rip_distance *rdistance;
3225
3226 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3227 if ((rdistance = rn->info) != NULL)
3228 {
3229 if (rdistance->access_list)
3230 free (rdistance->access_list);
3231 rip_distance_free (rdistance);
3232 rn->info = NULL;
3233 route_unlock_node (rn);
3234 }
3235}
3236
3237/* Apply RIP information to distance method. */
3238u_char
3239rip_distance_apply (struct rip_info *rinfo)
3240{
3241 struct route_node *rn;
3242 struct prefix_ipv4 p;
3243 struct rip_distance *rdistance;
3244 struct access_list *alist;
3245
3246 if (! rip)
3247 return 0;
3248
3249 memset (&p, 0, sizeof (struct prefix_ipv4));
3250 p.family = AF_INET;
3251 p.prefix = rinfo->from;
3252 p.prefixlen = IPV4_MAX_BITLEN;
3253
3254 /* Check source address. */
3255 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3256 if (rn)
3257 {
3258 rdistance = rn->info;
3259 route_unlock_node (rn);
3260
3261 if (rdistance->access_list)
3262 {
3263 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3264 if (alist == NULL)
3265 return 0;
3266 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3267 return 0;
3268
3269 return rdistance->distance;
3270 }
3271 else
3272 return rdistance->distance;
3273 }
3274
3275 if (rip->distance)
3276 return rip->distance;
3277
3278 return 0;
3279}
3280
pauldc63bfd2005-10-25 23:31:05 +00003281static void
paul718e3742002-12-13 20:15:29 +00003282rip_distance_show (struct vty *vty)
3283{
3284 struct route_node *rn;
3285 struct rip_distance *rdistance;
3286 int header = 1;
3287 char buf[BUFSIZ];
3288
3289 vty_out (vty, " Distance: (default is %d)%s",
3290 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3291 VTY_NEWLINE);
3292
3293 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3294 if ((rdistance = rn->info) != NULL)
3295 {
3296 if (header)
3297 {
3298 vty_out (vty, " Address Distance List%s",
3299 VTY_NEWLINE);
3300 header = 0;
3301 }
3302 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3303 vty_out (vty, " %-20s %4d %s%s",
3304 buf, rdistance->distance,
3305 rdistance->access_list ? rdistance->access_list : "",
3306 VTY_NEWLINE);
3307 }
3308}
3309
3310DEFUN (rip_distance,
3311 rip_distance_cmd,
3312 "distance <1-255>",
3313 "Administrative distance\n"
3314 "Distance value\n")
3315{
3316 rip->distance = atoi (argv[0]);
3317 return CMD_SUCCESS;
3318}
3319
3320DEFUN (no_rip_distance,
3321 no_rip_distance_cmd,
3322 "no distance <1-255>",
3323 NO_STR
3324 "Administrative distance\n"
3325 "Distance value\n")
3326{
3327 rip->distance = 0;
3328 return CMD_SUCCESS;
3329}
3330
3331DEFUN (rip_distance_source,
3332 rip_distance_source_cmd,
3333 "distance <1-255> A.B.C.D/M",
3334 "Administrative distance\n"
3335 "Distance value\n"
3336 "IP source prefix\n")
3337{
3338 rip_distance_set (vty, argv[0], argv[1], NULL);
3339 return CMD_SUCCESS;
3340}
3341
3342DEFUN (no_rip_distance_source,
3343 no_rip_distance_source_cmd,
3344 "no distance <1-255> A.B.C.D/M",
3345 NO_STR
3346 "Administrative distance\n"
3347 "Distance value\n"
3348 "IP source prefix\n")
3349{
3350 rip_distance_unset (vty, argv[0], argv[1], NULL);
3351 return CMD_SUCCESS;
3352}
3353
3354DEFUN (rip_distance_source_access_list,
3355 rip_distance_source_access_list_cmd,
3356 "distance <1-255> A.B.C.D/M WORD",
3357 "Administrative distance\n"
3358 "Distance value\n"
3359 "IP source prefix\n"
3360 "Access list name\n")
3361{
3362 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3363 return CMD_SUCCESS;
3364}
3365
3366DEFUN (no_rip_distance_source_access_list,
3367 no_rip_distance_source_access_list_cmd,
3368 "no distance <1-255> A.B.C.D/M WORD",
3369 NO_STR
3370 "Administrative distance\n"
3371 "Distance value\n"
3372 "IP source prefix\n"
3373 "Access list name\n")
3374{
3375 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3376 return CMD_SUCCESS;
3377}
David Lamparter6b0655a2014-06-04 06:53:35 +02003378
Lu Feng0b74a0a2014-07-18 06:13:19 +00003379/* Update ECMP routes to zebra when ECMP is disabled. */
3380static void
3381rip_ecmp_disable (void)
3382{
3383 struct route_node *rp;
3384 struct rip_info *rinfo, *tmp_rinfo;
3385 struct list *list;
3386 struct listnode *node, *nextnode;
3387
3388 if (!rip)
3389 return;
3390
3391 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3392 if ((list = rp->info) != NULL && listcount (list) > 1)
3393 {
3394 rinfo = listgetdata (listhead (list));
3395 if (!rip_route_rte (rinfo))
3396 continue;
3397
3398 /* Drop all other entries, except the first one. */
3399 for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
3400 if (tmp_rinfo != rinfo)
3401 {
3402 RIP_TIMER_OFF (tmp_rinfo->t_timeout);
3403 RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect);
3404 list_delete_node (list, node);
3405 rip_info_free (tmp_rinfo);
3406 }
3407
3408 /* Update zebra. */
3409 rip_zebra_ipv4_add (rp);
3410
3411 /* Set the route change flag. */
3412 SET_FLAG (rinfo->flags, RIP_RTF_CHANGED);
3413
3414 /* Signal the output process to trigger an update. */
3415 rip_event (RIP_TRIGGERED_UPDATE, 0);
3416 }
3417}
3418
3419DEFUN (rip_allow_ecmp,
3420 rip_allow_ecmp_cmd,
3421 "allow-ecmp",
3422 "Allow Equal Cost MultiPath\n")
3423{
3424 if (rip->ecmp)
3425 {
3426 vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
3427 return CMD_WARNING;
3428 }
3429
3430 rip->ecmp = 1;
3431 zlog_info ("ECMP is enabled.");
3432 return CMD_SUCCESS;
3433}
3434
3435DEFUN (no_rip_allow_ecmp,
3436 no_rip_allow_ecmp_cmd,
3437 "no allow-ecmp",
3438 NO_STR
3439 "Allow Equal Cost MultiPath\n")
3440{
3441 if (!rip->ecmp)
3442 {
3443 vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
3444 return CMD_WARNING;
3445 }
3446
3447 rip->ecmp = 0;
3448 zlog_info ("ECMP is disabled.");
3449 rip_ecmp_disable ();
3450 return CMD_SUCCESS;
3451}
3452
paul718e3742002-12-13 20:15:29 +00003453/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003454static void
paul718e3742002-12-13 20:15:29 +00003455rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3456{
paul718e3742002-12-13 20:15:29 +00003457 time_t clock;
3458 struct tm *tm;
3459#define TIME_BUF 25
3460 char timebuf [TIME_BUF];
3461 struct thread *thread;
3462
paul718e3742002-12-13 20:15:29 +00003463 if ((thread = rinfo->t_timeout) != NULL)
3464 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003465 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003466 tm = gmtime (&clock);
3467 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3468 vty_out (vty, "%5s", timebuf);
3469 }
3470 else if ((thread = rinfo->t_garbage_collect) != NULL)
3471 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003472 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003473 tm = gmtime (&clock);
3474 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3475 vty_out (vty, "%5s", timebuf);
3476 }
3477}
3478
pauldc63bfd2005-10-25 23:31:05 +00003479static const char *
paul718e3742002-12-13 20:15:29 +00003480rip_route_type_print (int sub_type)
3481{
3482 switch (sub_type)
3483 {
3484 case RIP_ROUTE_RTE:
3485 return "n";
3486 case RIP_ROUTE_STATIC:
3487 return "s";
3488 case RIP_ROUTE_DEFAULT:
3489 return "d";
3490 case RIP_ROUTE_REDISTRIBUTE:
3491 return "r";
3492 case RIP_ROUTE_INTERFACE:
3493 return "i";
3494 default:
3495 return "?";
3496 }
3497}
3498
3499DEFUN (show_ip_rip,
3500 show_ip_rip_cmd,
3501 "show ip rip",
3502 SHOW_STR
3503 IP_STR
3504 "Show RIP routes\n")
3505{
3506 struct route_node *np;
Lu Fengb397cf42014-07-18 06:13:18 +00003507 struct rip_info *rinfo = NULL;
3508 struct list *list = NULL;
3509 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003510
3511 if (! rip)
3512 return CMD_SUCCESS;
3513
hasso16705132003-05-25 14:49:19 +00003514 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3515 "Sub-codes:%s"
3516 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003517 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003518 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003519 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003520
3521 for (np = route_top (rip->table); np; np = route_next (np))
Lu Fengb397cf42014-07-18 06:13:18 +00003522 if ((list = np->info) != NULL)
3523 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
paul718e3742002-12-13 20:15:29 +00003524 {
3525 int len;
3526
ajsf52d13c2005-10-01 17:38:06 +00003527 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003528 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003529 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003530 rip_route_type_print (rinfo->sub_type),
3531 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3532
hassoa1455d82004-03-03 19:36:24 +00003533 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003534
3535 if (len > 0)
3536 vty_out (vty, "%*s", len, " ");
3537
3538 if (rinfo->nexthop.s_addr)
3539 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3540 rinfo->metric);
3541 else
3542 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3543
3544 /* Route which exist in kernel routing table. */
3545 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3546 (rinfo->sub_type == RIP_ROUTE_RTE))
3547 {
3548 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003549 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003550 rip_vty_out_uptime (vty, rinfo);
3551 }
3552 else if (rinfo->metric == RIP_METRIC_INFINITY)
3553 {
3554 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003555 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003556 rip_vty_out_uptime (vty, rinfo);
3557 }
3558 else
hasso16705132003-05-25 14:49:19 +00003559 {
vincentfbf5d032005-09-29 11:25:50 +00003560 if (rinfo->external_metric)
3561 {
3562 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003563 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003564 rinfo->external_metric);
3565 len = 16 - len;
3566 if (len > 0)
3567 vty_out (vty, "%*s", len, " ");
3568 }
3569 else
3570 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003571 vty_out (vty, "%3d", rinfo->tag);
3572 }
paul718e3742002-12-13 20:15:29 +00003573
3574 vty_out (vty, "%s", VTY_NEWLINE);
3575 }
3576 return CMD_SUCCESS;
3577}
3578
hasso16705132003-05-25 14:49:19 +00003579/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3580DEFUN (show_ip_rip_status,
3581 show_ip_rip_status_cmd,
3582 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003583 SHOW_STR
3584 IP_STR
hasso16705132003-05-25 14:49:19 +00003585 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003586 "IP routing protocol process parameters and statistics\n")
3587{
hasso52dc7ee2004-09-23 19:18:23 +00003588 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003589 struct interface *ifp;
3590 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003591 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003592 const char *send_version;
3593 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003594
3595 if (! rip)
3596 return CMD_SUCCESS;
3597
3598 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3599 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3600 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003601 vty_out (vty, " next due in %lu seconds%s",
3602 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003603 VTY_NEWLINE);
3604 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3605 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3606 VTY_NEWLINE);
3607
3608 /* Filtering status show. */
3609 config_show_distribute (vty);
3610
3611 /* Default metric information. */
3612 vty_out (vty, " Default redistribution metric is %d%s",
3613 rip->default_metric, VTY_NEWLINE);
3614
3615 /* Redistribute information. */
3616 vty_out (vty, " Redistributing:");
3617 config_write_rip_redistribute (vty, 0);
3618 vty_out (vty, "%s", VTY_NEWLINE);
3619
paulf38a4712003-06-07 01:10:00 +00003620 vty_out (vty, " Default version control: send version %s,",
3621 lookup(ri_version_msg,rip->version_send));
3622 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3623 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3624 else
3625 vty_out (vty, " receive version %s %s",
3626 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003627
3628 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3629
paul1eb8ef22005-04-07 07:30:20 +00003630 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003631 {
paul718e3742002-12-13 20:15:29 +00003632 ri = ifp->info;
3633
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003634 if (!ri->running)
3635 continue;
3636
paul718e3742002-12-13 20:15:29 +00003637 if (ri->enable_network || ri->enable_interface)
3638 {
3639 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003640 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003641 else
3642 send_version = lookup (ri_version_msg, ri->ri_send);
3643
3644 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003645 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003646 else
3647 receive_version = lookup (ri_version_msg, ri->ri_receive);
3648
3649 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3650 send_version,
3651 receive_version,
3652 ri->key_chain ? ri->key_chain : "",
3653 VTY_NEWLINE);
3654 }
3655 }
3656
3657 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3658 config_write_rip_network (vty, 0);
3659
paul4aaff3f2003-06-07 01:04:45 +00003660 {
3661 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003662 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003663 {
paul4aaff3f2003-06-07 01:04:45 +00003664 ri = ifp->info;
3665
3666 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3667 {
3668 if (!found_passive)
3669 {
3670 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3671 found_passive = 1;
3672 }
3673 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3674 }
3675 }
3676 }
3677
paul718e3742002-12-13 20:15:29 +00003678 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3679 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3680 rip_peer_display (vty);
3681
3682 rip_distance_show (vty);
3683
3684 return CMD_SUCCESS;
3685}
3686
3687/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003688static int
paul718e3742002-12-13 20:15:29 +00003689config_write_rip (struct vty *vty)
3690{
3691 int write = 0;
3692 struct route_node *rn;
3693 struct rip_distance *rdistance;
3694
3695 if (rip)
3696 {
3697 /* Router RIP statement. */
3698 vty_out (vty, "router rip%s", VTY_NEWLINE);
3699 write++;
3700
3701 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003702 if (rip->version_send != RI_RIP_VERSION_2
3703 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3704 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003705 VTY_NEWLINE);
3706
3707 /* RIP timer configuration. */
3708 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3709 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3710 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3711 vty_out (vty, " timers basic %lu %lu %lu%s",
3712 rip->update_time,
3713 rip->timeout_time,
3714 rip->garbage_time,
3715 VTY_NEWLINE);
3716
3717 /* Default information configuration. */
3718 if (rip->default_information)
3719 {
3720 if (rip->default_information_route_map)
3721 vty_out (vty, " default-information originate route-map %s%s",
3722 rip->default_information_route_map, VTY_NEWLINE);
3723 else
3724 vty_out (vty, " default-information originate%s",
3725 VTY_NEWLINE);
3726 }
3727
3728 /* Redistribute configuration. */
3729 config_write_rip_redistribute (vty, 1);
3730
3731 /* RIP offset-list configuration. */
3732 config_write_rip_offset_list (vty);
3733
3734 /* RIP enabled network and interface configuration. */
3735 config_write_rip_network (vty, 1);
3736
3737 /* RIP default metric configuration */
3738 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3739 vty_out (vty, " default-metric %d%s",
3740 rip->default_metric, VTY_NEWLINE);
3741
3742 /* Distribute configuration. */
3743 write += config_write_distribute (vty);
3744
hasso16705132003-05-25 14:49:19 +00003745 /* Interface routemap configuration */
3746 write += config_write_if_rmap (vty);
3747
paul718e3742002-12-13 20:15:29 +00003748 /* Distance configuration. */
3749 if (rip->distance)
3750 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3751
3752 /* RIP source IP prefix distance configuration. */
3753 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3754 if ((rdistance = rn->info) != NULL)
3755 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3756 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3757 rdistance->access_list ? rdistance->access_list : "",
3758 VTY_NEWLINE);
3759
Lu Feng0b74a0a2014-07-18 06:13:19 +00003760 /* ECMP configuration. */
3761 if (rip->ecmp)
3762 vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
3763
paul718e3742002-12-13 20:15:29 +00003764 /* RIP static route configuration. */
3765 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3766 if (rn->info)
3767 vty_out (vty, " route %s/%d%s",
3768 inet_ntoa (rn->p.u.prefix4),
3769 rn->p.prefixlen,
3770 VTY_NEWLINE);
3771
3772 }
3773 return write;
3774}
3775
3776/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003777static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003778{
3779 RIP_NODE,
3780 "%s(config-router)# ",
3781 1
3782};
David Lamparter6b0655a2014-06-04 06:53:35 +02003783
paul718e3742002-12-13 20:15:29 +00003784/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003785static void
paul718e3742002-12-13 20:15:29 +00003786rip_distribute_update (struct distribute *dist)
3787{
3788 struct interface *ifp;
3789 struct rip_interface *ri;
3790 struct access_list *alist;
3791 struct prefix_list *plist;
3792
3793 if (! dist->ifname)
3794 return;
3795
3796 ifp = if_lookup_by_name (dist->ifname);
3797 if (ifp == NULL)
3798 return;
3799
3800 ri = ifp->info;
3801
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003802 if (dist->list[DISTRIBUTE_V4_IN])
paul718e3742002-12-13 20:15:29 +00003803 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003804 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]);
paul718e3742002-12-13 20:15:29 +00003805 if (alist)
3806 ri->list[RIP_FILTER_IN] = alist;
3807 else
3808 ri->list[RIP_FILTER_IN] = NULL;
3809 }
3810 else
3811 ri->list[RIP_FILTER_IN] = NULL;
3812
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003813 if (dist->list[DISTRIBUTE_V4_OUT])
paul718e3742002-12-13 20:15:29 +00003814 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003815 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]);
paul718e3742002-12-13 20:15:29 +00003816 if (alist)
3817 ri->list[RIP_FILTER_OUT] = alist;
3818 else
3819 ri->list[RIP_FILTER_OUT] = NULL;
3820 }
3821 else
3822 ri->list[RIP_FILTER_OUT] = NULL;
3823
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003824 if (dist->prefix[DISTRIBUTE_V4_IN])
paul718e3742002-12-13 20:15:29 +00003825 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003826 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]);
paul718e3742002-12-13 20:15:29 +00003827 if (plist)
3828 ri->prefix[RIP_FILTER_IN] = plist;
3829 else
3830 ri->prefix[RIP_FILTER_IN] = NULL;
3831 }
3832 else
3833 ri->prefix[RIP_FILTER_IN] = NULL;
3834
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003835 if (dist->prefix[DISTRIBUTE_V4_OUT])
paul718e3742002-12-13 20:15:29 +00003836 {
Matthieu Boutierdf2ef242014-09-10 16:50:45 +02003837 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]);
paul718e3742002-12-13 20:15:29 +00003838 if (plist)
3839 ri->prefix[RIP_FILTER_OUT] = plist;
3840 else
3841 ri->prefix[RIP_FILTER_OUT] = NULL;
3842 }
3843 else
3844 ri->prefix[RIP_FILTER_OUT] = NULL;
3845}
3846
3847void
3848rip_distribute_update_interface (struct interface *ifp)
3849{
3850 struct distribute *dist;
3851
3852 dist = distribute_lookup (ifp->name);
3853 if (dist)
3854 rip_distribute_update (dist);
3855}
3856
3857/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003858/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003859static void
paul02ff83c2004-06-11 11:27:03 +00003860rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003861{
3862 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003863 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003864
paul1eb8ef22005-04-07 07:30:20 +00003865 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3866 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003867}
paul11dde9c2004-05-31 14:00:00 +00003868/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003869static void
paul11dde9c2004-05-31 14:00:00 +00003870rip_distribute_update_all_wrapper(struct access_list *notused)
3871{
paul02ff83c2004-06-11 11:27:03 +00003872 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003873}
David Lamparter6b0655a2014-06-04 06:53:35 +02003874
paul718e3742002-12-13 20:15:29 +00003875/* Delete all added rip route. */
3876void
paul216565a2005-10-25 23:35:28 +00003877rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003878{
3879 int i;
3880 struct route_node *rp;
Lu Fengb397cf42014-07-18 06:13:18 +00003881 struct rip_info *rinfo = NULL;
3882 struct list *list = NULL;
3883 struct listnode *listnode = NULL;
paul718e3742002-12-13 20:15:29 +00003884
3885 if (rip)
3886 {
3887 /* Clear RIP routes */
3888 for (rp = route_top (rip->table); rp; rp = route_next (rp))
Lu Fengb397cf42014-07-18 06:13:18 +00003889 if ((list = rp->info) != NULL)
3890 {
3891 rinfo = listgetdata (listhead (list));
3892 if (rip_route_rte (rinfo))
3893 rip_zebra_ipv4_delete (rp);
paul718e3742002-12-13 20:15:29 +00003894
Lu Fengb397cf42014-07-18 06:13:18 +00003895 for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
3896 {
3897 RIP_TIMER_OFF (rinfo->t_timeout);
3898 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3899 rip_info_free (rinfo);
3900 }
3901 list_delete (list);
3902 rp->info = NULL;
3903 route_unlock_node (rp);
3904 }
paul718e3742002-12-13 20:15:29 +00003905
3906 /* Cancel RIP related timers. */
3907 RIP_TIMER_OFF (rip->t_update);
3908 RIP_TIMER_OFF (rip->t_triggered_update);
3909 RIP_TIMER_OFF (rip->t_triggered_interval);
3910
3911 /* Cancel read thread. */
3912 if (rip->t_read)
3913 {
3914 thread_cancel (rip->t_read);
3915 rip->t_read = NULL;
3916 }
3917
3918 /* Close RIP socket. */
3919 if (rip->sock >= 0)
3920 {
3921 close (rip->sock);
3922 rip->sock = -1;
3923 }
3924
3925 /* Static RIP route configuration. */
3926 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3927 if (rp->info)
3928 {
3929 rp->info = NULL;
3930 route_unlock_node (rp);
3931 }
3932
3933 /* RIP neighbor configuration. */
3934 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3935 if (rp->info)
3936 {
3937 rp->info = NULL;
3938 route_unlock_node (rp);
3939 }
3940
3941 /* Redistribute related clear. */
3942 if (rip->default_information_route_map)
3943 free (rip->default_information_route_map);
3944
3945 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3946 if (rip->route_map[i].name)
3947 free (rip->route_map[i].name);
3948
3949 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3950 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3951 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3952
3953 XFREE (MTYPE_RIP, rip);
3954 rip = NULL;
3955 }
3956
3957 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003958 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003959 rip_offset_clean ();
Paul Jakmad319a3a2016-05-25 14:47:00 +01003960 rip_interfaces_clean ();
paul718e3742002-12-13 20:15:29 +00003961 rip_distance_reset ();
3962 rip_redistribute_clean ();
3963}
3964
3965/* Reset all values to the default settings. */
3966void
paul216565a2005-10-25 23:35:28 +00003967rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003968{
3969 /* Reset global counters. */
3970 rip_global_route_changes = 0;
3971 rip_global_queries = 0;
3972
3973 /* Call ripd related reset functions. */
3974 rip_debug_reset ();
3975 rip_route_map_reset ();
3976
3977 /* Call library reset functions. */
3978 vty_reset ();
3979 access_list_reset ();
3980 prefix_list_reset ();
3981
3982 distribute_list_reset ();
3983
Paul Jakmad319a3a2016-05-25 14:47:00 +01003984 rip_interfaces_reset ();
paul718e3742002-12-13 20:15:29 +00003985 rip_distance_reset ();
3986
3987 rip_zclient_reset ();
3988}
3989
pauldc63bfd2005-10-25 23:31:05 +00003990static void
hasso16705132003-05-25 14:49:19 +00003991rip_if_rmap_update (struct if_rmap *if_rmap)
3992{
3993 struct interface *ifp;
3994 struct rip_interface *ri;
3995 struct route_map *rmap;
3996
3997 ifp = if_lookup_by_name (if_rmap->ifname);
3998 if (ifp == NULL)
3999 return;
4000
4001 ri = ifp->info;
4002
4003 if (if_rmap->routemap[IF_RMAP_IN])
4004 {
4005 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
4006 if (rmap)
4007 ri->routemap[IF_RMAP_IN] = rmap;
4008 else
4009 ri->routemap[IF_RMAP_IN] = NULL;
4010 }
4011 else
4012 ri->routemap[RIP_FILTER_IN] = NULL;
4013
4014 if (if_rmap->routemap[IF_RMAP_OUT])
4015 {
4016 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
4017 if (rmap)
4018 ri->routemap[IF_RMAP_OUT] = rmap;
4019 else
4020 ri->routemap[IF_RMAP_OUT] = NULL;
4021 }
4022 else
4023 ri->routemap[RIP_FILTER_OUT] = NULL;
4024}
4025
4026void
4027rip_if_rmap_update_interface (struct interface *ifp)
4028{
4029 struct if_rmap *if_rmap;
4030
4031 if_rmap = if_rmap_lookup (ifp->name);
4032 if (if_rmap)
4033 rip_if_rmap_update (if_rmap);
4034}
4035
pauldc63bfd2005-10-25 23:31:05 +00004036static void
hasso16705132003-05-25 14:49:19 +00004037rip_routemap_update_redistribute (void)
4038{
4039 int i;
4040
4041 if (rip)
4042 {
4043 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
4044 {
4045 if (rip->route_map[i].name)
4046 rip->route_map[i].map =
4047 route_map_lookup_by_name (rip->route_map[i].name);
4048 }
4049 }
4050}
4051
paul11dde9c2004-05-31 14:00:00 +00004052/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00004053static void
hasso98b718a2004-10-11 12:57:57 +00004054rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00004055{
4056 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00004057 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00004058
paul1eb8ef22005-04-07 07:30:20 +00004059 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
4060 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00004061
4062 rip_routemap_update_redistribute ();
4063}
4064
paul718e3742002-12-13 20:15:29 +00004065/* Allocate new rip structure and set default value. */
4066void
pauldc63bfd2005-10-25 23:31:05 +00004067rip_init (void)
paul718e3742002-12-13 20:15:29 +00004068{
4069 /* Randomize for triggered update random(). */
Donald Sharpf31bab42015-06-19 19:26:19 -04004070 srandom (time (NULL));
paul718e3742002-12-13 20:15:29 +00004071
4072 /* Install top nodes. */
4073 install_node (&rip_node, config_write_rip);
4074
4075 /* Install rip commands. */
4076 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00004077 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00004078 install_element (CONFIG_NODE, &router_rip_cmd);
4079 install_element (CONFIG_NODE, &no_router_rip_cmd);
4080
4081 install_default (RIP_NODE);
4082 install_element (RIP_NODE, &rip_version_cmd);
4083 install_element (RIP_NODE, &no_rip_version_cmd);
4084 install_element (RIP_NODE, &no_rip_version_val_cmd);
4085 install_element (RIP_NODE, &rip_default_metric_cmd);
4086 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4087 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4088 install_element (RIP_NODE, &rip_timers_cmd);
4089 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004090 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004091 install_element (RIP_NODE, &rip_route_cmd);
4092 install_element (RIP_NODE, &no_rip_route_cmd);
4093 install_element (RIP_NODE, &rip_distance_cmd);
4094 install_element (RIP_NODE, &no_rip_distance_cmd);
4095 install_element (RIP_NODE, &rip_distance_source_cmd);
4096 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4097 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4098 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
Lu Feng0b74a0a2014-07-18 06:13:19 +00004099 install_element (RIP_NODE, &rip_allow_ecmp_cmd);
4100 install_element (RIP_NODE, &no_rip_allow_ecmp_cmd);
paul718e3742002-12-13 20:15:29 +00004101
4102 /* Debug related init. */
4103 rip_debug_init ();
4104
paul718e3742002-12-13 20:15:29 +00004105 /* SNMP init. */
4106#ifdef HAVE_SNMP
4107 rip_snmp_init ();
4108#endif /* HAVE_SNMP */
4109
4110 /* Access list install. */
4111 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004112 access_list_add_hook (rip_distribute_update_all_wrapper);
4113 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004114
4115 /* Prefix list initialize.*/
4116 prefix_list_init ();
4117 prefix_list_add_hook (rip_distribute_update_all);
4118 prefix_list_delete_hook (rip_distribute_update_all);
4119
4120 /* Distribute list install. */
4121 distribute_list_init (RIP_NODE);
4122 distribute_list_add_hook (rip_distribute_update);
4123 distribute_list_delete_hook (rip_distribute_update);
4124
hasso16705132003-05-25 14:49:19 +00004125 /* Route-map */
4126 rip_route_map_init ();
4127 rip_offset_init ();
4128
4129 route_map_add_hook (rip_routemap_update);
4130 route_map_delete_hook (rip_routemap_update);
4131
4132 if_rmap_init (RIP_NODE);
4133 if_rmap_hook_add (rip_if_rmap_update);
4134 if_rmap_hook_delete (rip_if_rmap_update);
4135
paul718e3742002-12-13 20:15:29 +00004136 /* Distance control. */
4137 rip_distance_table = route_table_init ();
4138}