blob: 8a7fef875b198b8c37e14bf34b0565ffb73006f2 [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. */
141 rp->info = NULL;
142 route_unlock_node (rp);
143
144 /* Free RIP routing information. */
145 rip_info_free (rinfo);
146
147 return 0;
148}
149
150/* Timeout RIP routes. */
pauldc63bfd2005-10-25 23:31:05 +0000151static int
paul718e3742002-12-13 20:15:29 +0000152rip_timeout (struct thread *t)
153{
154 struct rip_info *rinfo;
155 struct route_node *rn;
156
157 rinfo = THREAD_ARG (t);
158 rinfo->t_timeout = NULL;
159
160 rn = rinfo->rp;
161
162 /* - The garbage-collection timer is set for 120 seconds. */
163 RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
164 rip->garbage_time);
165
166 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
167 rinfo->metric);
168 /* - The metric for the route is set to 16 (infinity). This causes
169 the route to be removed from service. */
170 rinfo->metric = RIP_METRIC_INFINITY;
171 rinfo->flags &= ~RIP_RTF_FIB;
172
173 /* - The route change flag is to indicate that this entry has been
174 changed. */
175 rinfo->flags |= RIP_RTF_CHANGED;
176
177 /* - The output process is signalled to trigger a response. */
178 rip_event (RIP_TRIGGERED_UPDATE, 0);
179
180 return 0;
181}
182
pauldc63bfd2005-10-25 23:31:05 +0000183static void
paul718e3742002-12-13 20:15:29 +0000184rip_timeout_update (struct rip_info *rinfo)
185{
186 if (rinfo->metric != RIP_METRIC_INFINITY)
187 {
188 RIP_TIMER_OFF (rinfo->t_timeout);
189 RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
190 }
191}
192
pauldc63bfd2005-10-25 23:31:05 +0000193static int
paul718e3742002-12-13 20:15:29 +0000194rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
195{
196 struct distribute *dist;
197 struct access_list *alist;
198 struct prefix_list *plist;
199
200 /* Input distribute-list filtering. */
201 if (ri->list[RIP_FILTER_IN])
202 {
203 if (access_list_apply (ri->list[RIP_FILTER_IN],
204 (struct prefix *) p) == FILTER_DENY)
205 {
206 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000207 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000208 inet_ntoa (p->prefix), p->prefixlen);
209 return -1;
210 }
211 }
212 if (ri->prefix[RIP_FILTER_IN])
213 {
214 if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
215 (struct prefix *) p) == PREFIX_DENY)
216 {
217 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000218 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000219 inet_ntoa (p->prefix), p->prefixlen);
220 return -1;
221 }
222 }
223
224 /* All interface filter check. */
225 dist = distribute_lookup (NULL);
226 if (dist)
227 {
228 if (dist->list[DISTRIBUTE_IN])
229 {
230 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
231
232 if (alist)
233 {
234 if (access_list_apply (alist,
235 (struct prefix *) p) == FILTER_DENY)
236 {
237 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000238 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000239 inet_ntoa (p->prefix), p->prefixlen);
240 return -1;
241 }
242 }
243 }
244 if (dist->prefix[DISTRIBUTE_IN])
245 {
246 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
247
248 if (plist)
249 {
250 if (prefix_list_apply (plist,
251 (struct prefix *) p) == PREFIX_DENY)
252 {
253 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000254 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000255 inet_ntoa (p->prefix), p->prefixlen);
256 return -1;
257 }
258 }
259 }
260 }
261 return 0;
262}
263
pauldc63bfd2005-10-25 23:31:05 +0000264static int
paul718e3742002-12-13 20:15:29 +0000265rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
266{
267 struct distribute *dist;
268 struct access_list *alist;
269 struct prefix_list *plist;
270
271 if (ri->list[RIP_FILTER_OUT])
272 {
273 if (access_list_apply (ri->list[RIP_FILTER_OUT],
274 (struct prefix *) p) == FILTER_DENY)
275 {
276 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000277 zlog_debug ("%s/%d is filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000278 inet_ntoa (p->prefix), p->prefixlen);
279 return -1;
280 }
281 }
282 if (ri->prefix[RIP_FILTER_OUT])
283 {
284 if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
285 (struct prefix *) p) == PREFIX_DENY)
286 {
287 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000288 zlog_debug ("%s/%d is filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000289 inet_ntoa (p->prefix), p->prefixlen);
290 return -1;
291 }
292 }
293
294 /* All interface filter check. */
295 dist = distribute_lookup (NULL);
296 if (dist)
297 {
298 if (dist->list[DISTRIBUTE_OUT])
299 {
300 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
301
302 if (alist)
303 {
304 if (access_list_apply (alist,
305 (struct prefix *) p) == FILTER_DENY)
306 {
307 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000308 zlog_debug ("%s/%d filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000309 inet_ntoa (p->prefix), p->prefixlen);
310 return -1;
311 }
312 }
313 }
314 if (dist->prefix[DISTRIBUTE_OUT])
315 {
316 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
317
318 if (plist)
319 {
320 if (prefix_list_apply (plist,
321 (struct prefix *) p) == PREFIX_DENY)
322 {
323 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000324 zlog_debug ("%s/%d filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000325 inet_ntoa (p->prefix), p->prefixlen);
326 return -1;
327 }
328 }
329 }
330 }
331 return 0;
332}
333
334/* Check nexthop address validity. */
335static int
336rip_nexthop_check (struct in_addr *addr)
337{
hasso52dc7ee2004-09-23 19:18:23 +0000338 struct listnode *node;
339 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000340 struct interface *ifp;
341 struct connected *ifc;
342 struct prefix *p;
343
344 /* If nexthop address matches local configured address then it is
345 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000346 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000347 {
paul1eb8ef22005-04-07 07:30:20 +0000348 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000349 {
paul718e3742002-12-13 20:15:29 +0000350 p = ifc->address;
351
352 if (p->family == AF_INET
353 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
354 return -1;
355 }
356 }
357 return 0;
358}
359
360/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000361static void
paul718e3742002-12-13 20:15:29 +0000362rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000363 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000364{
365 int ret;
366 struct prefix_ipv4 p;
367 struct route_node *rp;
paulb94f9db2004-05-01 20:45:38 +0000368 struct rip_info *rinfo, rinfotmp;
paul718e3742002-12-13 20:15:29 +0000369 struct rip_interface *ri;
370 struct in_addr *nexthop;
371 u_char oldmetric;
372 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000373 int route_reuse = 0;
374 unsigned char old_dist, new_dist;
paul718e3742002-12-13 20:15:29 +0000375
376 /* Make prefix structure. */
377 memset (&p, 0, sizeof (struct prefix_ipv4));
378 p.family = AF_INET;
379 p.prefix = rte->prefix;
380 p.prefixlen = ip_masklen (rte->mask);
381
382 /* Make sure mask is applied. */
383 apply_mask_ipv4 (&p);
384
385 /* Apply input filters. */
386 ri = ifp->info;
387
388 ret = rip_incoming_filter (&p, ri);
389 if (ret < 0)
390 return;
391
hasso16705132003-05-25 14:49:19 +0000392 /* Modify entry according to the interface routemap. */
393 if (ri->routemap[RIP_FILTER_IN])
394 {
395 int ret;
396 struct rip_info newinfo;
397
398 memset (&newinfo, 0, sizeof (newinfo));
399 newinfo.type = ZEBRA_ROUTE_RIP;
400 newinfo.sub_type = RIP_ROUTE_RTE;
paula87552c2004-05-03 20:00:17 +0000401 newinfo.nexthop = rte->nexthop;
402 newinfo.from = from->sin_addr;
403 newinfo.ifindex = ifp->ifindex;
hasso16705132003-05-25 14:49:19 +0000404 newinfo.metric = rte->metric;
405 newinfo.metric_out = rte->metric; /* XXX */
paula87552c2004-05-03 20:00:17 +0000406 newinfo.tag = ntohs (rte->tag); /* XXX */
hasso16705132003-05-25 14:49:19 +0000407
408 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000409 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
410 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000411
412 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000413 {
414 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000415 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000416 inet_ntoa (p.prefix), p.prefixlen);
417 return;
418 }
hasso16705132003-05-25 14:49:19 +0000419
420 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000421 rte->nexthop = newinfo.nexthop_out;
422 rte->tag = htons (newinfo.tag_out); /* XXX */
423 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000424 }
425
paul718e3742002-12-13 20:15:29 +0000426 /* Once the entry has been validated, update the metric by
427 adding the cost of the network on wich the message
428 arrived. If the result is greater than infinity, use infinity
429 (RFC2453 Sec. 3.9.2) */
430 /* Zebra ripd can handle offset-list in. */
431 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
432
433 /* If offset-list does not modify the metric use interface's
434 metric. */
paula87552c2004-05-03 20:00:17 +0000435 if (!ret)
Lu Feng7b3b98a2014-04-14 08:09:29 +0000436 rte->metric += ifp->metric ? ifp->metric : 1;
paul718e3742002-12-13 20:15:29 +0000437
438 if (rte->metric > RIP_METRIC_INFINITY)
439 rte->metric = RIP_METRIC_INFINITY;
440
441 /* Set nexthop pointer. */
442 if (rte->nexthop.s_addr == 0)
443 nexthop = &from->sin_addr;
444 else
445 nexthop = &rte->nexthop;
446
hasso16705132003-05-25 14:49:19 +0000447 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000448 if (rip_nexthop_check (nexthop) < 0)
449 {
450 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000451 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000452 return;
453 }
454
455 /* Get index for the prefix. */
456 rp = route_node_get (rip->table, (struct prefix *) &p);
457
458 /* Check to see whether there is already RIP route on the table. */
459 rinfo = rp->info;
460
461 if (rinfo)
462 {
paul718e3742002-12-13 20:15:29 +0000463 /* Local static route. */
464 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000465 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
466 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
467 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000468 {
469 route_unlock_node (rp);
470 return;
471 }
472
473 /* Redistributed route check. */
474 if (rinfo->type != ZEBRA_ROUTE_RIP
475 && rinfo->metric != RIP_METRIC_INFINITY)
476 {
477 /* Fill in a minimaly temporary rip_info structure, for a future
478 rip_distance_apply() use) */
479 memset (&rinfotmp, 0, sizeof (rinfotmp));
480 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
481 rinfotmp.rp = rinfo->rp;
482 new_dist = rip_distance_apply (&rinfotmp);
483 new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
484 old_dist = rinfo->distance;
David Lamparterb68da442013-02-28 22:17:00 +0100485 /* Only routes directly connected to an interface (nexthop == 0)
486 * may have a valid NULL distance */
487 if (rinfo->nexthop.s_addr != 0)
vincent7a383332006-01-30 18:12:42 +0000488 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000489 /* If imported route does not have STRICT precedence,
490 mark it as a ghost */
491 if (new_dist > old_dist
492 || rte->metric == RIP_METRIC_INFINITY)
493 {
494 route_unlock_node (rp);
495 return;
496 }
497 else
498 {
499 RIP_TIMER_OFF (rinfo->t_timeout);
500 RIP_TIMER_OFF (rinfo->t_garbage_collect);
501
502 rp->info = NULL;
503 if (rip_route_rte (rinfo))
504 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
505 &rinfo->nexthop, rinfo->metric);
506 rip_info_free (rinfo);
507 rinfo = NULL;
508 route_reuse = 1;
509 }
510 }
paul718e3742002-12-13 20:15:29 +0000511 }
paula87552c2004-05-03 20:00:17 +0000512
513 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000514 {
515 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000516 for the destination prefix. If there is no such route, add
517 this route to the routing table, unless the metric is
518 infinity (there is no point in adding a route which
519 unusable). */
paul718e3742002-12-13 20:15:29 +0000520 if (rte->metric != RIP_METRIC_INFINITY)
paula87552c2004-05-03 20:00:17 +0000521 {
522 rinfo = rip_info_new ();
paul718e3742002-12-13 20:15:29 +0000523
paula87552c2004-05-03 20:00:17 +0000524 /* - Setting the destination prefix and length to those in
525 the RTE. */
526 rinfo->rp = rp;
paul718e3742002-12-13 20:15:29 +0000527
paula87552c2004-05-03 20:00:17 +0000528 /* - Setting the metric to the newly calculated metric (as
529 described above). */
530 rinfo->metric = rte->metric;
531 rinfo->tag = ntohs (rte->tag);
paul718e3742002-12-13 20:15:29 +0000532
paula87552c2004-05-03 20:00:17 +0000533 /* - Set the next hop address to be the address of the router
534 from which the datagram came or the next hop address
535 specified by a next hop RTE. */
536 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
537 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
538 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000539
paula87552c2004-05-03 20:00:17 +0000540 /* - Initialize the timeout for the route. If the
541 garbage-collection timer is running for this route, stop it
542 (see section 2.3 for a discussion of the timers). */
543 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000544
paula87552c2004-05-03 20:00:17 +0000545 /* - Set the route change flag. */
546 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +0000547
paula87552c2004-05-03 20:00:17 +0000548 /* - Signal the output process to trigger an update (see section
549 2.5). */
550 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000551
paula87552c2004-05-03 20:00:17 +0000552 /* Finally, route goes into the kernel. */
553 rinfo->type = ZEBRA_ROUTE_RIP;
554 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000555
paula87552c2004-05-03 20:00:17 +0000556 /* Set distance value. */
557 rinfo->distance = rip_distance_apply (rinfo);
558
559 rp->info = rinfo;
560 rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
561 rinfo->distance);
562 rinfo->flags |= RIP_RTF_FIB;
563 }
vincentfbf5d032005-09-29 11:25:50 +0000564
565 /* Unlock temporary lock, i.e. same behaviour */
566 if (route_reuse)
567 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +0000568 }
569 else
570 {
571 /* Route is there but we are not sure the route is RIP or not. */
572 rinfo = rp->info;
paula87552c2004-05-03 20:00:17 +0000573
paul718e3742002-12-13 20:15:29 +0000574 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000575 to the address of the router from which the datagram came.
576 If this datagram is from the same router as the existing
577 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000578 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000579 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000580
581 if (same)
paula87552c2004-05-03 20:00:17 +0000582 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000583
paulb94f9db2004-05-01 20:45:38 +0000584
585 /* Fill in a minimaly temporary rip_info structure, for a future
586 rip_distance_apply() use) */
paula87552c2004-05-03 20:00:17 +0000587 memset (&rinfotmp, 0, sizeof (rinfotmp));
paulb94f9db2004-05-01 20:45:38 +0000588 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
paula87552c2004-05-03 20:00:17 +0000589 rinfotmp.rp = rinfo->rp;
paulb94f9db2004-05-01 20:45:38 +0000590
591
paul718e3742002-12-13 20:15:29 +0000592 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000593 router as the existing route, and the new metric is different
594 than the old one; or, if the new metric is lower than the old
595 one, or if the tag has been changed; or if there is a route
596 with a lower administrave distance; or an update of the
597 distance on the actual route; do the following actions: */
598 if ((same && rinfo->metric != rte->metric)
599 || (rte->metric < rinfo->metric)
600 || ((same)
601 && (rinfo->metric == rte->metric)
602 && ntohs (rte->tag) != rinfo->tag)
603 || (rinfo->distance > rip_distance_apply (&rinfotmp))
604 || ((rinfo->distance != rip_distance_apply (rinfo)) && same))
605 {
606 /* - Adopt the route from the datagram. That is, put the
607 new metric in, and adjust the next hop address (if
608 necessary). */
609 oldmetric = rinfo->metric;
610 rinfo->metric = rte->metric;
611 rinfo->tag = ntohs (rte->tag);
612 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
613 rinfo->ifindex = ifp->ifindex;
614 rinfo->distance = rip_distance_apply (rinfo);
paul718e3742002-12-13 20:15:29 +0000615
paula87552c2004-05-03 20:00:17 +0000616 /* Should a new route to this network be established
617 while the garbage-collection timer is running, the
618 new route will replace the one that is about to be
619 deleted. In this case the garbage-collection timer
620 must be cleared. */
paul718e3742002-12-13 20:15:29 +0000621
paula87552c2004-05-03 20:00:17 +0000622 if (oldmetric == RIP_METRIC_INFINITY &&
623 rinfo->metric < RIP_METRIC_INFINITY)
624 {
625 rinfo->type = ZEBRA_ROUTE_RIP;
626 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000627
paula87552c2004-05-03 20:00:17 +0000628 RIP_TIMER_OFF (rinfo->t_garbage_collect);
paul718e3742002-12-13 20:15:29 +0000629
paula87552c2004-05-03 20:00:17 +0000630 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
631 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000632
paula87552c2004-05-03 20:00:17 +0000633 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
634 rinfo->distance);
635 rinfo->flags |= RIP_RTF_FIB;
636 }
paul718e3742002-12-13 20:15:29 +0000637
paula87552c2004-05-03 20:00:17 +0000638 /* Update nexthop and/or metric value. */
639 if (oldmetric != RIP_METRIC_INFINITY)
640 {
641 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
642 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
643 rinfo->distance);
644 rinfo->flags |= RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000645
paula87552c2004-05-03 20:00:17 +0000646 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
647 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
648 }
paul718e3742002-12-13 20:15:29 +0000649
paula87552c2004-05-03 20:00:17 +0000650 /* - Set the route change flag and signal the output process
651 to trigger an update. */
652 rinfo->flags |= RIP_RTF_CHANGED;
653 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000654
paula87552c2004-05-03 20:00:17 +0000655 /* - If the new metric is infinity, start the deletion
656 process (described above); */
657 if (rinfo->metric == RIP_METRIC_INFINITY)
658 {
659 /* If the new metric is infinity, the deletion process
660 begins for the route, which is no longer used for
661 routing packets. Note that the deletion process is
662 started only when the metric is first set to
663 infinity. If the metric was already infinity, then a
664 new deletion process is not started. */
665 if (oldmetric != RIP_METRIC_INFINITY)
666 {
667 /* - The garbage-collection timer is set for 120 seconds. */
668 RIP_TIMER_ON (rinfo->t_garbage_collect,
669 rip_garbage_collect, rip->garbage_time);
670 RIP_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +0000671
paula87552c2004-05-03 20:00:17 +0000672 /* - The metric for the route is set to 16
673 (infinity). This causes the route to be removed
674 from service. */
675 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
676 rinfo->flags &= ~RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000677
paula87552c2004-05-03 20:00:17 +0000678 /* - The route change flag is to indicate that this
679 entry has been changed. */
680 /* - The output process is signalled to trigger a
paul718e3742002-12-13 20:15:29 +0000681 response. */
paula87552c2004-05-03 20:00:17 +0000682 ; /* Above processes are already done previously. */
683 }
684 }
685 else
686 {
687 /* otherwise, re-initialize the timeout. */
688 rip_timeout_update (rinfo);
689 }
690 }
paul718e3742002-12-13 20:15:29 +0000691 /* Unlock tempolary lock of the route. */
692 route_unlock_node (rp);
693 }
694}
695
696/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000697static void
hasso8a676be2004-10-08 06:36:38 +0000698rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000699{
700 caddr_t lim;
701 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000702 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000703 char pbuf[BUFSIZ], nbuf[BUFSIZ];
704 u_char netmask = 0;
705 u_char *p;
706
707 /* Set command string. */
708 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
709 command_str = lookup (rip_msg, packet->command);
710 else
711 command_str = "unknown";
712
713 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000714 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000715 sndrcv, command_str, packet->version, size);
716
717 /* Dump each routing table entry. */
718 rte = packet->rte;
719
720 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
721 {
722 if (packet->version == RIPv2)
723 {
724 netmask = ip_masklen (rte->mask);
725
paulca5e5162004-06-06 22:06:33 +0000726 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000727 {
paulca5e5162004-06-06 22:06:33 +0000728 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000729 {
730 p = (u_char *)&rte->prefix;
731
ajs5d6c3772004-12-08 19:24:06 +0000732 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000733 ntohs (rte->family), ntohs (rte->tag), p);
734 }
paulca5e5162004-06-06 22:06:33 +0000735 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000736 {
737 struct rip_md5_info *md5;
738
739 md5 = (struct rip_md5_info *) &packet->rte;
740
ajs5d6c3772004-12-08 19:24:06 +0000741 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000742 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000743 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000744 " Auth Data len %d",
745 ntohs (md5->packet_len), md5->keyid,
746 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000747 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000748 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000749 }
paulca5e5162004-06-06 22:06:33 +0000750 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000751 {
752 p = (u_char *)&rte->prefix;
753
ajs5d6c3772004-12-08 19:24:06 +0000754 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000755 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000756 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000757 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000758 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
759 p[7], p[9], p[10], p[11], p[12], p[13],
760 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000761 }
762 else
763 {
ajs5d6c3772004-12-08 19:24:06 +0000764 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000765 ntohs (rte->family), ntohs (rte->tag));
766 }
767 }
768 else
ajs5d6c3772004-12-08 19:24:06 +0000769 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000770 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
771 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
772 BUFSIZ), ntohs (rte->family),
773 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000774 }
775 else
776 {
ajs5d6c3772004-12-08 19:24:06 +0000777 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000778 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
779 ntohs (rte->family), ntohs (rte->tag),
780 (u_long)ntohl (rte->metric));
781 }
782 }
783}
784
785/* Check if the destination address is valid (unicast; not net 0
786 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
787 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000788static int
paul718e3742002-12-13 20:15:29 +0000789rip_destination_check (struct in_addr addr)
790{
791 u_int32_t destination;
792
793 /* Convert to host byte order. */
794 destination = ntohl (addr.s_addr);
795
796 if (IPV4_NET127 (destination))
797 return 0;
798
799 /* Net 0 may match to the default route. */
800 if (IPV4_NET0 (destination) && destination != 0)
801 return 0;
802
803 /* Unicast address must belong to class A, B, C. */
804 if (IN_CLASSA (destination))
805 return 1;
806 if (IN_CLASSB (destination))
807 return 1;
808 if (IN_CLASSC (destination))
809 return 1;
810
811 return 0;
812}
813
814/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000815static int
paul718e3742002-12-13 20:15:29 +0000816rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
817 struct interface *ifp)
818{
819 struct rip_interface *ri;
820 char *auth_str;
821
822 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000823 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000824 inet_ntoa (from->sin_addr));
825
826 ri = ifp->info;
827
828 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000829 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000830 return 0;
831
832 /* Simple password authentication. */
833 if (ri->auth_str)
834 {
835 auth_str = (char *) &rte->prefix;
836
837 if (strncmp (auth_str, ri->auth_str, 16) == 0)
838 return 1;
839 }
840 if (ri->key_chain)
841 {
842 struct keychain *keychain;
843 struct key *key;
844
845 keychain = keychain_lookup (ri->key_chain);
846 if (keychain == NULL)
847 return 0;
848
849 key = key_match_for_accept (keychain, (char *) &rte->prefix);
850 if (key)
851 return 1;
852 }
853 return 0;
854}
855
856/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000857static int
paul718e3742002-12-13 20:15:29 +0000858rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000859 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000860{
861 struct rip_interface *ri;
862 struct rip_md5_info *md5;
863 struct rip_md5_data *md5data;
864 struct keychain *keychain;
865 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000866 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000867 u_char digest[RIP_AUTH_MD5_SIZE];
868 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000869 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000870
871 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000872 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000873 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000874
875 ri = ifp->info;
876 md5 = (struct rip_md5_info *) &packet->rte;
877
878 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000879 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000880 return 0;
881
paulca5e5162004-06-06 22:06:33 +0000882 /* If the authentication length is less than 16, then it must be wrong for
883 * any interpretation of rfc2082. Some implementations also interpret
884 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000885 */
paulca5e5162004-06-06 22:06:33 +0000886 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
887 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000888 {
889 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000890 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000891 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000892 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000893 }
paul718e3742002-12-13 20:15:29 +0000894
paulca5e5162004-06-06 22:06:33 +0000895 /* grab and verify check packet length */
896 packet_len = ntohs (md5->packet_len);
897
898 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
899 {
900 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000901 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000902 "greater than received length %d!",
903 md5->packet_len, length);
904 return 0;
905 }
906
907 /* retrieve authentication data */
908 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000909
910 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000911
paul718e3742002-12-13 20:15:29 +0000912 if (ri->key_chain)
913 {
914 keychain = keychain_lookup (ri->key_chain);
915 if (keychain == NULL)
916 return 0;
917
918 key = key_lookup_for_accept (keychain, md5->keyid);
919 if (key == NULL)
920 return 0;
921
paul98fd1e62006-01-17 17:26:25 +0000922 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000923 }
paul98fd1e62006-01-17 17:26:25 +0000924 else if (ri->auth_str)
925 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000926
Paul Jakmafa93b162008-05-29 19:03:08 +0000927 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000928 return 0;
paul98fd1e62006-01-17 17:26:25 +0000929
paul718e3742002-12-13 20:15:29 +0000930 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000931 memset (&ctx, 0, sizeof(ctx));
932 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000933 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
934 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000935 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000936
937 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000938 return packet_len;
939 else
940 return 0;
941}
942
paulb14ee002005-02-04 23:42:41 +0000943/* Pick correct auth string for sends, prepare auth_str buffer for use.
944 * (left justified and padded).
945 *
946 * presumes one of ri or key is valid, and that the auth strings they point
947 * to are nul terminated. If neither are present, auth_str will be fully
948 * zero padded.
949 *
950 */
951static void
952rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
953 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +0000954{
paulb14ee002005-02-04 23:42:41 +0000955 assert (ri || key);
paul718e3742002-12-13 20:15:29 +0000956
paulb14ee002005-02-04 23:42:41 +0000957 memset (auth_str, 0, len);
958 if (key && key->string)
959 strncpy (auth_str, key->string, len);
960 else if (ri->auth_str)
961 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +0000962
paulb14ee002005-02-04 23:42:41 +0000963 return;
964}
paul718e3742002-12-13 20:15:29 +0000965
paulb14ee002005-02-04 23:42:41 +0000966/* Write RIPv2 simple password authentication information
967 *
968 * auth_str is presumed to be 2 bytes and correctly prepared
969 * (left justified and zero padded).
970 */
971static void
972rip_auth_simple_write (struct stream *s, char *auth_str, int len)
973{
974 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +0000975
paulb14ee002005-02-04 23:42:41 +0000976 stream_putw (s, RIP_FAMILY_AUTH);
977 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
978 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
979
980 return;
981}
982
983/* write RIPv2 MD5 "authentication header"
984 * (uses the auth key data field)
985 *
986 * Digest offset field is set to 0.
987 *
988 * returns: offset of the digest offset field, which must be set when
989 * length to the auth-data MD5 digest is known.
990 */
991static size_t
992rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
993 struct key *key)
994{
paul98fd1e62006-01-17 17:26:25 +0000995 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +0000996
997 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +0000998
999 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +00001000 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +00001001 stream_putw (s, RIP_AUTH_MD5);
1002
paulb14ee002005-02-04 23:42:41 +00001003 /* MD5 AH digest offset field.
1004 *
1005 * Set to placeholder value here, to true value when RIP-2 Packet length
1006 * is known. Actual value is set in .....().
1007 */
paul98fd1e62006-01-17 17:26:25 +00001008 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001009 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001010
1011 /* Key ID. */
1012 if (key)
1013 stream_putc (s, key->index % 256);
1014 else
1015 stream_putc (s, 1);
1016
paulca5e5162004-06-06 22:06:33 +00001017 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1018 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1019 * to be configurable.
1020 */
1021 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001022
1023 /* Sequence Number (non-decreasing). */
1024 /* RFC2080: The value used in the sequence number is
1025 arbitrary, but two suggestions are the time of the
1026 message's creation or a simple message counter. */
1027 stream_putl (s, time (NULL));
1028
1029 /* Reserved field must be zero. */
1030 stream_putl (s, 0);
1031 stream_putl (s, 0);
1032
paul98fd1e62006-01-17 17:26:25 +00001033 return doff;
paulb14ee002005-02-04 23:42:41 +00001034}
paul718e3742002-12-13 20:15:29 +00001035
paulb14ee002005-02-04 23:42:41 +00001036/* If authentication is in used, write the appropriate header
1037 * returns stream offset to which length must later be written
1038 * or 0 if this is not required
1039 */
1040static size_t
1041rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1042 struct key *key, char *auth_str, int len)
1043{
1044 assert (ri->auth_type != RIP_NO_AUTH);
1045
1046 switch (ri->auth_type)
1047 {
1048 case RIP_AUTH_SIMPLE_PASSWORD:
1049 rip_auth_prepare_str_send (ri, key, auth_str, len);
1050 rip_auth_simple_write (s, auth_str, len);
1051 return 0;
1052 case RIP_AUTH_MD5:
1053 return rip_auth_md5_ah_write (s, ri, key);
1054 }
1055 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001056 return 0;
paulb14ee002005-02-04 23:42:41 +00001057}
1058
1059/* Write RIPv2 MD5 authentication data trailer */
1060static void
1061rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1062 char *auth_str, int authlen)
1063{
1064 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001065 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001066 unsigned char digest[RIP_AUTH_MD5_SIZE];
1067
1068 /* Make it sure this interface is configured as MD5
1069 authentication. */
1070 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1071 assert (doff > 0);
1072
1073 /* Get packet length. */
1074 len = stream_get_endp(s);
1075
1076 /* Check packet length. */
1077 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1078 {
1079 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1080 return;
1081 }
1082
1083 /* Set the digest offset length in the header */
1084 stream_putw_at (s, doff, len);
1085
paul718e3742002-12-13 20:15:29 +00001086 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001087 stream_putw (s, RIP_FAMILY_AUTH);
1088 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001089
1090 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001091 memset(&ctx, 0, sizeof(ctx));
1092 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001093 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001094 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1095 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001096
1097 /* Copy the digest to the packet. */
1098 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1099}
1100
1101/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001102static void
paul718e3742002-12-13 20:15:29 +00001103rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001104 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001105{
1106 caddr_t lim;
1107 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001108 struct prefix_ipv4 ifaddr;
1109 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001110 int subnetted;
paul718e3742002-12-13 20:15:29 +00001111
paul727d1042002-12-13 20:50:29 +00001112 /* We don't know yet. */
1113 subnetted = -1;
1114
paul718e3742002-12-13 20:15:29 +00001115 /* The Response must be ignored if it is not from the RIP
1116 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001117 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001118 {
1119 zlog_info ("response doesn't come from RIP port: %d",
1120 from->sin_port);
1121 rip_peer_bad_packet (from);
1122 return;
1123 }
1124
1125 /* The datagram's IPv4 source address should be checked to see
1126 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001127 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1128 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001129 {
1130 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1131 inet_ntoa (from->sin_addr));
1132 rip_peer_bad_packet (from);
1133 return;
1134 }
1135
1136 /* It is also worth checking to see whether the response is from one
1137 of the router's own addresses. */
1138
1139 ; /* Alredy done in rip_read () */
1140
1141 /* Update RIP peer. */
1142 rip_peer_update (from, packet->version);
1143
1144 /* Set RTE pointer. */
1145 rte = packet->rte;
1146
1147 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1148 {
1149 /* RIPv2 authentication check. */
1150 /* If the Address Family Identifier of the first (and only the
1151 first) entry in the message is 0xFFFF, then the remainder of
1152 the entry contains the authentication. */
1153 /* If the packet gets here it means authentication enabled */
1154 /* Check is done in rip_read(). So, just skipping it */
1155 if (packet->version == RIPv2 &&
1156 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001157 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001158 continue;
1159
paulca5e5162004-06-06 22:06:33 +00001160 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001161 {
1162 /* Address family check. RIP only supports AF_INET. */
1163 zlog_info ("Unsupported family %d from %s.",
1164 ntohs (rte->family), inet_ntoa (from->sin_addr));
1165 continue;
1166 }
1167
1168 /* - is the destination address valid (e.g., unicast; not net 0
1169 or 127) */
1170 if (! rip_destination_check (rte->prefix))
1171 {
1172 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1173 rip_peer_bad_route (from);
1174 continue;
1175 }
1176
1177 /* Convert metric value to host byte order. */
1178 rte->metric = ntohl (rte->metric);
1179
1180 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1181 if (! (rte->metric >= 1 && rte->metric <= 16))
1182 {
1183 zlog_info ("Route's metric is not in the 1-16 range.");
1184 rip_peer_bad_route (from);
1185 continue;
1186 }
1187
1188 /* RIPv1 does not have nexthop value. */
1189 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1190 {
1191 zlog_info ("RIPv1 packet with nexthop value %s",
1192 inet_ntoa (rte->nexthop));
1193 rip_peer_bad_route (from);
1194 continue;
1195 }
1196
1197 /* That is, if the provided information is ignored, a possibly
1198 sub-optimal, but absolutely valid, route may be taken. If
1199 the received Next Hop is not directly reachable, it should be
1200 treated as 0.0.0.0. */
1201 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1202 {
1203 u_int32_t addrval;
1204
1205 /* Multicast address check. */
1206 addrval = ntohl (rte->nexthop.s_addr);
1207 if (IN_CLASSD (addrval))
1208 {
1209 zlog_info ("Nexthop %s is multicast address, skip this rte",
1210 inet_ntoa (rte->nexthop));
1211 continue;
1212 }
1213
1214 if (! if_lookup_address (rte->nexthop))
1215 {
1216 struct route_node *rn;
1217 struct rip_info *rinfo;
1218
1219 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1220
1221 if (rn)
1222 {
1223 rinfo = rn->info;
1224
1225 if (rinfo->type == ZEBRA_ROUTE_RIP
1226 && rinfo->sub_type == RIP_ROUTE_RTE)
1227 {
1228 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001229 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 +00001230 rte->nexthop = rinfo->from;
1231 }
1232 else
1233 {
1234 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001235 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 +00001236 rte->nexthop.s_addr = 0;
1237 }
1238
1239 route_unlock_node (rn);
1240 }
1241 else
1242 {
1243 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001244 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 +00001245 rte->nexthop.s_addr = 0;
1246 }
1247
1248 }
1249 }
1250
1251 /* For RIPv1, there won't be a valid netmask.
1252
1253 This is a best guess at the masks. If everyone was using old
1254 Ciscos before the 'ip subnet zero' option, it would be almost
1255 right too :-)
1256
1257 Cisco summarize ripv1 advertisments to the classful boundary
1258 (/16 for class B's) except when the RIP packet does to inside
1259 the classful network in question. */
1260
1261 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1262 || (packet->version == RIPv2
1263 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1264 {
1265 u_int32_t destination;
1266
paul727d1042002-12-13 20:50:29 +00001267 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001268 {
1269 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1270 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1271 apply_classful_mask_ipv4 (&ifaddrclass);
1272 subnetted = 0;
1273 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1274 subnetted = 1;
1275 }
paul727d1042002-12-13 20:50:29 +00001276
paul718e3742002-12-13 20:15:29 +00001277 destination = ntohl (rte->prefix.s_addr);
1278
paul727d1042002-12-13 20:50:29 +00001279 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001280 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001281 else if (IN_CLASSB (destination))
1282 masklen2ip (16, &rte->mask);
1283 else if (IN_CLASSC (destination))
1284 masklen2ip (24, &rte->mask);
1285
1286 if (subnetted == 1)
1287 masklen2ip (ifaddrclass.prefixlen,
1288 (struct in_addr *) &destination);
1289 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1290 ifaddrclass.prefix.s_addr))
1291 {
1292 masklen2ip (ifaddr.prefixlen, &rte->mask);
1293 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1294 masklen2ip (32, &rte->mask);
1295 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001296 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001297 }
1298 else
1299 {
1300 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1301 continue;
1302 }
1303
1304 if (IS_RIP_DEBUG_EVENT)
1305 {
ajs5d6c3772004-12-08 19:24:06 +00001306 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1307 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001308 }
1309 }
1310
1311 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1312 ignore the entry. */
1313 if ((packet->version == RIPv2)
1314 && (rte->mask.s_addr != 0)
1315 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1316 {
1317 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1318 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1319 rip_peer_bad_route (from);
1320 continue;
1321 }
1322
1323 /* Default route's netmask is ignored. */
1324 if (packet->version == RIPv2
1325 && (rte->prefix.s_addr == 0)
1326 && (rte->mask.s_addr != 0))
1327 {
1328 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001329 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001330 rte->mask.s_addr = 0;
1331 }
1332
1333 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001334 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001335 }
1336}
1337
paula4e987e2005-06-03 17:46:49 +00001338/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001339static int
paul2c61ae32005-08-16 15:22:14 +00001340rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001341{
1342 int ret;
1343 int sock;
1344 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001345
paul2c61ae32005-08-16 15:22:14 +00001346 memset (&addr, 0, sizeof (struct sockaddr_in));
1347
1348 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001349 {
paulf69bd9d2005-06-03 18:01:50 +00001350 addr.sin_family = AF_INET;
1351 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001352#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001353 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001354#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001355 } else {
1356 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001357 }
1358
paul2c61ae32005-08-16 15:22:14 +00001359 /* sending port must always be the RIP port */
1360 addr.sin_port = htons (RIP_PORT_DEFAULT);
1361
paula4e987e2005-06-03 17:46:49 +00001362 /* Make datagram socket. */
1363 sock = socket (AF_INET, SOCK_DGRAM, 0);
1364 if (sock < 0)
1365 {
1366 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1367 exit (1);
1368 }
1369
1370 sockopt_broadcast (sock);
1371 sockopt_reuseaddr (sock);
1372 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001373#ifdef RIP_RECVMSG
1374 setsockopt_pktinfo (sock);
1375#endif /* RIP_RECVMSG */
Stephen Hemminger78b31d52009-07-21 16:27:26 -07001376#ifdef IPTOS_PREC_INTERNETCONTROL
1377 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
1378#endif
paula4e987e2005-06-03 17:46:49 +00001379
1380 if (ripd_privs.change (ZPRIVS_RAISE))
1381 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001382 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1383 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1384
paula4e987e2005-06-03 17:46:49 +00001385 {
1386 int save_errno = errno;
1387 if (ripd_privs.change (ZPRIVS_LOWER))
1388 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001389
1390 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1391 sock, inet_ntoa(addr.sin_addr),
1392 (int) ntohs(addr.sin_port),
1393 safe_strerror(save_errno));
1394
paulf69bd9d2005-06-03 18:01:50 +00001395 close (sock);
paula4e987e2005-06-03 17:46:49 +00001396 return ret;
1397 }
paulf69bd9d2005-06-03 18:01:50 +00001398
paula4e987e2005-06-03 17:46:49 +00001399 if (ripd_privs.change (ZPRIVS_LOWER))
1400 zlog_err ("rip_create_socket: could not lower privs");
1401
1402 return sock;
1403}
1404
paulc49ad8f2004-10-22 10:27:28 +00001405/* RIP packet send to destination address, on interface denoted by
1406 * by connected argument. NULL to argument denotes destination should be
1407 * should be RIP multicast group
1408 */
pauldc63bfd2005-10-25 23:31:05 +00001409static int
paulc49ad8f2004-10-22 10:27:28 +00001410rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1411 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001412{
paul931cd542004-01-23 15:31:42 +00001413 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001414 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001415
1416 assert (ifc != NULL);
1417
paul931cd542004-01-23 15:31:42 +00001418 if (IS_RIP_DEBUG_PACKET)
1419 {
paulf69bd9d2005-06-03 18:01:50 +00001420#define ADDRESS_SIZE 20
1421 char dst[ADDRESS_SIZE];
1422 dst[ADDRESS_SIZE - 1] = '\0';
1423
paul931cd542004-01-23 15:31:42 +00001424 if (to)
1425 {
paulf69bd9d2005-06-03 18:01:50 +00001426 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001427 }
1428 else
1429 {
1430 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001431 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001432 }
paulf69bd9d2005-06-03 18:01:50 +00001433#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001434 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001435 inet_ntoa(ifc->address->u.prefix4),
1436 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001437 }
paulf69bd9d2005-06-03 18:01:50 +00001438
paulc49ad8f2004-10-22 10:27:28 +00001439 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001440 {
1441 /*
1442 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1443 * with multiple addresses on the same subnet: the first address
1444 * on the subnet is configured "primary", and all subsequent addresses
1445 * on that subnet are treated as "secondary" addresses.
1446 * In order to avoid routing-table bloat on other rip listeners,
1447 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1448 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1449 * flag is set, we would end up sending a packet for a "secondary"
1450 * source address on non-linux systems.
1451 */
1452 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001453 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001454 return 0;
1455 }
1456
paul718e3742002-12-13 20:15:29 +00001457 /* Make destination address. */
1458 memset (&sin, 0, sizeof (struct sockaddr_in));
1459 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001460#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001461 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001462#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001463
1464 /* When destination is specified, use it's port and address. */
1465 if (to)
1466 {
paul718e3742002-12-13 20:15:29 +00001467 sin.sin_port = to->sin_port;
1468 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001469 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001470 }
1471 else
1472 {
paul2c61ae32005-08-16 15:22:14 +00001473 struct sockaddr_in from;
1474
paul718e3742002-12-13 20:15:29 +00001475 sin.sin_port = htons (RIP_PORT_DEFAULT);
1476 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001477
1478 /* multicast send should bind to local interface address */
Nick Hilliardbb2315f2012-08-18 15:10:57 +00001479 memset (&from, 0, sizeof (from));
paul2c61ae32005-08-16 15:22:14 +00001480 from.sin_family = AF_INET;
1481 from.sin_port = htons (RIP_PORT_DEFAULT);
1482 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001483#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001484 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001485#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001486
paul931cd542004-01-23 15:31:42 +00001487 /*
1488 * we have to open a new socket for each packet because this
1489 * is the most portable way to bind to a different source
1490 * ipv4 address for each packet.
1491 */
paul2c61ae32005-08-16 15:22:14 +00001492 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001493 {
paulf69bd9d2005-06-03 18:01:50 +00001494 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001495 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001496 }
paulc49ad8f2004-10-22 10:27:28 +00001497 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001498 }
1499
paul931cd542004-01-23 15:31:42 +00001500 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001501 sizeof (struct sockaddr_in));
1502
1503 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001504 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001505 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001506
1507 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001508 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001509
paul931cd542004-01-23 15:31:42 +00001510 if (!to)
1511 close(send_sock);
1512
paul718e3742002-12-13 20:15:29 +00001513 return ret;
1514}
1515
1516/* Add redistributed route to RIP table. */
1517void
1518rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001519 unsigned int ifindex, struct in_addr *nexthop,
1520 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001521{
1522 int ret;
1523 struct route_node *rp;
1524 struct rip_info *rinfo;
1525
1526 /* Redistribute route */
1527 ret = rip_destination_check (p->prefix);
1528 if (! ret)
1529 return;
1530
1531 rp = route_node_get (rip->table, (struct prefix *) p);
1532
1533 rinfo = rp->info;
1534
1535 if (rinfo)
1536 {
1537 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1538 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1539 && rinfo->metric != RIP_METRIC_INFINITY)
1540 {
1541 route_unlock_node (rp);
1542 return;
1543 }
1544
1545 /* Manually configured RIP route check. */
1546 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001547 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1548 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001549 {
hasso16705132003-05-25 14:49:19 +00001550 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1551 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001552 {
1553 route_unlock_node (rp);
1554 return;
1555 }
1556 }
1557
1558 RIP_TIMER_OFF (rinfo->t_timeout);
1559 RIP_TIMER_OFF (rinfo->t_garbage_collect);
1560
1561 if (rip_route_rte (rinfo))
1562 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
1563 rinfo->metric);
1564 rp->info = NULL;
1565 rip_info_free (rinfo);
1566
1567 route_unlock_node (rp);
1568 }
1569
1570 rinfo = rip_info_new ();
1571
1572 rinfo->type = type;
1573 rinfo->sub_type = sub_type;
1574 rinfo->ifindex = ifindex;
1575 rinfo->metric = 1;
vincentfbf5d032005-09-29 11:25:50 +00001576 rinfo->external_metric = metric;
1577 rinfo->distance = distance;
paul718e3742002-12-13 20:15:29 +00001578 rinfo->rp = rp;
1579
1580 if (nexthop)
1581 rinfo->nexthop = *nexthop;
1582
1583 rinfo->flags |= RIP_RTF_FIB;
1584 rp->info = rinfo;
1585
1586 rinfo->flags |= RIP_RTF_CHANGED;
1587
hasso16705132003-05-25 14:49:19 +00001588 if (IS_RIP_DEBUG_EVENT) {
1589 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001590 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001591 inet_ntoa(p->prefix), p->prefixlen,
1592 ifindex2ifname(ifindex));
1593 else
ajs5d6c3772004-12-08 19:24:06 +00001594 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001595 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1596 ifindex2ifname(ifindex));
1597 }
1598
1599
paul718e3742002-12-13 20:15:29 +00001600 rip_event (RIP_TRIGGERED_UPDATE, 0);
1601}
1602
1603/* Delete redistributed route from RIP table. */
1604void
1605rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1606 unsigned int ifindex)
1607{
1608 int ret;
1609 struct route_node *rp;
1610 struct rip_info *rinfo;
1611
1612 ret = rip_destination_check (p->prefix);
1613 if (! ret)
1614 return;
1615
1616 rp = route_node_lookup (rip->table, (struct prefix *) p);
1617 if (rp)
1618 {
1619 rinfo = rp->info;
1620
1621 if (rinfo != NULL
1622 && rinfo->type == type
1623 && rinfo->sub_type == sub_type
1624 && rinfo->ifindex == ifindex)
1625 {
1626 /* Perform poisoned reverse. */
1627 rinfo->metric = RIP_METRIC_INFINITY;
1628 RIP_TIMER_ON (rinfo->t_garbage_collect,
1629 rip_garbage_collect, rip->garbage_time);
1630 RIP_TIMER_OFF (rinfo->t_timeout);
1631 rinfo->flags |= RIP_RTF_CHANGED;
1632
hasso16705132003-05-25 14:49:19 +00001633 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001634 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso16705132003-05-25 14:49:19 +00001635 inet_ntoa(p->prefix), p->prefixlen,
1636 ifindex2ifname(ifindex));
1637
paul718e3742002-12-13 20:15:29 +00001638 rip_event (RIP_TRIGGERED_UPDATE, 0);
1639 }
1640 }
1641}
1642
1643/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001644static void
paul718e3742002-12-13 20:15:29 +00001645rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001646 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001647{
1648 caddr_t lim;
1649 struct rte *rte;
1650 struct prefix_ipv4 p;
1651 struct route_node *rp;
1652 struct rip_info *rinfo;
1653 struct rip_interface *ri;
1654
hasso16705132003-05-25 14:49:19 +00001655 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001656 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001657 return;
1658
hasso429a0f82004-02-22 23:42:22 +00001659 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001660 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001661 if (! ri->running)
1662 return;
paul718e3742002-12-13 20:15:29 +00001663
1664 /* When passive interface is specified, suppress responses */
1665 if (ri->passive)
1666 return;
paulc49ad8f2004-10-22 10:27:28 +00001667
paul718e3742002-12-13 20:15:29 +00001668 /* RIP peer update. */
1669 rip_peer_update (from, packet->version);
1670
1671 lim = ((caddr_t) packet) + size;
1672 rte = packet->rte;
1673
1674 /* The Request is processed entry by entry. If there are no
1675 entries, no response is given. */
1676 if (lim == (caddr_t) rte)
1677 return;
1678
1679 /* There is one special case. If there is exactly one entry in the
1680 request, and it has an address family identifier of zero and a
1681 metric of infinity (i.e., 16), then this is a request to send the
1682 entire routing table. */
1683 if (lim == ((caddr_t) (rte + 1)) &&
1684 ntohs (rte->family) == 0 &&
1685 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1686 {
paulcc1131a2003-10-15 23:20:17 +00001687 struct prefix_ipv4 saddr;
1688
1689 /* saddr will be used for determining which routes to split-horizon.
1690 Since the source address we'll pick will be on the same subnet as the
1691 destination, for the purpose of split-horizoning, we'll
1692 pretend that "from" is our source address. */
1693 saddr.family = AF_INET;
1694 saddr.prefixlen = IPV4_MAX_BITLEN;
1695 saddr.prefix = from->sin_addr;
1696
paul718e3742002-12-13 20:15:29 +00001697 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001698 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001699 }
1700 else
1701 {
1702 /* Examine the list of RTEs in the Request one by one. For each
1703 entry, look up the destination in the router's routing
1704 database and, if there is a route, put that route's metric in
1705 the metric field of the RTE. If there is no explicit route
1706 to the specified destination, put infinity in the metric
1707 field. Once all the entries have been filled in, change the
1708 command from Request to Response and send the datagram back
1709 to the requestor. */
1710 p.family = AF_INET;
1711
1712 for (; ((caddr_t) rte) < lim; rte++)
1713 {
1714 p.prefix = rte->prefix;
1715 p.prefixlen = ip_masklen (rte->mask);
1716 apply_mask_ipv4 (&p);
1717
1718 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1719 if (rp)
1720 {
1721 rinfo = rp->info;
1722 rte->metric = htonl (rinfo->metric);
1723 route_unlock_node (rp);
1724 }
1725 else
1726 rte->metric = htonl (RIP_METRIC_INFINITY);
1727 }
1728 packet->command = RIP_RESPONSE;
1729
paulc49ad8f2004-10-22 10:27:28 +00001730 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001731 }
1732 rip_global_queries++;
1733}
1734
1735#if RIP_RECVMSG
1736/* Set IPv6 packet info to the socket. */
1737static int
1738setsockopt_pktinfo (int sock)
1739{
1740 int ret;
1741 int val = 1;
1742
1743 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1744 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001745 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001746 return ret;
1747}
1748
1749/* Read RIP packet by recvmsg function. */
1750int
1751rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1752 int *ifindex)
1753{
1754 int ret;
1755 struct msghdr msg;
1756 struct iovec iov;
1757 struct cmsghdr *ptr;
1758 char adata[1024];
1759
1760 msg.msg_name = (void *) from;
1761 msg.msg_namelen = sizeof (struct sockaddr_in);
1762 msg.msg_iov = &iov;
1763 msg.msg_iovlen = 1;
1764 msg.msg_control = (void *) adata;
1765 msg.msg_controllen = sizeof adata;
1766 iov.iov_base = buf;
1767 iov.iov_len = size;
1768
1769 ret = recvmsg (sock, &msg, 0);
1770 if (ret < 0)
1771 return ret;
1772
ajsb99760a2005-01-04 16:24:43 +00001773 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001774 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1775 {
1776 struct in_pktinfo *pktinfo;
1777 int i;
1778
1779 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1780 i = pktinfo->ipi_ifindex;
1781 }
1782 return ret;
1783}
1784
1785/* RIP packet read function. */
1786int
1787rip_read_new (struct thread *t)
1788{
1789 int ret;
1790 int sock;
1791 char buf[RIP_PACKET_MAXSIZ];
1792 struct sockaddr_in from;
1793 unsigned int ifindex;
1794
1795 /* Fetch socket then register myself. */
1796 sock = THREAD_FD (t);
1797 rip_event (RIP_READ, sock);
1798
1799 /* Read RIP packet. */
1800 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1801 if (ret < 0)
1802 {
ajs6099b3b2004-11-20 02:06:59 +00001803 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001804 return ret;
1805 }
1806
1807 return ret;
1808}
1809#endif /* RIP_RECVMSG */
1810
1811/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001812static int
paul718e3742002-12-13 20:15:29 +00001813rip_read (struct thread *t)
1814{
1815 int sock;
1816 int ret;
1817 int rtenum;
1818 union rip_buf rip_buf;
1819 struct rip_packet *packet;
1820 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001821 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001822 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001823 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001824 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001825 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001826 struct rip_interface *ri;
1827
1828 /* Fetch socket then register myself. */
1829 sock = THREAD_FD (t);
1830 rip->t_read = NULL;
1831
1832 /* Add myself to tne next event */
1833 rip_event (RIP_READ, sock);
1834
1835 /* RIPd manages only IPv4. */
1836 memset (&from, 0, sizeof (struct sockaddr_in));
1837 fromlen = sizeof (struct sockaddr_in);
1838
1839 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1840 (struct sockaddr *) &from, &fromlen);
1841 if (len < 0)
1842 {
ajs6099b3b2004-11-20 02:06:59 +00001843 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001844 return len;
1845 }
1846
1847 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001848 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001849 {
1850 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001851 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001852 return -1;
1853 }
1854
1855 /* Which interface is this packet comes from. */
1856 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001857
paul718e3742002-12-13 20:15:29 +00001858 /* RIP packet received */
1859 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001860 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001861 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1862 ifp ? ifp->name : "unknown");
1863
1864 /* If this packet come from unknown interface, ignore it. */
1865 if (ifp == NULL)
1866 {
ajs766a0ca2004-12-15 14:55:51 +00001867 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1868 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001869 return -1;
1870 }
1871
1872 ifc = connected_lookup_address (ifp, from.sin_addr);
1873
1874 if (ifc == NULL)
1875 {
ajs766a0ca2004-12-15 14:55:51 +00001876 zlog_info ("rip_read: cannot find connected address for packet from %s "
1877 "port %d on interface %s",
1878 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001879 return -1;
1880 }
1881
1882 /* Packet length check. */
1883 if (len < RIP_PACKET_MINSIZ)
1884 {
1885 zlog_warn ("packet size %d is smaller than minimum size %d",
1886 len, RIP_PACKET_MINSIZ);
1887 rip_peer_bad_packet (&from);
1888 return len;
1889 }
1890 if (len > RIP_PACKET_MAXSIZ)
1891 {
1892 zlog_warn ("packet size %d is larger than max size %d",
1893 len, RIP_PACKET_MAXSIZ);
1894 rip_peer_bad_packet (&from);
1895 return len;
1896 }
1897
1898 /* Packet alignment check. */
1899 if ((len - RIP_PACKET_MINSIZ) % 20)
1900 {
1901 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1902 rip_peer_bad_packet (&from);
1903 return len;
1904 }
1905
1906 /* Set RTE number. */
1907 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1908
1909 /* For easy to handle. */
1910 packet = &rip_buf.rip_packet;
1911
1912 /* RIP version check. */
1913 if (packet->version == 0)
1914 {
1915 zlog_info ("version 0 with command %d received.", packet->command);
1916 rip_peer_bad_packet (&from);
1917 return -1;
1918 }
1919
1920 /* Dump RIP packet. */
1921 if (IS_RIP_DEBUG_RECV)
1922 rip_packet_dump (packet, len, "RECV");
1923
1924 /* RIP version adjust. This code should rethink now. RFC1058 says
1925 that "Version 1 implementations are to ignore this extra data and
1926 process only the fields specified in this document.". So RIPv3
1927 packet should be treated as RIPv1 ignoring must be zero field. */
1928 if (packet->version > RIPv2)
1929 packet->version = RIPv2;
1930
1931 /* Is RIP running or is this RIP neighbor ?*/
1932 ri = ifp->info;
1933 if (! ri->running && ! rip_neighbor_lookup (&from))
1934 {
1935 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001936 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001937 rip_peer_bad_packet (&from);
1938 return -1;
1939 }
1940
Paul Jakma15a2b082006-05-04 07:36:34 +00001941 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001942 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1943 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001944 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001945 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001946 if (IS_RIP_DEBUG_PACKET)
1947 zlog_debug (" packet's v%d doesn't fit to if version spec",
1948 packet->version);
1949 rip_peer_bad_packet (&from);
1950 return -1;
paul718e3742002-12-13 20:15:29 +00001951 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001952 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1953 {
1954 if (IS_RIP_DEBUG_PACKET)
1955 zlog_debug (" packet's v%d doesn't fit to if version spec",
1956 packet->version);
1957 rip_peer_bad_packet (&from);
1958 return -1;
1959 }
1960
paul718e3742002-12-13 20:15:29 +00001961 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1962 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1963 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001964 if ((ri->auth_type == RIP_NO_AUTH)
1965 && rtenum
paulca5e5162004-06-06 22:06:33 +00001966 && (packet->version == RIPv2)
1967 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001968 {
1969 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001970 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001971 packet->version);
1972 rip_peer_bad_packet (&from);
1973 return -1;
1974 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001975
1976 /* RFC:
1977 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001978 RIP-1 messages and RIP-2 messages which pass authentication
1979 testing shall be accepted; unauthenticated and failed
1980 authentication RIP-2 messages shall be discarded. For maximum
1981 security, RIP-1 messages should be ignored when authentication is
1982 in use (see section 4.1); otherwise, the routing information from
1983 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001984 unauthenticated manner.
1985 */
1986 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1987 * always reply regardless of authentication settings, because:
1988 *
1989 * - if there other authorised routers on-link, the REQUESTor can
1990 * passively obtain the routing updates anyway
1991 * - if there are no other authorised routers on-link, RIP can
1992 * easily be disabled for the link to prevent giving out information
1993 * on state of this routers RIP routing table..
1994 *
1995 * I.e. if RIPv1 has any place anymore these days, it's as a very
1996 * simple way to distribute routing information (e.g. to embedded
1997 * hosts / appliances) and the ability to give out RIPv1
1998 * routing-information freely, while still requiring RIPv2
1999 * authentication for any RESPONSEs might be vaguely useful.
2000 */
2001 if (ri->auth_type != RIP_NO_AUTH
2002 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002003 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002004 /* Discard RIPv1 messages other than REQUESTs */
2005 if (packet->command != RIP_REQUEST)
2006 {
2007 if (IS_RIP_DEBUG_PACKET)
2008 zlog_debug ("RIPv1" " dropped because authentication enabled");
2009 rip_peer_bad_packet (&from);
2010 return -1;
2011 }
2012 }
2013 else if (ri->auth_type != RIP_NO_AUTH)
2014 {
2015 const char *auth_desc;
2016
2017 if (rtenum == 0)
2018 {
2019 /* There definitely is no authentication in the packet. */
2020 if (IS_RIP_DEBUG_PACKET)
2021 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2022 rip_peer_bad_packet (&from);
2023 return -1;
2024 }
2025
2026 /* First RTE must be an Authentication Family RTE */
2027 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2028 {
2029 if (IS_RIP_DEBUG_PACKET)
2030 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002031 rip_peer_bad_packet (&from);
2032 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002033 }
2034
paul718e3742002-12-13 20:15:29 +00002035 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002036 switch (ntohs(packet->rte->tag))
2037 {
2038 case RIP_AUTH_SIMPLE_PASSWORD:
2039 auth_desc = "simple";
2040 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2041 break;
2042
2043 case RIP_AUTH_MD5:
2044 auth_desc = "MD5";
2045 ret = rip_auth_md5 (packet, &from, len, ifp);
2046 /* Reset RIP packet length to trim MD5 data. */
2047 len = ret;
2048 break;
2049
2050 default:
2051 ret = 0;
2052 auth_desc = "unknown type";
2053 if (IS_RIP_DEBUG_PACKET)
2054 zlog_debug ("RIPv2 Unknown authentication type %d",
2055 ntohs (packet->rte->tag));
2056 }
2057
2058 if (ret)
2059 {
2060 if (IS_RIP_DEBUG_PACKET)
2061 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2062 }
2063 else
2064 {
2065 if (IS_RIP_DEBUG_PACKET)
2066 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2067 rip_peer_bad_packet (&from);
2068 return -1;
2069 }
paul718e3742002-12-13 20:15:29 +00002070 }
2071
2072 /* Process each command. */
2073 switch (packet->command)
2074 {
2075 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002076 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002077 break;
2078 case RIP_REQUEST:
2079 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002080 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002081 break;
2082 case RIP_TRACEON:
2083 case RIP_TRACEOFF:
2084 zlog_info ("Obsolete command %s received, please sent it to routed",
2085 lookup (rip_msg, packet->command));
2086 rip_peer_bad_packet (&from);
2087 break;
2088 case RIP_POLL_ENTRY:
2089 zlog_info ("Obsolete command %s received",
2090 lookup (rip_msg, packet->command));
2091 rip_peer_bad_packet (&from);
2092 break;
2093 default:
2094 zlog_info ("Unknown RIP command %d received", packet->command);
2095 rip_peer_bad_packet (&from);
2096 break;
2097 }
2098
2099 return len;
2100}
2101
paul718e3742002-12-13 20:15:29 +00002102/* Write routing table entry to the stream and return next index of
2103 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002104static int
paul718e3742002-12-13 20:15:29 +00002105rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002106 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002107{
2108 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002109
2110 /* Write routing table entry. */
2111 if (version == RIPv1)
2112 {
2113 stream_putw (s, AF_INET);
2114 stream_putw (s, 0);
2115 stream_put_ipv4 (s, p->prefix.s_addr);
2116 stream_put_ipv4 (s, 0);
2117 stream_put_ipv4 (s, 0);
2118 stream_putl (s, rinfo->metric_out);
2119 }
2120 else
2121 {
2122 masklen2ip (p->prefixlen, &mask);
2123
2124 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002125 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002126 stream_put_ipv4 (s, p->prefix.s_addr);
2127 stream_put_ipv4 (s, mask.s_addr);
2128 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2129 stream_putl (s, rinfo->metric_out);
2130 }
2131
2132 return ++num;
2133}
2134
2135/* Send update to the ifp or spcified neighbor. */
2136void
paulc49ad8f2004-10-22 10:27:28 +00002137rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2138 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002139{
2140 int ret;
2141 struct stream *s;
2142 struct route_node *rp;
2143 struct rip_info *rinfo;
2144 struct rip_interface *ri;
2145 struct prefix_ipv4 *p;
2146 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002147 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002148 struct key *key = NULL;
2149 /* this might need to made dynamic if RIP ever supported auth methods
2150 with larger key string sizes */
2151 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002152 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002153 int num = 0;
paul718e3742002-12-13 20:15:29 +00002154 int rtemax;
paul01d09082003-06-08 21:22:18 +00002155 int subnetted = 0;
paul718e3742002-12-13 20:15:29 +00002156
2157 /* Logging output event. */
2158 if (IS_RIP_DEBUG_EVENT)
2159 {
2160 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002161 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002162 else
ajs5d6c3772004-12-08 19:24:06 +00002163 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002164 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002165 }
2166
2167 /* Set output stream. */
2168 s = rip->obuf;
2169
2170 /* Reset stream and RTE counter. */
2171 stream_reset (s);
Lu Feng342a31b2014-06-25 07:43:15 +00002172 rtemax = RIP_MAX_RTE;
paul718e3742002-12-13 20:15:29 +00002173
2174 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002175 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002176
2177 /* If output interface is in simple password authentication mode, we
2178 need space for authentication data. */
2179 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2180 rtemax -= 1;
2181
2182 /* If output interface is in MD5 authentication mode, we need space
2183 for authentication header and data. */
2184 if (ri->auth_type == RIP_AUTH_MD5)
2185 rtemax -= 2;
2186
2187 /* If output interface is in simple password authentication mode
2188 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002189 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002190 {
2191 if (ri->key_chain)
2192 {
2193 struct keychain *keychain;
2194
2195 keychain = keychain_lookup (ri->key_chain);
2196 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002197 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002198 }
paulb14ee002005-02-04 23:42:41 +00002199 /* to be passed to auth functions later */
2200 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002201 }
2202
paul727d1042002-12-13 20:50:29 +00002203 if (version == RIPv1)
2204 {
paulc49ad8f2004-10-22 10:27:28 +00002205 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002206 apply_classful_mask_ipv4 (&ifaddrclass);
2207 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002208 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002209 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002210 }
2211
paul718e3742002-12-13 20:15:29 +00002212 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2213 if ((rinfo = rp->info) != NULL)
2214 {
paul727d1042002-12-13 20:50:29 +00002215 /* For RIPv1, if we are subnetted, output subnets in our network */
2216 /* that have the same mask as the output "interface". For other */
2217 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002218
2219 if (version == RIPv1)
2220 {
paul727d1042002-12-13 20:50:29 +00002221 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002222
2223 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002224 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002225 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002226
paul727d1042002-12-13 20:50:29 +00002227 if (subnetted &&
2228 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2229 {
paulc49ad8f2004-10-22 10:27:28 +00002230 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002231 (rp->p.prefixlen != 32))
2232 continue;
2233 }
2234 else
2235 {
2236 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2237 apply_classful_mask_ipv4(&classfull);
2238 if (rp->p.u.prefix4.s_addr != 0 &&
2239 classfull.prefixlen != rp->p.prefixlen)
2240 continue;
2241 }
paul718e3742002-12-13 20:15:29 +00002242 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002243 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002244 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002245 }
2246 else
2247 p = (struct prefix_ipv4 *) &rp->p;
2248
2249 /* Apply output filters. */
2250 ret = rip_outgoing_filter (p, ri);
2251 if (ret < 0)
2252 continue;
2253
2254 /* Changed route only output. */
2255 if (route_type == rip_changed_route &&
2256 (! (rinfo->flags & RIP_RTF_CHANGED)))
2257 continue;
2258
2259 /* Split horizon. */
2260 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002261 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002262 {
paul42d14d92003-11-17 09:15:18 +00002263 /*
2264 * We perform split horizon for RIP and connected route.
2265 * For rip routes, we want to suppress the route if we would
2266 * end up sending the route back on the interface that we
2267 * learned it from, with a higher metric. For connected routes,
2268 * we suppress the route if the prefix is a subset of the
2269 * source address that we are going to use for the packet
2270 * (in order to handle the case when multiple subnets are
2271 * configured on the same interface).
2272 */
2273 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002274 rinfo->ifindex == ifc->ifp->ifindex)
paul42d14d92003-11-17 09:15:18 +00002275 continue;
2276 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002277 prefix_match((struct prefix *)p, ifc->address))
paul718e3742002-12-13 20:15:29 +00002278 continue;
2279 }
2280
2281 /* Preparation for route-map. */
2282 rinfo->metric_set = 0;
2283 rinfo->nexthop_out.s_addr = 0;
2284 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002285 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002286 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002287
hasso16705132003-05-25 14:49:19 +00002288 /* In order to avoid some local loops,
2289 * if the RIP route has a nexthop via this interface, keep the nexthop,
2290 * otherwise set it to 0. The nexthop should not be propagated
2291 * beyond the local broadcast/multicast area in order
2292 * to avoid an IGP multi-level recursive look-up.
2293 * see (4.4)
2294 */
paulc49ad8f2004-10-22 10:27:28 +00002295 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002296 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002297
2298 /* Interface route-map */
2299 if (ri->routemap[RIP_FILTER_OUT])
2300 {
2301 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2302 (struct prefix *) p, RMAP_RIP,
2303 rinfo);
2304
2305 if (ret == RMAP_DENYMATCH)
2306 {
2307 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002308 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002309 inet_ntoa (p->prefix), p->prefixlen);
2310 continue;
2311 }
2312 }
paul718e3742002-12-13 20:15:29 +00002313
hasso16705132003-05-25 14:49:19 +00002314 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002315 if (rip->route_map[rinfo->type].name
2316 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2317 {
2318 ret = route_map_apply (rip->route_map[rinfo->type].map,
2319 (struct prefix *)p, RMAP_RIP, rinfo);
2320
2321 if (ret == RMAP_DENYMATCH)
2322 {
2323 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002324 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002325 inet_ntoa (p->prefix), p->prefixlen);
2326 continue;
2327 }
2328 }
2329
2330 /* When route-map does not set metric. */
2331 if (! rinfo->metric_set)
2332 {
2333 /* If redistribute metric is set. */
2334 if (rip->route_map[rinfo->type].metric_config
2335 && rinfo->metric != RIP_METRIC_INFINITY)
2336 {
2337 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2338 }
2339 else
2340 {
2341 /* If the route is not connected or localy generated
2342 one, use default-metric value*/
2343 if (rinfo->type != ZEBRA_ROUTE_RIP
2344 && rinfo->type != ZEBRA_ROUTE_CONNECT
2345 && rinfo->metric != RIP_METRIC_INFINITY)
2346 rinfo->metric_out = rip->default_metric;
2347 }
2348 }
2349
2350 /* Apply offset-list */
2351 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002352 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002353
2354 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2355 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002356
2357 /* Perform split-horizon with poisoned reverse
2358 * for RIP and connected routes.
2359 **/
2360 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002361 /*
2362 * We perform split horizon for RIP and connected route.
2363 * For rip routes, we want to suppress the route if we would
2364 * end up sending the route back on the interface that we
2365 * learned it from, with a higher metric. For connected routes,
2366 * we suppress the route if the prefix is a subset of the
2367 * source address that we are going to use for the packet
2368 * (in order to handle the case when multiple subnets are
2369 * configured on the same interface).
2370 */
2371 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002372 rinfo->ifindex == ifc->ifp->ifindex)
hasso16705132003-05-25 14:49:19 +00002373 rinfo->metric_out = RIP_METRIC_INFINITY;
paul42d14d92003-11-17 09:15:18 +00002374 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002375 prefix_match((struct prefix *)p, ifc->address))
paul42d14d92003-11-17 09:15:18 +00002376 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002377 }
paulb14ee002005-02-04 23:42:41 +00002378
2379 /* Prepare preamble, auth headers, if needs be */
2380 if (num == 0)
2381 {
2382 stream_putc (s, RIP_RESPONSE);
2383 stream_putc (s, version);
2384 stream_putw (s, 0);
2385
paul0cb8a012005-05-29 11:27:24 +00002386 /* auth header for !v1 && !no_auth */
2387 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002388 doff = rip_auth_header_write (s, ri, key, auth_str,
2389 RIP_AUTH_SIMPLE_SIZE);
2390 }
2391
paul718e3742002-12-13 20:15:29 +00002392 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002393 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002394 if (num == rtemax)
2395 {
2396 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002397 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002398
2399 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002400 to, ifc);
paul718e3742002-12-13 20:15:29 +00002401
2402 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2403 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2404 stream_get_endp(s), "SEND");
2405 num = 0;
2406 stream_reset (s);
2407 }
2408 }
2409
2410 /* Flush unwritten RTE. */
2411 if (num != 0)
2412 {
2413 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002414 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002415
paulc49ad8f2004-10-22 10:27:28 +00002416 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002417
2418 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2419 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2420 stream_get_endp (s), "SEND");
2421 num = 0;
2422 stream_reset (s);
2423 }
2424
2425 /* Statistics updates. */
2426 ri->sent_updates++;
2427}
2428
2429/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002430static void
paulc49ad8f2004-10-22 10:27:28 +00002431rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002432{
paul718e3742002-12-13 20:15:29 +00002433 struct sockaddr_in to;
2434
2435 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002436 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002437 {
2438 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002439 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002440
paulc49ad8f2004-10-22 10:27:28 +00002441 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002442 return;
2443 }
paulc49ad8f2004-10-22 10:27:28 +00002444
paul718e3742002-12-13 20:15:29 +00002445 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002446 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002447 {
paulc49ad8f2004-10-22 10:27:28 +00002448 if (ifc->address->family == AF_INET)
2449 {
2450 /* Destination address and port setting. */
2451 memset (&to, 0, sizeof (struct sockaddr_in));
2452 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002453 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002454 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002455 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002456 /* calculate the appropriate broadcast address */
2457 to.sin_addr.s_addr =
2458 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2459 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002460 else
2461 /* do not know where to send the packet */
2462 return;
paulc49ad8f2004-10-22 10:27:28 +00002463 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002464
paulc49ad8f2004-10-22 10:27:28 +00002465 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002466 zlog_debug("%s announce to %s on %s",
2467 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2468 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002469
paulc49ad8f2004-10-22 10:27:28 +00002470 rip_output_process (ifc, &to, route_type, version);
2471 }
paul718e3742002-12-13 20:15:29 +00002472 }
2473}
2474
2475/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002476static void
paul718e3742002-12-13 20:15:29 +00002477rip_update_process (int route_type)
2478{
paul1eb8ef22005-04-07 07:30:20 +00002479 struct listnode *node;
2480 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002481 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002482 struct interface *ifp;
2483 struct rip_interface *ri;
2484 struct route_node *rp;
2485 struct sockaddr_in to;
2486 struct prefix_ipv4 *p;
2487
2488 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002489 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002490 {
paul718e3742002-12-13 20:15:29 +00002491 if (if_is_loopback (ifp))
2492 continue;
2493
paul2e3b2e42002-12-13 21:03:13 +00002494 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002495 continue;
2496
2497 /* Fetch RIP interface information. */
2498 ri = ifp->info;
2499
2500 /* When passive interface is specified, suppress announce to the
2501 interface. */
2502 if (ri->passive)
2503 continue;
2504
2505 if (ri->running)
2506 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002507 /*
2508 * If there is no version configuration in the interface,
2509 * use rip's version setting.
2510 */
2511 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2512 rip->version_send : ri->ri_send);
2513
paul718e3742002-12-13 20:15:29 +00002514 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002515 zlog_debug("SEND UPDATE to %s ifindex %d",
2516 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002517
paulcc1131a2003-10-15 23:20:17 +00002518 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002519 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002520 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002521 if (connected->address->family == AF_INET)
2522 {
2523 if (vsend & RIPv1)
2524 rip_update_interface (connected, RIPv1, route_type);
2525 if ((vsend & RIPv2) && if_is_multicast(ifp))
2526 rip_update_interface (connected, RIPv2, route_type);
2527 }
2528 }
paul718e3742002-12-13 20:15:29 +00002529 }
2530 }
2531
2532 /* RIP send updates to each neighbor. */
2533 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2534 if (rp->info != NULL)
2535 {
2536 p = (struct prefix_ipv4 *) &rp->p;
2537
2538 ifp = if_lookup_address (p->prefix);
2539 if (! ifp)
2540 {
paulc49ad8f2004-10-22 10:27:28 +00002541 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002542 inet_ntoa (p->prefix));
2543 continue;
2544 }
paulc49ad8f2004-10-22 10:27:28 +00002545
2546 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2547 {
2548 zlog_warn ("Neighbor %s doesnt have connected network",
2549 inet_ntoa (p->prefix));
2550 continue;
2551 }
2552
paul718e3742002-12-13 20:15:29 +00002553 /* Set destination address and port */
2554 memset (&to, 0, sizeof (struct sockaddr_in));
2555 to.sin_addr = p->prefix;
2556 to.sin_port = htons (RIP_PORT_DEFAULT);
2557
2558 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002559 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002560 }
2561}
2562
2563/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002564static int
paul718e3742002-12-13 20:15:29 +00002565rip_update (struct thread *t)
2566{
2567 /* Clear timer pointer. */
2568 rip->t_update = NULL;
2569
2570 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002571 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002572
2573 /* Process update output. */
2574 rip_update_process (rip_all_route);
2575
2576 /* Triggered updates may be suppressed if a regular update is due by
2577 the time the triggered update would be sent. */
2578 if (rip->t_triggered_interval)
2579 {
2580 thread_cancel (rip->t_triggered_interval);
2581 rip->t_triggered_interval = NULL;
2582 }
2583 rip->trigger = 0;
2584
2585 /* Register myself. */
2586 rip_event (RIP_UPDATE_EVENT, 0);
2587
2588 return 0;
2589}
2590
2591/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002592static void
paul216565a2005-10-25 23:35:28 +00002593rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002594{
2595 struct route_node *rp;
2596 struct rip_info *rinfo;
2597
2598 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2599 if ((rinfo = rp->info) != NULL)
2600 if (rinfo->flags & RIP_RTF_CHANGED)
2601 rinfo->flags &= ~RIP_RTF_CHANGED;
2602}
2603
2604/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002605static int
paul718e3742002-12-13 20:15:29 +00002606rip_triggered_interval (struct thread *t)
2607{
2608 int rip_triggered_update (struct thread *);
2609
2610 rip->t_triggered_interval = NULL;
2611
2612 if (rip->trigger)
2613 {
2614 rip->trigger = 0;
2615 rip_triggered_update (t);
2616 }
2617 return 0;
2618}
2619
2620/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002621static int
paul718e3742002-12-13 20:15:29 +00002622rip_triggered_update (struct thread *t)
2623{
2624 int interval;
2625
2626 /* Clear thred pointer. */
2627 rip->t_triggered_update = NULL;
2628
2629 /* Cancel interval timer. */
2630 if (rip->t_triggered_interval)
2631 {
2632 thread_cancel (rip->t_triggered_interval);
2633 rip->t_triggered_interval = NULL;
2634 }
2635 rip->trigger = 0;
2636
2637 /* Logging triggered update. */
2638 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002639 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002640
2641 /* Split Horizon processing is done when generating triggered
2642 updates as well as normal updates (see section 2.6). */
2643 rip_update_process (rip_changed_route);
2644
2645 /* Once all of the triggered updates have been generated, the route
2646 change flags should be cleared. */
2647 rip_clear_changed_flag ();
2648
2649 /* After a triggered update is sent, a timer should be set for a
2650 random interval between 1 and 5 seconds. If other changes that
2651 would trigger updates occur before the timer expires, a single
2652 update is triggered when the timer expires. */
2653 interval = (random () % 5) + 1;
2654
2655 rip->t_triggered_interval =
2656 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2657
2658 return 0;
2659}
2660
2661/* Withdraw redistributed route. */
2662void
2663rip_redistribute_withdraw (int type)
2664{
2665 struct route_node *rp;
2666 struct rip_info *rinfo;
2667
2668 if (!rip)
2669 return;
2670
2671 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2672 if ((rinfo = rp->info) != NULL)
2673 {
2674 if (rinfo->type == type
2675 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2676 {
2677 /* Perform poisoned reverse. */
2678 rinfo->metric = RIP_METRIC_INFINITY;
2679 RIP_TIMER_ON (rinfo->t_garbage_collect,
2680 rip_garbage_collect, rip->garbage_time);
2681 RIP_TIMER_OFF (rinfo->t_timeout);
2682 rinfo->flags |= RIP_RTF_CHANGED;
2683
hasso16705132003-05-25 14:49:19 +00002684 if (IS_RIP_DEBUG_EVENT) {
2685 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2686
ajs5d6c3772004-12-08 19:24:06 +00002687 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002688 inet_ntoa(p->prefix), p->prefixlen,
2689 ifindex2ifname(rinfo->ifindex));
2690 }
2691
paul718e3742002-12-13 20:15:29 +00002692 rip_event (RIP_TRIGGERED_UPDATE, 0);
2693 }
2694 }
2695}
2696
2697/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002698static int
2699rip_create (void)
paul718e3742002-12-13 20:15:29 +00002700{
Stephen Hemminger393deb92008-08-18 14:13:29 -07002701 rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
paul718e3742002-12-13 20:15:29 +00002702
2703 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002704 rip->version_send = RI_RIP_VERSION_2;
2705 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002706 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2707 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2708 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2709 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2710
2711 /* Initialize RIP routig table. */
2712 rip->table = route_table_init ();
2713 rip->route = route_table_init ();
2714 rip->neighbor = route_table_init ();
2715
2716 /* Make output stream. */
2717 rip->obuf = stream_new (1500);
2718
2719 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002720 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002721 if (rip->sock < 0)
2722 return rip->sock;
2723
2724 /* Create read and timer thread. */
2725 rip_event (RIP_READ, rip->sock);
2726 rip_event (RIP_UPDATE_EVENT, 1);
2727
2728 return 0;
2729}
2730
2731/* Sned RIP request to the destination. */
2732int
2733rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002734 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002735{
2736 struct rte *rte;
2737 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002738 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002739
2740 memset (&rip_packet, 0, sizeof (rip_packet));
2741
2742 rip_packet.command = RIP_REQUEST;
2743 rip_packet.version = version;
2744 rte = rip_packet.rte;
2745 rte->metric = htonl (RIP_METRIC_INFINITY);
2746
paul931cd542004-01-23 15:31:42 +00002747 if (connected)
2748 {
2749 /*
2750 * connected is only sent for ripv1 case, or when
2751 * interface does not support multicast. Caller loops
2752 * over each connected address for this case.
2753 */
paul11dde9c2004-05-31 14:00:00 +00002754 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002755 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002756 return -1;
2757 else
2758 return sizeof (rip_packet);
2759 }
2760
paulcc1131a2003-10-15 23:20:17 +00002761 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002762 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002763 {
2764 struct prefix_ipv4 *p;
2765
2766 p = (struct prefix_ipv4 *) connected->address;
2767
2768 if (p->family != AF_INET)
2769 continue;
2770
paul11dde9c2004-05-31 14:00:00 +00002771 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002772 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002773 return -1;
2774 }
2775 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002776}
David Lamparter6b0655a2014-06-04 06:53:35 +02002777
pauldc63bfd2005-10-25 23:31:05 +00002778static int
paul718e3742002-12-13 20:15:29 +00002779rip_update_jitter (unsigned long time)
2780{
paul239389b2004-05-05 14:09:37 +00002781#define JITTER_BOUND 4
2782 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2783 Given that, we cannot let time be less than JITTER_BOUND seconds.
2784 The RIPv2 RFC says jitter should be small compared to
2785 update_time. We consider 1/JITTER_BOUND to be small.
2786 */
2787
2788 int jitter_input = time;
2789 int jitter;
2790
2791 if (jitter_input < JITTER_BOUND)
2792 jitter_input = JITTER_BOUND;
2793
2794 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2795
2796 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002797}
2798
2799void
2800rip_event (enum rip_event event, int sock)
2801{
2802 int jitter = 0;
2803
2804 switch (event)
2805 {
2806 case RIP_READ:
2807 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2808 break;
2809 case RIP_UPDATE_EVENT:
2810 if (rip->t_update)
2811 {
2812 thread_cancel (rip->t_update);
2813 rip->t_update = NULL;
2814 }
2815 jitter = rip_update_jitter (rip->update_time);
2816 rip->t_update =
2817 thread_add_timer (master, rip_update, NULL,
2818 sock ? 2 : rip->update_time + jitter);
2819 break;
2820 case RIP_TRIGGERED_UPDATE:
2821 if (rip->t_triggered_interval)
2822 rip->trigger = 1;
2823 else if (! rip->t_triggered_update)
2824 rip->t_triggered_update =
2825 thread_add_event (master, rip_triggered_update, NULL, 0);
2826 break;
2827 default:
2828 break;
2829 }
2830}
David Lamparter6b0655a2014-06-04 06:53:35 +02002831
paul718e3742002-12-13 20:15:29 +00002832DEFUN (router_rip,
2833 router_rip_cmd,
2834 "router rip",
2835 "Enable a routing process\n"
2836 "Routing Information Protocol (RIP)\n")
2837{
2838 int ret;
2839
2840 /* If rip is not enabled before. */
2841 if (! rip)
2842 {
2843 ret = rip_create ();
2844 if (ret < 0)
2845 {
2846 zlog_info ("Can't create RIP");
2847 return CMD_WARNING;
2848 }
2849 }
2850 vty->node = RIP_NODE;
2851 vty->index = rip;
2852
2853 return CMD_SUCCESS;
2854}
2855
2856DEFUN (no_router_rip,
2857 no_router_rip_cmd,
2858 "no router rip",
2859 NO_STR
2860 "Enable a routing process\n"
2861 "Routing Information Protocol (RIP)\n")
2862{
2863 if (rip)
2864 rip_clean ();
2865 return CMD_SUCCESS;
2866}
2867
2868DEFUN (rip_version,
2869 rip_version_cmd,
2870 "version <1-2>",
2871 "Set routing protocol version\n"
2872 "version\n")
2873{
2874 int version;
2875
2876 version = atoi (argv[0]);
2877 if (version != RIPv1 && version != RIPv2)
2878 {
2879 vty_out (vty, "invalid rip version %d%s", version,
2880 VTY_NEWLINE);
2881 return CMD_WARNING;
2882 }
paulf38a4712003-06-07 01:10:00 +00002883 rip->version_send = version;
2884 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002885
2886 return CMD_SUCCESS;
2887}
2888
2889DEFUN (no_rip_version,
2890 no_rip_version_cmd,
2891 "no version",
2892 NO_STR
2893 "Set routing protocol version\n")
2894{
2895 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002896 rip->version_send = RI_RIP_VERSION_2;
2897 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002898
2899 return CMD_SUCCESS;
2900}
2901
2902ALIAS (no_rip_version,
2903 no_rip_version_val_cmd,
2904 "no version <1-2>",
2905 NO_STR
2906 "Set routing protocol version\n"
2907 "version\n")
2908
2909DEFUN (rip_route,
2910 rip_route_cmd,
2911 "route A.B.C.D/M",
2912 "RIP static route configuration\n"
2913 "IP prefix <network>/<length>\n")
2914{
2915 int ret;
2916 struct prefix_ipv4 p;
2917 struct route_node *node;
2918
2919 ret = str2prefix_ipv4 (argv[0], &p);
2920 if (ret < 0)
2921 {
2922 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2923 return CMD_WARNING;
2924 }
2925 apply_mask_ipv4 (&p);
2926
2927 /* For router rip configuration. */
2928 node = route_node_get (rip->route, (struct prefix *) &p);
2929
2930 if (node->info)
2931 {
2932 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2933 route_unlock_node (node);
2934 return CMD_WARNING;
2935 }
2936
hasso8a676be2004-10-08 06:36:38 +00002937 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002938
vincentfbf5d032005-09-29 11:25:50 +00002939 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002940
2941 return CMD_SUCCESS;
2942}
2943
2944DEFUN (no_rip_route,
2945 no_rip_route_cmd,
2946 "no route A.B.C.D/M",
2947 NO_STR
2948 "RIP static route configuration\n"
2949 "IP prefix <network>/<length>\n")
2950{
2951 int ret;
2952 struct prefix_ipv4 p;
2953 struct route_node *node;
2954
2955 ret = str2prefix_ipv4 (argv[0], &p);
2956 if (ret < 0)
2957 {
2958 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2959 return CMD_WARNING;
2960 }
2961 apply_mask_ipv4 (&p);
2962
2963 /* For router rip configuration. */
2964 node = route_node_lookup (rip->route, (struct prefix *) &p);
2965 if (! node)
2966 {
2967 vty_out (vty, "Can't find route %s.%s", argv[0],
2968 VTY_NEWLINE);
2969 return CMD_WARNING;
2970 }
2971
2972 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2973 route_unlock_node (node);
2974
2975 node->info = NULL;
2976 route_unlock_node (node);
2977
2978 return CMD_SUCCESS;
2979}
2980
Stephen Hemminger2c239702009-12-10 19:16:05 +03002981#if 0
pauldc63bfd2005-10-25 23:31:05 +00002982static void
paul216565a2005-10-25 23:35:28 +00002983rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002984{
2985 struct route_node *np;
2986 struct rip_info *rinfo;
2987
2988 for (np = route_top (rip->table); np; np = route_next (np))
2989 if ((rinfo = np->info) != NULL)
2990 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2991 rinfo->metric = rip->default_metric;
2992}
Stephen Hemminger2c239702009-12-10 19:16:05 +03002993#endif
paul718e3742002-12-13 20:15:29 +00002994
2995DEFUN (rip_default_metric,
2996 rip_default_metric_cmd,
2997 "default-metric <1-16>",
2998 "Set a metric of redistribute routes\n"
2999 "Default metric\n")
3000{
3001 if (rip)
3002 {
3003 rip->default_metric = atoi (argv[0]);
3004 /* rip_update_default_metric (); */
3005 }
3006 return CMD_SUCCESS;
3007}
3008
3009DEFUN (no_rip_default_metric,
3010 no_rip_default_metric_cmd,
3011 "no default-metric",
3012 NO_STR
3013 "Set a metric of redistribute routes\n"
3014 "Default metric\n")
3015{
3016 if (rip)
3017 {
3018 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3019 /* rip_update_default_metric (); */
3020 }
3021 return CMD_SUCCESS;
3022}
3023
3024ALIAS (no_rip_default_metric,
3025 no_rip_default_metric_val_cmd,
3026 "no default-metric <1-16>",
3027 NO_STR
3028 "Set a metric of redistribute routes\n"
3029 "Default metric\n")
3030
3031DEFUN (rip_timers,
3032 rip_timers_cmd,
3033 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3034 "Adjust routing timers\n"
3035 "Basic routing protocol update timers\n"
3036 "Routing table update timer value in second. Default is 30.\n"
3037 "Routing information timeout timer. Default is 180.\n"
3038 "Garbage collection timer. Default is 120.\n")
3039{
3040 unsigned long update;
3041 unsigned long timeout;
3042 unsigned long garbage;
3043 char *endptr = NULL;
3044 unsigned long RIP_TIMER_MAX = 2147483647;
3045 unsigned long RIP_TIMER_MIN = 5;
3046
3047 update = strtoul (argv[0], &endptr, 10);
3048 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3049 {
3050 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3051 return CMD_WARNING;
3052 }
3053
3054 timeout = strtoul (argv[1], &endptr, 10);
3055 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3056 {
3057 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3058 return CMD_WARNING;
3059 }
3060
3061 garbage = strtoul (argv[2], &endptr, 10);
3062 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3063 {
3064 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3065 return CMD_WARNING;
3066 }
3067
3068 /* Set each timer value. */
3069 rip->update_time = update;
3070 rip->timeout_time = timeout;
3071 rip->garbage_time = garbage;
3072
3073 /* Reset update timer thread. */
3074 rip_event (RIP_UPDATE_EVENT, 0);
3075
3076 return CMD_SUCCESS;
3077}
3078
3079DEFUN (no_rip_timers,
3080 no_rip_timers_cmd,
3081 "no timers basic",
3082 NO_STR
3083 "Adjust routing timers\n"
3084 "Basic routing protocol update timers\n")
3085{
3086 /* Set each timer value to the default. */
3087 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3088 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3089 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3090
3091 /* Reset update timer thread. */
3092 rip_event (RIP_UPDATE_EVENT, 0);
3093
3094 return CMD_SUCCESS;
3095}
hasso16705132003-05-25 14:49:19 +00003096
3097ALIAS (no_rip_timers,
3098 no_rip_timers_val_cmd,
3099 "no timers basic <0-65535> <0-65535> <0-65535>",
3100 NO_STR
3101 "Adjust routing timers\n"
3102 "Basic routing protocol update timers\n"
3103 "Routing table update timer value in second. Default is 30.\n"
3104 "Routing information timeout timer. Default is 180.\n"
3105 "Garbage collection timer. Default is 120.\n")
3106
David Lamparter6b0655a2014-06-04 06:53:35 +02003107
paul718e3742002-12-13 20:15:29 +00003108struct route_table *rip_distance_table;
3109
3110struct rip_distance
3111{
3112 /* Distance value for the IP source prefix. */
3113 u_char distance;
3114
3115 /* Name of the access-list to be matched. */
3116 char *access_list;
3117};
3118
pauldc63bfd2005-10-25 23:31:05 +00003119static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003120rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003121{
Stephen Hemminger393deb92008-08-18 14:13:29 -07003122 return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
paul718e3742002-12-13 20:15:29 +00003123}
3124
pauldc63bfd2005-10-25 23:31:05 +00003125static void
paul718e3742002-12-13 20:15:29 +00003126rip_distance_free (struct rip_distance *rdistance)
3127{
3128 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3129}
3130
pauldc63bfd2005-10-25 23:31:05 +00003131static int
hasso98b718a2004-10-11 12:57:57 +00003132rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3133 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003134{
3135 int ret;
3136 struct prefix_ipv4 p;
3137 u_char distance;
3138 struct route_node *rn;
3139 struct rip_distance *rdistance;
3140
3141 ret = str2prefix_ipv4 (ip_str, &p);
3142 if (ret == 0)
3143 {
3144 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3145 return CMD_WARNING;
3146 }
3147
3148 distance = atoi (distance_str);
3149
3150 /* Get RIP distance node. */
3151 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3152 if (rn->info)
3153 {
3154 rdistance = rn->info;
3155 route_unlock_node (rn);
3156 }
3157 else
3158 {
3159 rdistance = rip_distance_new ();
3160 rn->info = rdistance;
3161 }
3162
3163 /* Set distance value. */
3164 rdistance->distance = distance;
3165
3166 /* Reset access-list configuration. */
3167 if (rdistance->access_list)
3168 {
3169 free (rdistance->access_list);
3170 rdistance->access_list = NULL;
3171 }
3172 if (access_list_str)
3173 rdistance->access_list = strdup (access_list_str);
3174
3175 return CMD_SUCCESS;
3176}
3177
pauldc63bfd2005-10-25 23:31:05 +00003178static int
hasso98b718a2004-10-11 12:57:57 +00003179rip_distance_unset (struct vty *vty, const char *distance_str,
3180 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003181{
3182 int ret;
3183 struct prefix_ipv4 p;
3184 u_char distance;
3185 struct route_node *rn;
3186 struct rip_distance *rdistance;
3187
3188 ret = str2prefix_ipv4 (ip_str, &p);
3189 if (ret == 0)
3190 {
3191 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3192 return CMD_WARNING;
3193 }
3194
3195 distance = atoi (distance_str);
3196
3197 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3198 if (! rn)
3199 {
3200 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3201 return CMD_WARNING;
3202 }
3203
3204 rdistance = rn->info;
3205
3206 if (rdistance->access_list)
3207 free (rdistance->access_list);
3208 rip_distance_free (rdistance);
3209
3210 rn->info = NULL;
3211 route_unlock_node (rn);
3212 route_unlock_node (rn);
3213
3214 return CMD_SUCCESS;
3215}
3216
pauldc63bfd2005-10-25 23:31:05 +00003217static void
paul216565a2005-10-25 23:35:28 +00003218rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003219{
3220 struct route_node *rn;
3221 struct rip_distance *rdistance;
3222
3223 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3224 if ((rdistance = rn->info) != NULL)
3225 {
3226 if (rdistance->access_list)
3227 free (rdistance->access_list);
3228 rip_distance_free (rdistance);
3229 rn->info = NULL;
3230 route_unlock_node (rn);
3231 }
3232}
3233
3234/* Apply RIP information to distance method. */
3235u_char
3236rip_distance_apply (struct rip_info *rinfo)
3237{
3238 struct route_node *rn;
3239 struct prefix_ipv4 p;
3240 struct rip_distance *rdistance;
3241 struct access_list *alist;
3242
3243 if (! rip)
3244 return 0;
3245
3246 memset (&p, 0, sizeof (struct prefix_ipv4));
3247 p.family = AF_INET;
3248 p.prefix = rinfo->from;
3249 p.prefixlen = IPV4_MAX_BITLEN;
3250
3251 /* Check source address. */
3252 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3253 if (rn)
3254 {
3255 rdistance = rn->info;
3256 route_unlock_node (rn);
3257
3258 if (rdistance->access_list)
3259 {
3260 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3261 if (alist == NULL)
3262 return 0;
3263 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3264 return 0;
3265
3266 return rdistance->distance;
3267 }
3268 else
3269 return rdistance->distance;
3270 }
3271
3272 if (rip->distance)
3273 return rip->distance;
3274
3275 return 0;
3276}
3277
pauldc63bfd2005-10-25 23:31:05 +00003278static void
paul718e3742002-12-13 20:15:29 +00003279rip_distance_show (struct vty *vty)
3280{
3281 struct route_node *rn;
3282 struct rip_distance *rdistance;
3283 int header = 1;
3284 char buf[BUFSIZ];
3285
3286 vty_out (vty, " Distance: (default is %d)%s",
3287 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3288 VTY_NEWLINE);
3289
3290 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3291 if ((rdistance = rn->info) != NULL)
3292 {
3293 if (header)
3294 {
3295 vty_out (vty, " Address Distance List%s",
3296 VTY_NEWLINE);
3297 header = 0;
3298 }
3299 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3300 vty_out (vty, " %-20s %4d %s%s",
3301 buf, rdistance->distance,
3302 rdistance->access_list ? rdistance->access_list : "",
3303 VTY_NEWLINE);
3304 }
3305}
3306
3307DEFUN (rip_distance,
3308 rip_distance_cmd,
3309 "distance <1-255>",
3310 "Administrative distance\n"
3311 "Distance value\n")
3312{
3313 rip->distance = atoi (argv[0]);
3314 return CMD_SUCCESS;
3315}
3316
3317DEFUN (no_rip_distance,
3318 no_rip_distance_cmd,
3319 "no distance <1-255>",
3320 NO_STR
3321 "Administrative distance\n"
3322 "Distance value\n")
3323{
3324 rip->distance = 0;
3325 return CMD_SUCCESS;
3326}
3327
3328DEFUN (rip_distance_source,
3329 rip_distance_source_cmd,
3330 "distance <1-255> A.B.C.D/M",
3331 "Administrative distance\n"
3332 "Distance value\n"
3333 "IP source prefix\n")
3334{
3335 rip_distance_set (vty, argv[0], argv[1], NULL);
3336 return CMD_SUCCESS;
3337}
3338
3339DEFUN (no_rip_distance_source,
3340 no_rip_distance_source_cmd,
3341 "no distance <1-255> A.B.C.D/M",
3342 NO_STR
3343 "Administrative distance\n"
3344 "Distance value\n"
3345 "IP source prefix\n")
3346{
3347 rip_distance_unset (vty, argv[0], argv[1], NULL);
3348 return CMD_SUCCESS;
3349}
3350
3351DEFUN (rip_distance_source_access_list,
3352 rip_distance_source_access_list_cmd,
3353 "distance <1-255> A.B.C.D/M WORD",
3354 "Administrative distance\n"
3355 "Distance value\n"
3356 "IP source prefix\n"
3357 "Access list name\n")
3358{
3359 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3360 return CMD_SUCCESS;
3361}
3362
3363DEFUN (no_rip_distance_source_access_list,
3364 no_rip_distance_source_access_list_cmd,
3365 "no distance <1-255> A.B.C.D/M WORD",
3366 NO_STR
3367 "Administrative distance\n"
3368 "Distance value\n"
3369 "IP source prefix\n"
3370 "Access list name\n")
3371{
3372 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3373 return CMD_SUCCESS;
3374}
David Lamparter6b0655a2014-06-04 06:53:35 +02003375
paul718e3742002-12-13 20:15:29 +00003376/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003377static void
paul718e3742002-12-13 20:15:29 +00003378rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3379{
paul718e3742002-12-13 20:15:29 +00003380 time_t clock;
3381 struct tm *tm;
3382#define TIME_BUF 25
3383 char timebuf [TIME_BUF];
3384 struct thread *thread;
3385
paul718e3742002-12-13 20:15:29 +00003386 if ((thread = rinfo->t_timeout) != NULL)
3387 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003388 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003389 tm = gmtime (&clock);
3390 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3391 vty_out (vty, "%5s", timebuf);
3392 }
3393 else if ((thread = rinfo->t_garbage_collect) != NULL)
3394 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003395 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003396 tm = gmtime (&clock);
3397 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3398 vty_out (vty, "%5s", timebuf);
3399 }
3400}
3401
pauldc63bfd2005-10-25 23:31:05 +00003402static const char *
paul718e3742002-12-13 20:15:29 +00003403rip_route_type_print (int sub_type)
3404{
3405 switch (sub_type)
3406 {
3407 case RIP_ROUTE_RTE:
3408 return "n";
3409 case RIP_ROUTE_STATIC:
3410 return "s";
3411 case RIP_ROUTE_DEFAULT:
3412 return "d";
3413 case RIP_ROUTE_REDISTRIBUTE:
3414 return "r";
3415 case RIP_ROUTE_INTERFACE:
3416 return "i";
3417 default:
3418 return "?";
3419 }
3420}
3421
3422DEFUN (show_ip_rip,
3423 show_ip_rip_cmd,
3424 "show ip rip",
3425 SHOW_STR
3426 IP_STR
3427 "Show RIP routes\n")
3428{
3429 struct route_node *np;
3430 struct rip_info *rinfo;
3431
3432 if (! rip)
3433 return CMD_SUCCESS;
3434
hasso16705132003-05-25 14:49:19 +00003435 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3436 "Sub-codes:%s"
3437 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003438 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003439 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003440 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003441
3442 for (np = route_top (rip->table); np; np = route_next (np))
3443 if ((rinfo = np->info) != NULL)
3444 {
3445 int len;
3446
ajsf52d13c2005-10-01 17:38:06 +00003447 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003448 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003449 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003450 rip_route_type_print (rinfo->sub_type),
3451 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3452
hassoa1455d82004-03-03 19:36:24 +00003453 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003454
3455 if (len > 0)
3456 vty_out (vty, "%*s", len, " ");
3457
3458 if (rinfo->nexthop.s_addr)
3459 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3460 rinfo->metric);
3461 else
3462 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3463
3464 /* Route which exist in kernel routing table. */
3465 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3466 (rinfo->sub_type == RIP_ROUTE_RTE))
3467 {
3468 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003469 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003470 rip_vty_out_uptime (vty, rinfo);
3471 }
3472 else if (rinfo->metric == RIP_METRIC_INFINITY)
3473 {
3474 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003475 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003476 rip_vty_out_uptime (vty, rinfo);
3477 }
3478 else
hasso16705132003-05-25 14:49:19 +00003479 {
vincentfbf5d032005-09-29 11:25:50 +00003480 if (rinfo->external_metric)
3481 {
3482 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003483 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003484 rinfo->external_metric);
3485 len = 16 - len;
3486 if (len > 0)
3487 vty_out (vty, "%*s", len, " ");
3488 }
3489 else
3490 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003491 vty_out (vty, "%3d", rinfo->tag);
3492 }
paul718e3742002-12-13 20:15:29 +00003493
3494 vty_out (vty, "%s", VTY_NEWLINE);
3495 }
3496 return CMD_SUCCESS;
3497}
3498
hasso16705132003-05-25 14:49:19 +00003499/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3500DEFUN (show_ip_rip_status,
3501 show_ip_rip_status_cmd,
3502 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003503 SHOW_STR
3504 IP_STR
hasso16705132003-05-25 14:49:19 +00003505 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003506 "IP routing protocol process parameters and statistics\n")
3507{
hasso52dc7ee2004-09-23 19:18:23 +00003508 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003509 struct interface *ifp;
3510 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003511 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003512 const char *send_version;
3513 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003514
3515 if (! rip)
3516 return CMD_SUCCESS;
3517
3518 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3519 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3520 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003521 vty_out (vty, " next due in %lu seconds%s",
3522 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003523 VTY_NEWLINE);
3524 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3525 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3526 VTY_NEWLINE);
3527
3528 /* Filtering status show. */
3529 config_show_distribute (vty);
3530
3531 /* Default metric information. */
3532 vty_out (vty, " Default redistribution metric is %d%s",
3533 rip->default_metric, VTY_NEWLINE);
3534
3535 /* Redistribute information. */
3536 vty_out (vty, " Redistributing:");
3537 config_write_rip_redistribute (vty, 0);
3538 vty_out (vty, "%s", VTY_NEWLINE);
3539
paulf38a4712003-06-07 01:10:00 +00003540 vty_out (vty, " Default version control: send version %s,",
3541 lookup(ri_version_msg,rip->version_send));
3542 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3543 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3544 else
3545 vty_out (vty, " receive version %s %s",
3546 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003547
3548 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3549
paul1eb8ef22005-04-07 07:30:20 +00003550 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003551 {
paul718e3742002-12-13 20:15:29 +00003552 ri = ifp->info;
3553
Stephen Hemminger82f5ee12009-04-07 15:00:46 -07003554 if (!ri->running)
3555 continue;
3556
paul718e3742002-12-13 20:15:29 +00003557 if (ri->enable_network || ri->enable_interface)
3558 {
3559 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003560 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003561 else
3562 send_version = lookup (ri_version_msg, ri->ri_send);
3563
3564 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003565 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003566 else
3567 receive_version = lookup (ri_version_msg, ri->ri_receive);
3568
3569 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3570 send_version,
3571 receive_version,
3572 ri->key_chain ? ri->key_chain : "",
3573 VTY_NEWLINE);
3574 }
3575 }
3576
3577 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3578 config_write_rip_network (vty, 0);
3579
paul4aaff3f2003-06-07 01:04:45 +00003580 {
3581 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003582 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003583 {
paul4aaff3f2003-06-07 01:04:45 +00003584 ri = ifp->info;
3585
3586 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3587 {
3588 if (!found_passive)
3589 {
3590 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3591 found_passive = 1;
3592 }
3593 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3594 }
3595 }
3596 }
3597
paul718e3742002-12-13 20:15:29 +00003598 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3599 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3600 rip_peer_display (vty);
3601
3602 rip_distance_show (vty);
3603
3604 return CMD_SUCCESS;
3605}
3606
3607/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003608static int
paul718e3742002-12-13 20:15:29 +00003609config_write_rip (struct vty *vty)
3610{
3611 int write = 0;
3612 struct route_node *rn;
3613 struct rip_distance *rdistance;
3614
3615 if (rip)
3616 {
3617 /* Router RIP statement. */
3618 vty_out (vty, "router rip%s", VTY_NEWLINE);
3619 write++;
3620
3621 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003622 if (rip->version_send != RI_RIP_VERSION_2
3623 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3624 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003625 VTY_NEWLINE);
3626
3627 /* RIP timer configuration. */
3628 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3629 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3630 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3631 vty_out (vty, " timers basic %lu %lu %lu%s",
3632 rip->update_time,
3633 rip->timeout_time,
3634 rip->garbage_time,
3635 VTY_NEWLINE);
3636
3637 /* Default information configuration. */
3638 if (rip->default_information)
3639 {
3640 if (rip->default_information_route_map)
3641 vty_out (vty, " default-information originate route-map %s%s",
3642 rip->default_information_route_map, VTY_NEWLINE);
3643 else
3644 vty_out (vty, " default-information originate%s",
3645 VTY_NEWLINE);
3646 }
3647
3648 /* Redistribute configuration. */
3649 config_write_rip_redistribute (vty, 1);
3650
3651 /* RIP offset-list configuration. */
3652 config_write_rip_offset_list (vty);
3653
3654 /* RIP enabled network and interface configuration. */
3655 config_write_rip_network (vty, 1);
3656
3657 /* RIP default metric configuration */
3658 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3659 vty_out (vty, " default-metric %d%s",
3660 rip->default_metric, VTY_NEWLINE);
3661
3662 /* Distribute configuration. */
3663 write += config_write_distribute (vty);
3664
hasso16705132003-05-25 14:49:19 +00003665 /* Interface routemap configuration */
3666 write += config_write_if_rmap (vty);
3667
paul718e3742002-12-13 20:15:29 +00003668 /* Distance configuration. */
3669 if (rip->distance)
3670 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3671
3672 /* RIP source IP prefix distance configuration. */
3673 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3674 if ((rdistance = rn->info) != NULL)
3675 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3676 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3677 rdistance->access_list ? rdistance->access_list : "",
3678 VTY_NEWLINE);
3679
3680 /* RIP static route configuration. */
3681 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3682 if (rn->info)
3683 vty_out (vty, " route %s/%d%s",
3684 inet_ntoa (rn->p.u.prefix4),
3685 rn->p.prefixlen,
3686 VTY_NEWLINE);
3687
3688 }
3689 return write;
3690}
3691
3692/* RIP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08003693static struct cmd_node rip_node =
paul718e3742002-12-13 20:15:29 +00003694{
3695 RIP_NODE,
3696 "%s(config-router)# ",
3697 1
3698};
David Lamparter6b0655a2014-06-04 06:53:35 +02003699
paul718e3742002-12-13 20:15:29 +00003700/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003701static void
paul718e3742002-12-13 20:15:29 +00003702rip_distribute_update (struct distribute *dist)
3703{
3704 struct interface *ifp;
3705 struct rip_interface *ri;
3706 struct access_list *alist;
3707 struct prefix_list *plist;
3708
3709 if (! dist->ifname)
3710 return;
3711
3712 ifp = if_lookup_by_name (dist->ifname);
3713 if (ifp == NULL)
3714 return;
3715
3716 ri = ifp->info;
3717
3718 if (dist->list[DISTRIBUTE_IN])
3719 {
3720 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3721 if (alist)
3722 ri->list[RIP_FILTER_IN] = alist;
3723 else
3724 ri->list[RIP_FILTER_IN] = NULL;
3725 }
3726 else
3727 ri->list[RIP_FILTER_IN] = NULL;
3728
3729 if (dist->list[DISTRIBUTE_OUT])
3730 {
3731 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3732 if (alist)
3733 ri->list[RIP_FILTER_OUT] = alist;
3734 else
3735 ri->list[RIP_FILTER_OUT] = NULL;
3736 }
3737 else
3738 ri->list[RIP_FILTER_OUT] = NULL;
3739
3740 if (dist->prefix[DISTRIBUTE_IN])
3741 {
3742 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3743 if (plist)
3744 ri->prefix[RIP_FILTER_IN] = plist;
3745 else
3746 ri->prefix[RIP_FILTER_IN] = NULL;
3747 }
3748 else
3749 ri->prefix[RIP_FILTER_IN] = NULL;
3750
3751 if (dist->prefix[DISTRIBUTE_OUT])
3752 {
3753 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3754 if (plist)
3755 ri->prefix[RIP_FILTER_OUT] = plist;
3756 else
3757 ri->prefix[RIP_FILTER_OUT] = NULL;
3758 }
3759 else
3760 ri->prefix[RIP_FILTER_OUT] = NULL;
3761}
3762
3763void
3764rip_distribute_update_interface (struct interface *ifp)
3765{
3766 struct distribute *dist;
3767
3768 dist = distribute_lookup (ifp->name);
3769 if (dist)
3770 rip_distribute_update (dist);
3771}
3772
3773/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003774/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003775static void
paul02ff83c2004-06-11 11:27:03 +00003776rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003777{
3778 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003779 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003780
paul1eb8ef22005-04-07 07:30:20 +00003781 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3782 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003783}
paul11dde9c2004-05-31 14:00:00 +00003784/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003785static void
paul11dde9c2004-05-31 14:00:00 +00003786rip_distribute_update_all_wrapper(struct access_list *notused)
3787{
paul02ff83c2004-06-11 11:27:03 +00003788 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003789}
David Lamparter6b0655a2014-06-04 06:53:35 +02003790
paul718e3742002-12-13 20:15:29 +00003791/* Delete all added rip route. */
3792void
paul216565a2005-10-25 23:35:28 +00003793rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003794{
3795 int i;
3796 struct route_node *rp;
3797 struct rip_info *rinfo;
3798
3799 if (rip)
3800 {
3801 /* Clear RIP routes */
3802 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3803 if ((rinfo = rp->info) != NULL)
3804 {
3805 if (rinfo->type == ZEBRA_ROUTE_RIP &&
3806 rinfo->sub_type == RIP_ROUTE_RTE)
3807 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
3808 &rinfo->nexthop, rinfo->metric);
3809
3810 RIP_TIMER_OFF (rinfo->t_timeout);
3811 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3812
3813 rp->info = NULL;
3814 route_unlock_node (rp);
3815
3816 rip_info_free (rinfo);
3817 }
3818
3819 /* Cancel RIP related timers. */
3820 RIP_TIMER_OFF (rip->t_update);
3821 RIP_TIMER_OFF (rip->t_triggered_update);
3822 RIP_TIMER_OFF (rip->t_triggered_interval);
3823
3824 /* Cancel read thread. */
3825 if (rip->t_read)
3826 {
3827 thread_cancel (rip->t_read);
3828 rip->t_read = NULL;
3829 }
3830
3831 /* Close RIP socket. */
3832 if (rip->sock >= 0)
3833 {
3834 close (rip->sock);
3835 rip->sock = -1;
3836 }
3837
3838 /* Static RIP route configuration. */
3839 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3840 if (rp->info)
3841 {
3842 rp->info = NULL;
3843 route_unlock_node (rp);
3844 }
3845
3846 /* RIP neighbor configuration. */
3847 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3848 if (rp->info)
3849 {
3850 rp->info = NULL;
3851 route_unlock_node (rp);
3852 }
3853
3854 /* Redistribute related clear. */
3855 if (rip->default_information_route_map)
3856 free (rip->default_information_route_map);
3857
3858 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3859 if (rip->route_map[i].name)
3860 free (rip->route_map[i].name);
3861
3862 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3863 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3864 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3865
3866 XFREE (MTYPE_RIP, rip);
3867 rip = NULL;
3868 }
3869
3870 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003871 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003872 rip_offset_clean ();
3873 rip_interface_clean ();
3874 rip_distance_reset ();
3875 rip_redistribute_clean ();
3876}
3877
3878/* Reset all values to the default settings. */
3879void
paul216565a2005-10-25 23:35:28 +00003880rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003881{
3882 /* Reset global counters. */
3883 rip_global_route_changes = 0;
3884 rip_global_queries = 0;
3885
3886 /* Call ripd related reset functions. */
3887 rip_debug_reset ();
3888 rip_route_map_reset ();
3889
3890 /* Call library reset functions. */
3891 vty_reset ();
3892 access_list_reset ();
3893 prefix_list_reset ();
3894
3895 distribute_list_reset ();
3896
3897 rip_interface_reset ();
3898 rip_distance_reset ();
3899
3900 rip_zclient_reset ();
3901}
3902
pauldc63bfd2005-10-25 23:31:05 +00003903static void
hasso16705132003-05-25 14:49:19 +00003904rip_if_rmap_update (struct if_rmap *if_rmap)
3905{
3906 struct interface *ifp;
3907 struct rip_interface *ri;
3908 struct route_map *rmap;
3909
3910 ifp = if_lookup_by_name (if_rmap->ifname);
3911 if (ifp == NULL)
3912 return;
3913
3914 ri = ifp->info;
3915
3916 if (if_rmap->routemap[IF_RMAP_IN])
3917 {
3918 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3919 if (rmap)
3920 ri->routemap[IF_RMAP_IN] = rmap;
3921 else
3922 ri->routemap[IF_RMAP_IN] = NULL;
3923 }
3924 else
3925 ri->routemap[RIP_FILTER_IN] = NULL;
3926
3927 if (if_rmap->routemap[IF_RMAP_OUT])
3928 {
3929 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3930 if (rmap)
3931 ri->routemap[IF_RMAP_OUT] = rmap;
3932 else
3933 ri->routemap[IF_RMAP_OUT] = NULL;
3934 }
3935 else
3936 ri->routemap[RIP_FILTER_OUT] = NULL;
3937}
3938
3939void
3940rip_if_rmap_update_interface (struct interface *ifp)
3941{
3942 struct if_rmap *if_rmap;
3943
3944 if_rmap = if_rmap_lookup (ifp->name);
3945 if (if_rmap)
3946 rip_if_rmap_update (if_rmap);
3947}
3948
pauldc63bfd2005-10-25 23:31:05 +00003949static void
hasso16705132003-05-25 14:49:19 +00003950rip_routemap_update_redistribute (void)
3951{
3952 int i;
3953
3954 if (rip)
3955 {
3956 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3957 {
3958 if (rip->route_map[i].name)
3959 rip->route_map[i].map =
3960 route_map_lookup_by_name (rip->route_map[i].name);
3961 }
3962 }
3963}
3964
paul11dde9c2004-05-31 14:00:00 +00003965/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003966static void
hasso98b718a2004-10-11 12:57:57 +00003967rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00003968{
3969 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003970 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00003971
paul1eb8ef22005-04-07 07:30:20 +00003972 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3973 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00003974
3975 rip_routemap_update_redistribute ();
3976}
3977
paul718e3742002-12-13 20:15:29 +00003978/* Allocate new rip structure and set default value. */
3979void
pauldc63bfd2005-10-25 23:31:05 +00003980rip_init (void)
paul718e3742002-12-13 20:15:29 +00003981{
3982 /* Randomize for triggered update random(). */
3983 srand (time (NULL));
3984
3985 /* Install top nodes. */
3986 install_node (&rip_node, config_write_rip);
3987
3988 /* Install rip commands. */
3989 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003990 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003991 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003992 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003993 install_element (CONFIG_NODE, &router_rip_cmd);
3994 install_element (CONFIG_NODE, &no_router_rip_cmd);
3995
3996 install_default (RIP_NODE);
3997 install_element (RIP_NODE, &rip_version_cmd);
3998 install_element (RIP_NODE, &no_rip_version_cmd);
3999 install_element (RIP_NODE, &no_rip_version_val_cmd);
4000 install_element (RIP_NODE, &rip_default_metric_cmd);
4001 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4002 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4003 install_element (RIP_NODE, &rip_timers_cmd);
4004 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004005 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004006 install_element (RIP_NODE, &rip_route_cmd);
4007 install_element (RIP_NODE, &no_rip_route_cmd);
4008 install_element (RIP_NODE, &rip_distance_cmd);
4009 install_element (RIP_NODE, &no_rip_distance_cmd);
4010 install_element (RIP_NODE, &rip_distance_source_cmd);
4011 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4012 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4013 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
4014
4015 /* Debug related init. */
4016 rip_debug_init ();
4017
paul718e3742002-12-13 20:15:29 +00004018 /* SNMP init. */
4019#ifdef HAVE_SNMP
4020 rip_snmp_init ();
4021#endif /* HAVE_SNMP */
4022
4023 /* Access list install. */
4024 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004025 access_list_add_hook (rip_distribute_update_all_wrapper);
4026 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004027
4028 /* Prefix list initialize.*/
4029 prefix_list_init ();
4030 prefix_list_add_hook (rip_distribute_update_all);
4031 prefix_list_delete_hook (rip_distribute_update_all);
4032
4033 /* Distribute list install. */
4034 distribute_list_init (RIP_NODE);
4035 distribute_list_add_hook (rip_distribute_update);
4036 distribute_list_delete_hook (rip_distribute_update);
4037
hasso16705132003-05-25 14:49:19 +00004038 /* Route-map */
4039 rip_route_map_init ();
4040 rip_offset_init ();
4041
4042 route_map_add_hook (rip_routemap_update);
4043 route_map_delete_hook (rip_routemap_update);
4044
4045 if_rmap_init (RIP_NODE);
4046 if_rmap_hook_add (rip_if_rmap_update);
4047 if_rmap_hook_delete (rip_if_rmap_update);
4048
paul718e3742002-12-13 20:15:29 +00004049 /* Distance control. */
4050 rip_distance_table = route_table_init ();
4051}