blob: 62d8691ccd835adac600d99ce770b3224cfea8f9 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIP version 1 and 2.
vincentfbf5d032005-09-29 11:25:50 +00002 * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
paul718e3742002-12-13 20:15:29 +00003 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org>
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "if.h"
26#include "command.h"
27#include "prefix.h"
28#include "table.h"
29#include "thread.h"
30#include "memory.h"
31#include "log.h"
32#include "stream.h"
33#include "filter.h"
34#include "sockunion.h"
hasso1af81932004-09-26 16:11:14 +000035#include "sockopt.h"
paul718e3742002-12-13 20:15:29 +000036#include "routemap.h"
hasso16705132003-05-25 14:49:19 +000037#include "if_rmap.h"
paul718e3742002-12-13 20:15:29 +000038#include "plist.h"
39#include "distribute.h"
vincentc1a03d42005-09-28 15:47:44 +000040#include "md5.h"
paul718e3742002-12-13 20:15:29 +000041#include "keychain.h"
pauledd7c242003-06-04 13:59:38 +000042#include "privs.h"
paul718e3742002-12-13 20:15:29 +000043
44#include "ripd/ripd.h"
45#include "ripd/rip_debug.h"
46
paul0b3acf42004-09-17 08:39:08 +000047/* UDP receive buffer size */
48#define RIP_UDP_RCV_BUF 41600
49
50/* privileges global */
pauledd7c242003-06-04 13:59:38 +000051extern struct zebra_privs_t ripd_privs;
52
paul718e3742002-12-13 20:15:29 +000053/* RIP Structure. */
54struct rip *rip = NULL;
55
56/* RIP neighbor address table. */
57struct route_table *rip_neighbor_table;
58
59/* RIP route changes. */
60long rip_global_route_changes = 0;
61
62/* RIP queries. */
63long rip_global_queries = 0;
64
65/* Prototypes. */
pauldc63bfd2005-10-25 23:31:05 +000066static void rip_event (enum rip_event, int);
67static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char);
68static int rip_triggered_update (struct thread *);
69static int rip_update_jitter (unsigned long);
70
paul718e3742002-12-13 20:15:29 +000071/* RIP output routes type. */
72enum
73{
74 rip_all_route,
75 rip_changed_route
76};
77
78/* RIP command strings. */
79struct message rip_msg[] =
80{
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"},
paul718e3742002-12-13 20:15:29 +000087};
paul718e3742002-12-13 20:15:29 +000088
89/* Utility function to set boradcast option to the socket. */
pauldc63bfd2005-10-25 23:31:05 +000090static int
paul718e3742002-12-13 20:15:29 +000091sockopt_broadcast (int sock)
92{
93 int ret;
94 int on = 1;
95
96 ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
97 if (ret < 0)
98 {
99 zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
100 return -1;
101 }
102 return 0;
103}
104
pauldc63bfd2005-10-25 23:31:05 +0000105static int
paul718e3742002-12-13 20:15:29 +0000106rip_route_rte (struct rip_info *rinfo)
107{
108 return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE);
109}
110
pauldc63bfd2005-10-25 23:31:05 +0000111static struct rip_info *
paul718e3742002-12-13 20:15:29 +0000112rip_info_new ()
113{
114 struct rip_info *new;
115
116 new = XMALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
117 memset (new, 0, sizeof (struct rip_info));
118 return new;
119}
120
121void
122rip_info_free (struct rip_info *rinfo)
123{
124 XFREE (MTYPE_RIP_INFO, rinfo);
125}
126
127/* RIP route garbage collect timer. */
pauldc63bfd2005-10-25 23:31:05 +0000128static int
paul718e3742002-12-13 20:15:29 +0000129rip_garbage_collect (struct thread *t)
130{
131 struct rip_info *rinfo;
132 struct route_node *rp;
133
134 rinfo = THREAD_ARG (t);
135 rinfo->t_garbage_collect = NULL;
136
137 /* Off timeout timer. */
138 RIP_TIMER_OFF (rinfo->t_timeout);
139
140 /* Get route_node pointer. */
141 rp = rinfo->rp;
142
143 /* Unlock route_node. */
144 rp->info = NULL;
145 route_unlock_node (rp);
146
147 /* Free RIP routing information. */
148 rip_info_free (rinfo);
149
150 return 0;
151}
152
153/* Timeout RIP routes. */
pauldc63bfd2005-10-25 23:31:05 +0000154static int
paul718e3742002-12-13 20:15:29 +0000155rip_timeout (struct thread *t)
156{
157 struct rip_info *rinfo;
158 struct route_node *rn;
159
160 rinfo = THREAD_ARG (t);
161 rinfo->t_timeout = NULL;
162
163 rn = rinfo->rp;
164
165 /* - The garbage-collection timer is set for 120 seconds. */
166 RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
167 rip->garbage_time);
168
169 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
170 rinfo->metric);
171 /* - The metric for the route is set to 16 (infinity). This causes
172 the route to be removed from service. */
173 rinfo->metric = RIP_METRIC_INFINITY;
174 rinfo->flags &= ~RIP_RTF_FIB;
175
176 /* - The route change flag is to indicate that this entry has been
177 changed. */
178 rinfo->flags |= RIP_RTF_CHANGED;
179
180 /* - The output process is signalled to trigger a response. */
181 rip_event (RIP_TRIGGERED_UPDATE, 0);
182
183 return 0;
184}
185
pauldc63bfd2005-10-25 23:31:05 +0000186static void
paul718e3742002-12-13 20:15:29 +0000187rip_timeout_update (struct rip_info *rinfo)
188{
189 if (rinfo->metric != RIP_METRIC_INFINITY)
190 {
191 RIP_TIMER_OFF (rinfo->t_timeout);
192 RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
193 }
194}
195
pauldc63bfd2005-10-25 23:31:05 +0000196static int
paul718e3742002-12-13 20:15:29 +0000197rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
198{
199 struct distribute *dist;
200 struct access_list *alist;
201 struct prefix_list *plist;
202
203 /* Input distribute-list filtering. */
204 if (ri->list[RIP_FILTER_IN])
205 {
206 if (access_list_apply (ri->list[RIP_FILTER_IN],
207 (struct prefix *) p) == FILTER_DENY)
208 {
209 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000210 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000211 inet_ntoa (p->prefix), p->prefixlen);
212 return -1;
213 }
214 }
215 if (ri->prefix[RIP_FILTER_IN])
216 {
217 if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
218 (struct prefix *) p) == PREFIX_DENY)
219 {
220 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000221 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000222 inet_ntoa (p->prefix), p->prefixlen);
223 return -1;
224 }
225 }
226
227 /* All interface filter check. */
228 dist = distribute_lookup (NULL);
229 if (dist)
230 {
231 if (dist->list[DISTRIBUTE_IN])
232 {
233 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
234
235 if (alist)
236 {
237 if (access_list_apply (alist,
238 (struct prefix *) p) == FILTER_DENY)
239 {
240 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000241 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000242 inet_ntoa (p->prefix), p->prefixlen);
243 return -1;
244 }
245 }
246 }
247 if (dist->prefix[DISTRIBUTE_IN])
248 {
249 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
250
251 if (plist)
252 {
253 if (prefix_list_apply (plist,
254 (struct prefix *) p) == PREFIX_DENY)
255 {
256 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000257 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000258 inet_ntoa (p->prefix), p->prefixlen);
259 return -1;
260 }
261 }
262 }
263 }
264 return 0;
265}
266
pauldc63bfd2005-10-25 23:31:05 +0000267static int
paul718e3742002-12-13 20:15:29 +0000268rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
269{
270 struct distribute *dist;
271 struct access_list *alist;
272 struct prefix_list *plist;
273
274 if (ri->list[RIP_FILTER_OUT])
275 {
276 if (access_list_apply (ri->list[RIP_FILTER_OUT],
277 (struct prefix *) p) == FILTER_DENY)
278 {
279 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000280 zlog_debug ("%s/%d is filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000281 inet_ntoa (p->prefix), p->prefixlen);
282 return -1;
283 }
284 }
285 if (ri->prefix[RIP_FILTER_OUT])
286 {
287 if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
288 (struct prefix *) p) == PREFIX_DENY)
289 {
290 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000291 zlog_debug ("%s/%d is filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000292 inet_ntoa (p->prefix), p->prefixlen);
293 return -1;
294 }
295 }
296
297 /* All interface filter check. */
298 dist = distribute_lookup (NULL);
299 if (dist)
300 {
301 if (dist->list[DISTRIBUTE_OUT])
302 {
303 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
304
305 if (alist)
306 {
307 if (access_list_apply (alist,
308 (struct prefix *) p) == FILTER_DENY)
309 {
310 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000311 zlog_debug ("%s/%d filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000312 inet_ntoa (p->prefix), p->prefixlen);
313 return -1;
314 }
315 }
316 }
317 if (dist->prefix[DISTRIBUTE_OUT])
318 {
319 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
320
321 if (plist)
322 {
323 if (prefix_list_apply (plist,
324 (struct prefix *) p) == PREFIX_DENY)
325 {
326 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000327 zlog_debug ("%s/%d filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000328 inet_ntoa (p->prefix), p->prefixlen);
329 return -1;
330 }
331 }
332 }
333 }
334 return 0;
335}
336
337/* Check nexthop address validity. */
338static int
339rip_nexthop_check (struct in_addr *addr)
340{
hasso52dc7ee2004-09-23 19:18:23 +0000341 struct listnode *node;
342 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000343 struct interface *ifp;
344 struct connected *ifc;
345 struct prefix *p;
346
347 /* If nexthop address matches local configured address then it is
348 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000349 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000350 {
paul1eb8ef22005-04-07 07:30:20 +0000351 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000352 {
paul718e3742002-12-13 20:15:29 +0000353 p = ifc->address;
354
355 if (p->family == AF_INET
356 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
357 return -1;
358 }
359 }
360 return 0;
361}
362
363/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000364static void
paul718e3742002-12-13 20:15:29 +0000365rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000366 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000367{
368 int ret;
369 struct prefix_ipv4 p;
370 struct route_node *rp;
paulb94f9db2004-05-01 20:45:38 +0000371 struct rip_info *rinfo, rinfotmp;
paul718e3742002-12-13 20:15:29 +0000372 struct rip_interface *ri;
373 struct in_addr *nexthop;
374 u_char oldmetric;
375 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000376 int route_reuse = 0;
377 unsigned char old_dist, new_dist;
paul718e3742002-12-13 20:15:29 +0000378
379 /* Make prefix structure. */
380 memset (&p, 0, sizeof (struct prefix_ipv4));
381 p.family = AF_INET;
382 p.prefix = rte->prefix;
383 p.prefixlen = ip_masklen (rte->mask);
384
385 /* Make sure mask is applied. */
386 apply_mask_ipv4 (&p);
387
388 /* Apply input filters. */
389 ri = ifp->info;
390
391 ret = rip_incoming_filter (&p, ri);
392 if (ret < 0)
393 return;
394
hasso16705132003-05-25 14:49:19 +0000395 /* Modify entry according to the interface routemap. */
396 if (ri->routemap[RIP_FILTER_IN])
397 {
398 int ret;
399 struct rip_info newinfo;
400
401 memset (&newinfo, 0, sizeof (newinfo));
402 newinfo.type = ZEBRA_ROUTE_RIP;
403 newinfo.sub_type = RIP_ROUTE_RTE;
paula87552c2004-05-03 20:00:17 +0000404 newinfo.nexthop = rte->nexthop;
405 newinfo.from = from->sin_addr;
406 newinfo.ifindex = ifp->ifindex;
hasso16705132003-05-25 14:49:19 +0000407 newinfo.metric = rte->metric;
408 newinfo.metric_out = rte->metric; /* XXX */
paula87552c2004-05-03 20:00:17 +0000409 newinfo.tag = ntohs (rte->tag); /* XXX */
hasso16705132003-05-25 14:49:19 +0000410
411 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000412 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
413 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000414
415 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000416 {
417 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000418 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000419 inet_ntoa (p.prefix), p.prefixlen);
420 return;
421 }
hasso16705132003-05-25 14:49:19 +0000422
423 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000424 rte->nexthop = newinfo.nexthop_out;
425 rte->tag = htons (newinfo.tag_out); /* XXX */
426 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000427 }
428
paul718e3742002-12-13 20:15:29 +0000429 /* Once the entry has been validated, update the metric by
430 adding the cost of the network on wich the message
431 arrived. If the result is greater than infinity, use infinity
432 (RFC2453 Sec. 3.9.2) */
433 /* Zebra ripd can handle offset-list in. */
434 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
435
436 /* If offset-list does not modify the metric use interface's
437 metric. */
paula87552c2004-05-03 20:00:17 +0000438 if (!ret)
paul718e3742002-12-13 20:15:29 +0000439 rte->metric += ifp->metric;
440
441 if (rte->metric > RIP_METRIC_INFINITY)
442 rte->metric = RIP_METRIC_INFINITY;
443
444 /* Set nexthop pointer. */
445 if (rte->nexthop.s_addr == 0)
446 nexthop = &from->sin_addr;
447 else
448 nexthop = &rte->nexthop;
449
hasso16705132003-05-25 14:49:19 +0000450 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000451 if (rip_nexthop_check (nexthop) < 0)
452 {
453 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000454 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000455 return;
456 }
457
458 /* Get index for the prefix. */
459 rp = route_node_get (rip->table, (struct prefix *) &p);
460
461 /* Check to see whether there is already RIP route on the table. */
462 rinfo = rp->info;
463
464 if (rinfo)
465 {
paul718e3742002-12-13 20:15:29 +0000466 /* Local static route. */
467 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000468 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
469 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
470 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000471 {
472 route_unlock_node (rp);
473 return;
474 }
475
476 /* Redistributed route check. */
477 if (rinfo->type != ZEBRA_ROUTE_RIP
478 && rinfo->metric != RIP_METRIC_INFINITY)
479 {
480 /* Fill in a minimaly temporary rip_info structure, for a future
481 rip_distance_apply() use) */
482 memset (&rinfotmp, 0, sizeof (rinfotmp));
483 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
484 rinfotmp.rp = rinfo->rp;
485 new_dist = rip_distance_apply (&rinfotmp);
486 new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
487 old_dist = rinfo->distance;
vincent7a383332006-01-30 18:12:42 +0000488 /* Only connected routes may have a valid NULL distance */
489 if (rinfo->type != ZEBRA_ROUTE_CONNECT)
490 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000491 /* If imported route does not have STRICT precedence,
492 mark it as a ghost */
493 if (new_dist > old_dist
494 || rte->metric == RIP_METRIC_INFINITY)
495 {
496 route_unlock_node (rp);
497 return;
498 }
499 else
500 {
501 RIP_TIMER_OFF (rinfo->t_timeout);
502 RIP_TIMER_OFF (rinfo->t_garbage_collect);
503
504 rp->info = NULL;
505 if (rip_route_rte (rinfo))
506 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
507 &rinfo->nexthop, rinfo->metric);
508 rip_info_free (rinfo);
509 rinfo = NULL;
510 route_reuse = 1;
511 }
512 }
paul718e3742002-12-13 20:15:29 +0000513 }
paula87552c2004-05-03 20:00:17 +0000514
515 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000516 {
517 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000518 for the destination prefix. If there is no such route, add
519 this route to the routing table, unless the metric is
520 infinity (there is no point in adding a route which
521 unusable). */
paul718e3742002-12-13 20:15:29 +0000522 if (rte->metric != RIP_METRIC_INFINITY)
paula87552c2004-05-03 20:00:17 +0000523 {
524 rinfo = rip_info_new ();
paul718e3742002-12-13 20:15:29 +0000525
paula87552c2004-05-03 20:00:17 +0000526 /* - Setting the destination prefix and length to those in
527 the RTE. */
528 rinfo->rp = rp;
paul718e3742002-12-13 20:15:29 +0000529
paula87552c2004-05-03 20:00:17 +0000530 /* - Setting the metric to the newly calculated metric (as
531 described above). */
532 rinfo->metric = rte->metric;
533 rinfo->tag = ntohs (rte->tag);
paul718e3742002-12-13 20:15:29 +0000534
paula87552c2004-05-03 20:00:17 +0000535 /* - Set the next hop address to be the address of the router
536 from which the datagram came or the next hop address
537 specified by a next hop RTE. */
538 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
539 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
540 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000541
paula87552c2004-05-03 20:00:17 +0000542 /* - Initialize the timeout for the route. If the
543 garbage-collection timer is running for this route, stop it
544 (see section 2.3 for a discussion of the timers). */
545 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000546
paula87552c2004-05-03 20:00:17 +0000547 /* - Set the route change flag. */
548 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +0000549
paula87552c2004-05-03 20:00:17 +0000550 /* - Signal the output process to trigger an update (see section
551 2.5). */
552 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000553
paula87552c2004-05-03 20:00:17 +0000554 /* Finally, route goes into the kernel. */
555 rinfo->type = ZEBRA_ROUTE_RIP;
556 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000557
paula87552c2004-05-03 20:00:17 +0000558 /* Set distance value. */
559 rinfo->distance = rip_distance_apply (rinfo);
560
561 rp->info = rinfo;
562 rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
563 rinfo->distance);
564 rinfo->flags |= RIP_RTF_FIB;
565 }
vincentfbf5d032005-09-29 11:25:50 +0000566
567 /* Unlock temporary lock, i.e. same behaviour */
568 if (route_reuse)
569 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +0000570 }
571 else
572 {
573 /* Route is there but we are not sure the route is RIP or not. */
574 rinfo = rp->info;
paula87552c2004-05-03 20:00:17 +0000575
paul718e3742002-12-13 20:15:29 +0000576 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000577 to the address of the router from which the datagram came.
578 If this datagram is from the same router as the existing
579 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000580 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000581 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000582
583 if (same)
paula87552c2004-05-03 20:00:17 +0000584 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000585
paulb94f9db2004-05-01 20:45:38 +0000586
587 /* Fill in a minimaly temporary rip_info structure, for a future
588 rip_distance_apply() use) */
paula87552c2004-05-03 20:00:17 +0000589 memset (&rinfotmp, 0, sizeof (rinfotmp));
paulb94f9db2004-05-01 20:45:38 +0000590 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
paula87552c2004-05-03 20:00:17 +0000591 rinfotmp.rp = rinfo->rp;
paulb94f9db2004-05-01 20:45:38 +0000592
593
paul718e3742002-12-13 20:15:29 +0000594 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000595 router as the existing route, and the new metric is different
596 than the old one; or, if the new metric is lower than the old
597 one, or if the tag has been changed; or if there is a route
598 with a lower administrave distance; or an update of the
599 distance on the actual route; do the following actions: */
600 if ((same && rinfo->metric != rte->metric)
601 || (rte->metric < rinfo->metric)
602 || ((same)
603 && (rinfo->metric == rte->metric)
604 && ntohs (rte->tag) != rinfo->tag)
605 || (rinfo->distance > rip_distance_apply (&rinfotmp))
606 || ((rinfo->distance != rip_distance_apply (rinfo)) && same))
607 {
608 /* - Adopt the route from the datagram. That is, put the
609 new metric in, and adjust the next hop address (if
610 necessary). */
611 oldmetric = rinfo->metric;
612 rinfo->metric = rte->metric;
613 rinfo->tag = ntohs (rte->tag);
614 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
615 rinfo->ifindex = ifp->ifindex;
616 rinfo->distance = rip_distance_apply (rinfo);
paul718e3742002-12-13 20:15:29 +0000617
paula87552c2004-05-03 20:00:17 +0000618 /* Should a new route to this network be established
619 while the garbage-collection timer is running, the
620 new route will replace the one that is about to be
621 deleted. In this case the garbage-collection timer
622 must be cleared. */
paul718e3742002-12-13 20:15:29 +0000623
paula87552c2004-05-03 20:00:17 +0000624 if (oldmetric == RIP_METRIC_INFINITY &&
625 rinfo->metric < RIP_METRIC_INFINITY)
626 {
627 rinfo->type = ZEBRA_ROUTE_RIP;
628 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000629
paula87552c2004-05-03 20:00:17 +0000630 RIP_TIMER_OFF (rinfo->t_garbage_collect);
paul718e3742002-12-13 20:15:29 +0000631
paula87552c2004-05-03 20:00:17 +0000632 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
633 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000634
paula87552c2004-05-03 20:00:17 +0000635 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
636 rinfo->distance);
637 rinfo->flags |= RIP_RTF_FIB;
638 }
paul718e3742002-12-13 20:15:29 +0000639
paula87552c2004-05-03 20:00:17 +0000640 /* Update nexthop and/or metric value. */
641 if (oldmetric != RIP_METRIC_INFINITY)
642 {
643 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
644 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
645 rinfo->distance);
646 rinfo->flags |= RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000647
paula87552c2004-05-03 20:00:17 +0000648 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
649 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
650 }
paul718e3742002-12-13 20:15:29 +0000651
paula87552c2004-05-03 20:00:17 +0000652 /* - Set the route change flag and signal the output process
653 to trigger an update. */
654 rinfo->flags |= RIP_RTF_CHANGED;
655 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000656
paula87552c2004-05-03 20:00:17 +0000657 /* - If the new metric is infinity, start the deletion
658 process (described above); */
659 if (rinfo->metric == RIP_METRIC_INFINITY)
660 {
661 /* If the new metric is infinity, the deletion process
662 begins for the route, which is no longer used for
663 routing packets. Note that the deletion process is
664 started only when the metric is first set to
665 infinity. If the metric was already infinity, then a
666 new deletion process is not started. */
667 if (oldmetric != RIP_METRIC_INFINITY)
668 {
669 /* - The garbage-collection timer is set for 120 seconds. */
670 RIP_TIMER_ON (rinfo->t_garbage_collect,
671 rip_garbage_collect, rip->garbage_time);
672 RIP_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +0000673
paula87552c2004-05-03 20:00:17 +0000674 /* - The metric for the route is set to 16
675 (infinity). This causes the route to be removed
676 from service. */
677 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
678 rinfo->flags &= ~RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000679
paula87552c2004-05-03 20:00:17 +0000680 /* - The route change flag is to indicate that this
681 entry has been changed. */
682 /* - The output process is signalled to trigger a
paul718e3742002-12-13 20:15:29 +0000683 response. */
paula87552c2004-05-03 20:00:17 +0000684 ; /* Above processes are already done previously. */
685 }
686 }
687 else
688 {
689 /* otherwise, re-initialize the timeout. */
690 rip_timeout_update (rinfo);
691 }
692 }
paul718e3742002-12-13 20:15:29 +0000693 /* Unlock tempolary lock of the route. */
694 route_unlock_node (rp);
695 }
696}
697
698/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000699static void
hasso8a676be2004-10-08 06:36:38 +0000700rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000701{
702 caddr_t lim;
703 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000704 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000705 char pbuf[BUFSIZ], nbuf[BUFSIZ];
706 u_char netmask = 0;
707 u_char *p;
708
709 /* Set command string. */
710 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
711 command_str = lookup (rip_msg, packet->command);
712 else
713 command_str = "unknown";
714
715 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000716 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000717 sndrcv, command_str, packet->version, size);
718
719 /* Dump each routing table entry. */
720 rte = packet->rte;
721
722 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
723 {
724 if (packet->version == RIPv2)
725 {
726 netmask = ip_masklen (rte->mask);
727
paulca5e5162004-06-06 22:06:33 +0000728 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000729 {
paulca5e5162004-06-06 22:06:33 +0000730 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000731 {
732 p = (u_char *)&rte->prefix;
733
ajs5d6c3772004-12-08 19:24:06 +0000734 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000735 ntohs (rte->family), ntohs (rte->tag), p);
736 }
paulca5e5162004-06-06 22:06:33 +0000737 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000738 {
739 struct rip_md5_info *md5;
740
741 md5 = (struct rip_md5_info *) &packet->rte;
742
ajs5d6c3772004-12-08 19:24:06 +0000743 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000744 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000745 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000746 " Auth Data len %d",
747 ntohs (md5->packet_len), md5->keyid,
748 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000749 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000750 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000751 }
paulca5e5162004-06-06 22:06:33 +0000752 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000753 {
754 p = (u_char *)&rte->prefix;
755
ajs5d6c3772004-12-08 19:24:06 +0000756 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000757 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000758 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000759 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000760 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
761 p[7], p[9], p[10], p[11], p[12], p[13],
762 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000763 }
764 else
765 {
ajs5d6c3772004-12-08 19:24:06 +0000766 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000767 ntohs (rte->family), ntohs (rte->tag));
768 }
769 }
770 else
ajs5d6c3772004-12-08 19:24:06 +0000771 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000772 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
773 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
774 BUFSIZ), ntohs (rte->family),
775 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000776 }
777 else
778 {
ajs5d6c3772004-12-08 19:24:06 +0000779 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000780 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
781 ntohs (rte->family), ntohs (rte->tag),
782 (u_long)ntohl (rte->metric));
783 }
784 }
785}
786
787/* Check if the destination address is valid (unicast; not net 0
788 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
789 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000790static int
paul718e3742002-12-13 20:15:29 +0000791rip_destination_check (struct in_addr addr)
792{
793 u_int32_t destination;
794
795 /* Convert to host byte order. */
796 destination = ntohl (addr.s_addr);
797
798 if (IPV4_NET127 (destination))
799 return 0;
800
801 /* Net 0 may match to the default route. */
802 if (IPV4_NET0 (destination) && destination != 0)
803 return 0;
804
805 /* Unicast address must belong to class A, B, C. */
806 if (IN_CLASSA (destination))
807 return 1;
808 if (IN_CLASSB (destination))
809 return 1;
810 if (IN_CLASSC (destination))
811 return 1;
812
813 return 0;
814}
815
816/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000817static int
paul718e3742002-12-13 20:15:29 +0000818rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
819 struct interface *ifp)
820{
821 struct rip_interface *ri;
822 char *auth_str;
823
824 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000825 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000826 inet_ntoa (from->sin_addr));
827
828 ri = ifp->info;
829
830 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000831 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000832 return 0;
833
834 /* Simple password authentication. */
835 if (ri->auth_str)
836 {
837 auth_str = (char *) &rte->prefix;
838
839 if (strncmp (auth_str, ri->auth_str, 16) == 0)
840 return 1;
841 }
842 if (ri->key_chain)
843 {
844 struct keychain *keychain;
845 struct key *key;
846
847 keychain = keychain_lookup (ri->key_chain);
848 if (keychain == NULL)
849 return 0;
850
851 key = key_match_for_accept (keychain, (char *) &rte->prefix);
852 if (key)
853 return 1;
854 }
855 return 0;
856}
857
858/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000859static int
paul718e3742002-12-13 20:15:29 +0000860rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000861 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000862{
863 struct rip_interface *ri;
864 struct rip_md5_info *md5;
865 struct rip_md5_data *md5data;
866 struct keychain *keychain;
867 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000868 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000869 u_char digest[RIP_AUTH_MD5_SIZE];
870 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000871 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000872
873 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000874 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000875 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000876
877 ri = ifp->info;
878 md5 = (struct rip_md5_info *) &packet->rte;
879
880 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000881 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000882 return 0;
883
paulca5e5162004-06-06 22:06:33 +0000884 /* If the authentication length is less than 16, then it must be wrong for
885 * any interpretation of rfc2082. Some implementations also interpret
886 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000887 */
paulca5e5162004-06-06 22:06:33 +0000888 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
889 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000890 {
891 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000892 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000893 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000894 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000895 }
paul718e3742002-12-13 20:15:29 +0000896
paulca5e5162004-06-06 22:06:33 +0000897 /* grab and verify check packet length */
898 packet_len = ntohs (md5->packet_len);
899
900 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
901 {
902 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000903 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000904 "greater than received length %d!",
905 md5->packet_len, length);
906 return 0;
907 }
908
909 /* retrieve authentication data */
910 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000911
912 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000913
paul718e3742002-12-13 20:15:29 +0000914 if (ri->key_chain)
915 {
916 keychain = keychain_lookup (ri->key_chain);
917 if (keychain == NULL)
918 return 0;
919
920 key = key_lookup_for_accept (keychain, md5->keyid);
921 if (key == NULL)
922 return 0;
923
paul98fd1e62006-01-17 17:26:25 +0000924 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000925 }
paul98fd1e62006-01-17 17:26:25 +0000926 else if (ri->auth_str)
927 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000928
Paul Jakmafa93b162008-05-29 19:03:08 +0000929 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000930 return 0;
paul98fd1e62006-01-17 17:26:25 +0000931
paul718e3742002-12-13 20:15:29 +0000932 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000933 memset (&ctx, 0, sizeof(ctx));
934 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000935 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
936 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000937 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000938
939 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000940 return packet_len;
941 else
942 return 0;
943}
944
paulb14ee002005-02-04 23:42:41 +0000945/* Pick correct auth string for sends, prepare auth_str buffer for use.
946 * (left justified and padded).
947 *
948 * presumes one of ri or key is valid, and that the auth strings they point
949 * to are nul terminated. If neither are present, auth_str will be fully
950 * zero padded.
951 *
952 */
953static void
954rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
955 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +0000956{
paulb14ee002005-02-04 23:42:41 +0000957 assert (ri || key);
paul718e3742002-12-13 20:15:29 +0000958
paulb14ee002005-02-04 23:42:41 +0000959 memset (auth_str, 0, len);
960 if (key && key->string)
961 strncpy (auth_str, key->string, len);
962 else if (ri->auth_str)
963 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +0000964
paulb14ee002005-02-04 23:42:41 +0000965 return;
966}
paul718e3742002-12-13 20:15:29 +0000967
paulb14ee002005-02-04 23:42:41 +0000968/* Write RIPv2 simple password authentication information
969 *
970 * auth_str is presumed to be 2 bytes and correctly prepared
971 * (left justified and zero padded).
972 */
973static void
974rip_auth_simple_write (struct stream *s, char *auth_str, int len)
975{
976 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +0000977
paulb14ee002005-02-04 23:42:41 +0000978 stream_putw (s, RIP_FAMILY_AUTH);
979 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
980 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
981
982 return;
983}
984
985/* write RIPv2 MD5 "authentication header"
986 * (uses the auth key data field)
987 *
988 * Digest offset field is set to 0.
989 *
990 * returns: offset of the digest offset field, which must be set when
991 * length to the auth-data MD5 digest is known.
992 */
993static size_t
994rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
995 struct key *key)
996{
paul98fd1e62006-01-17 17:26:25 +0000997 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +0000998
999 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +00001000
1001 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +00001002 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +00001003 stream_putw (s, RIP_AUTH_MD5);
1004
paulb14ee002005-02-04 23:42:41 +00001005 /* MD5 AH digest offset field.
1006 *
1007 * Set to placeholder value here, to true value when RIP-2 Packet length
1008 * is known. Actual value is set in .....().
1009 */
paul98fd1e62006-01-17 17:26:25 +00001010 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001011 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001012
1013 /* Key ID. */
1014 if (key)
1015 stream_putc (s, key->index % 256);
1016 else
1017 stream_putc (s, 1);
1018
paulca5e5162004-06-06 22:06:33 +00001019 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1020 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1021 * to be configurable.
1022 */
1023 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001024
1025 /* Sequence Number (non-decreasing). */
1026 /* RFC2080: The value used in the sequence number is
1027 arbitrary, but two suggestions are the time of the
1028 message's creation or a simple message counter. */
1029 stream_putl (s, time (NULL));
1030
1031 /* Reserved field must be zero. */
1032 stream_putl (s, 0);
1033 stream_putl (s, 0);
1034
paul98fd1e62006-01-17 17:26:25 +00001035 return doff;
paulb14ee002005-02-04 23:42:41 +00001036}
paul718e3742002-12-13 20:15:29 +00001037
paulb14ee002005-02-04 23:42:41 +00001038/* If authentication is in used, write the appropriate header
1039 * returns stream offset to which length must later be written
1040 * or 0 if this is not required
1041 */
1042static size_t
1043rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1044 struct key *key, char *auth_str, int len)
1045{
1046 assert (ri->auth_type != RIP_NO_AUTH);
1047
1048 switch (ri->auth_type)
1049 {
1050 case RIP_AUTH_SIMPLE_PASSWORD:
1051 rip_auth_prepare_str_send (ri, key, auth_str, len);
1052 rip_auth_simple_write (s, auth_str, len);
1053 return 0;
1054 case RIP_AUTH_MD5:
1055 return rip_auth_md5_ah_write (s, ri, key);
1056 }
1057 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001058 return 0;
paulb14ee002005-02-04 23:42:41 +00001059}
1060
1061/* Write RIPv2 MD5 authentication data trailer */
1062static void
1063rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1064 char *auth_str, int authlen)
1065{
1066 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001067 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001068 unsigned char digest[RIP_AUTH_MD5_SIZE];
1069
1070 /* Make it sure this interface is configured as MD5
1071 authentication. */
1072 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1073 assert (doff > 0);
1074
1075 /* Get packet length. */
1076 len = stream_get_endp(s);
1077
1078 /* Check packet length. */
1079 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1080 {
1081 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1082 return;
1083 }
1084
1085 /* Set the digest offset length in the header */
1086 stream_putw_at (s, doff, len);
1087
paul718e3742002-12-13 20:15:29 +00001088 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001089 stream_putw (s, RIP_FAMILY_AUTH);
1090 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001091
1092 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001093 memset(&ctx, 0, sizeof(ctx));
1094 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001095 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001096 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1097 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001098
1099 /* Copy the digest to the packet. */
1100 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1101}
1102
1103/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001104static void
paul718e3742002-12-13 20:15:29 +00001105rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001106 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001107{
1108 caddr_t lim;
1109 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001110 struct prefix_ipv4 ifaddr;
1111 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001112 int subnetted;
paul718e3742002-12-13 20:15:29 +00001113
paul727d1042002-12-13 20:50:29 +00001114 /* We don't know yet. */
1115 subnetted = -1;
1116
paul718e3742002-12-13 20:15:29 +00001117 /* The Response must be ignored if it is not from the RIP
1118 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001119 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001120 {
1121 zlog_info ("response doesn't come from RIP port: %d",
1122 from->sin_port);
1123 rip_peer_bad_packet (from);
1124 return;
1125 }
1126
1127 /* The datagram's IPv4 source address should be checked to see
1128 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001129 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1130 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001131 {
1132 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1133 inet_ntoa (from->sin_addr));
1134 rip_peer_bad_packet (from);
1135 return;
1136 }
1137
1138 /* It is also worth checking to see whether the response is from one
1139 of the router's own addresses. */
1140
1141 ; /* Alredy done in rip_read () */
1142
1143 /* Update RIP peer. */
1144 rip_peer_update (from, packet->version);
1145
1146 /* Set RTE pointer. */
1147 rte = packet->rte;
1148
1149 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1150 {
1151 /* RIPv2 authentication check. */
1152 /* If the Address Family Identifier of the first (and only the
1153 first) entry in the message is 0xFFFF, then the remainder of
1154 the entry contains the authentication. */
1155 /* If the packet gets here it means authentication enabled */
1156 /* Check is done in rip_read(). So, just skipping it */
1157 if (packet->version == RIPv2 &&
1158 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001159 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001160 continue;
1161
paulca5e5162004-06-06 22:06:33 +00001162 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001163 {
1164 /* Address family check. RIP only supports AF_INET. */
1165 zlog_info ("Unsupported family %d from %s.",
1166 ntohs (rte->family), inet_ntoa (from->sin_addr));
1167 continue;
1168 }
1169
1170 /* - is the destination address valid (e.g., unicast; not net 0
1171 or 127) */
1172 if (! rip_destination_check (rte->prefix))
1173 {
1174 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1175 rip_peer_bad_route (from);
1176 continue;
1177 }
1178
1179 /* Convert metric value to host byte order. */
1180 rte->metric = ntohl (rte->metric);
1181
1182 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1183 if (! (rte->metric >= 1 && rte->metric <= 16))
1184 {
1185 zlog_info ("Route's metric is not in the 1-16 range.");
1186 rip_peer_bad_route (from);
1187 continue;
1188 }
1189
1190 /* RIPv1 does not have nexthop value. */
1191 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1192 {
1193 zlog_info ("RIPv1 packet with nexthop value %s",
1194 inet_ntoa (rte->nexthop));
1195 rip_peer_bad_route (from);
1196 continue;
1197 }
1198
1199 /* That is, if the provided information is ignored, a possibly
1200 sub-optimal, but absolutely valid, route may be taken. If
1201 the received Next Hop is not directly reachable, it should be
1202 treated as 0.0.0.0. */
1203 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1204 {
1205 u_int32_t addrval;
1206
1207 /* Multicast address check. */
1208 addrval = ntohl (rte->nexthop.s_addr);
1209 if (IN_CLASSD (addrval))
1210 {
1211 zlog_info ("Nexthop %s is multicast address, skip this rte",
1212 inet_ntoa (rte->nexthop));
1213 continue;
1214 }
1215
1216 if (! if_lookup_address (rte->nexthop))
1217 {
1218 struct route_node *rn;
1219 struct rip_info *rinfo;
1220
1221 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1222
1223 if (rn)
1224 {
1225 rinfo = rn->info;
1226
1227 if (rinfo->type == ZEBRA_ROUTE_RIP
1228 && rinfo->sub_type == RIP_ROUTE_RTE)
1229 {
1230 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001231 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 +00001232 rte->nexthop = rinfo->from;
1233 }
1234 else
1235 {
1236 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001237 zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
paul718e3742002-12-13 20:15:29 +00001238 rte->nexthop.s_addr = 0;
1239 }
1240
1241 route_unlock_node (rn);
1242 }
1243 else
1244 {
1245 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001246 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 +00001247 rte->nexthop.s_addr = 0;
1248 }
1249
1250 }
1251 }
1252
1253 /* For RIPv1, there won't be a valid netmask.
1254
1255 This is a best guess at the masks. If everyone was using old
1256 Ciscos before the 'ip subnet zero' option, it would be almost
1257 right too :-)
1258
1259 Cisco summarize ripv1 advertisments to the classful boundary
1260 (/16 for class B's) except when the RIP packet does to inside
1261 the classful network in question. */
1262
1263 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1264 || (packet->version == RIPv2
1265 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1266 {
1267 u_int32_t destination;
1268
paul727d1042002-12-13 20:50:29 +00001269 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001270 {
1271 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1272 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1273 apply_classful_mask_ipv4 (&ifaddrclass);
1274 subnetted = 0;
1275 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1276 subnetted = 1;
1277 }
paul727d1042002-12-13 20:50:29 +00001278
paul718e3742002-12-13 20:15:29 +00001279 destination = ntohl (rte->prefix.s_addr);
1280
paul727d1042002-12-13 20:50:29 +00001281 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001282 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001283 else if (IN_CLASSB (destination))
1284 masklen2ip (16, &rte->mask);
1285 else if (IN_CLASSC (destination))
1286 masklen2ip (24, &rte->mask);
1287
1288 if (subnetted == 1)
1289 masklen2ip (ifaddrclass.prefixlen,
1290 (struct in_addr *) &destination);
1291 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1292 ifaddrclass.prefix.s_addr))
1293 {
1294 masklen2ip (ifaddr.prefixlen, &rte->mask);
1295 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1296 masklen2ip (32, &rte->mask);
1297 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001298 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001299 }
1300 else
1301 {
1302 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1303 continue;
1304 }
1305
1306 if (IS_RIP_DEBUG_EVENT)
1307 {
ajs5d6c3772004-12-08 19:24:06 +00001308 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1309 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001310 }
1311 }
1312
1313 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1314 ignore the entry. */
1315 if ((packet->version == RIPv2)
1316 && (rte->mask.s_addr != 0)
1317 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1318 {
1319 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1320 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1321 rip_peer_bad_route (from);
1322 continue;
1323 }
1324
1325 /* Default route's netmask is ignored. */
1326 if (packet->version == RIPv2
1327 && (rte->prefix.s_addr == 0)
1328 && (rte->mask.s_addr != 0))
1329 {
1330 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001331 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001332 rte->mask.s_addr = 0;
1333 }
1334
1335 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001336 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001337 }
1338}
1339
paula4e987e2005-06-03 17:46:49 +00001340/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001341static int
paul2c61ae32005-08-16 15:22:14 +00001342rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001343{
1344 int ret;
1345 int sock;
1346 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001347
paul2c61ae32005-08-16 15:22:14 +00001348 memset (&addr, 0, sizeof (struct sockaddr_in));
1349
1350 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001351 {
paulf69bd9d2005-06-03 18:01:50 +00001352 addr.sin_family = AF_INET;
1353 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001354#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001355 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001356#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001357 } else {
1358 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001359 }
1360
paul2c61ae32005-08-16 15:22:14 +00001361 /* sending port must always be the RIP port */
1362 addr.sin_port = htons (RIP_PORT_DEFAULT);
1363
paula4e987e2005-06-03 17:46:49 +00001364 /* Make datagram socket. */
1365 sock = socket (AF_INET, SOCK_DGRAM, 0);
1366 if (sock < 0)
1367 {
1368 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1369 exit (1);
1370 }
1371
1372 sockopt_broadcast (sock);
1373 sockopt_reuseaddr (sock);
1374 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001375#ifdef RIP_RECVMSG
1376 setsockopt_pktinfo (sock);
1377#endif /* RIP_RECVMSG */
1378
1379 if (ripd_privs.change (ZPRIVS_RAISE))
1380 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001381 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1382 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1383
paula4e987e2005-06-03 17:46:49 +00001384 {
1385 int save_errno = errno;
1386 if (ripd_privs.change (ZPRIVS_LOWER))
1387 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001388
1389 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1390 sock, inet_ntoa(addr.sin_addr),
1391 (int) ntohs(addr.sin_port),
1392 safe_strerror(save_errno));
1393
paulf69bd9d2005-06-03 18:01:50 +00001394 close (sock);
paula4e987e2005-06-03 17:46:49 +00001395 return ret;
1396 }
paulf69bd9d2005-06-03 18:01:50 +00001397
paula4e987e2005-06-03 17:46:49 +00001398 if (ripd_privs.change (ZPRIVS_LOWER))
1399 zlog_err ("rip_create_socket: could not lower privs");
1400
1401 return sock;
1402}
1403
paulc49ad8f2004-10-22 10:27:28 +00001404/* RIP packet send to destination address, on interface denoted by
1405 * by connected argument. NULL to argument denotes destination should be
1406 * should be RIP multicast group
1407 */
pauldc63bfd2005-10-25 23:31:05 +00001408static int
paulc49ad8f2004-10-22 10:27:28 +00001409rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1410 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001411{
paul931cd542004-01-23 15:31:42 +00001412 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001413 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001414
1415 assert (ifc != NULL);
1416
paul931cd542004-01-23 15:31:42 +00001417 if (IS_RIP_DEBUG_PACKET)
1418 {
paulf69bd9d2005-06-03 18:01:50 +00001419#define ADDRESS_SIZE 20
1420 char dst[ADDRESS_SIZE];
1421 dst[ADDRESS_SIZE - 1] = '\0';
1422
paul931cd542004-01-23 15:31:42 +00001423 if (to)
1424 {
paulf69bd9d2005-06-03 18:01:50 +00001425 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001426 }
1427 else
1428 {
1429 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001430 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001431 }
paulf69bd9d2005-06-03 18:01:50 +00001432#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001433 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001434 inet_ntoa(ifc->address->u.prefix4),
1435 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001436 }
paulf69bd9d2005-06-03 18:01:50 +00001437
paulc49ad8f2004-10-22 10:27:28 +00001438 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001439 {
1440 /*
1441 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1442 * with multiple addresses on the same subnet: the first address
1443 * on the subnet is configured "primary", and all subsequent addresses
1444 * on that subnet are treated as "secondary" addresses.
1445 * In order to avoid routing-table bloat on other rip listeners,
1446 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1447 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1448 * flag is set, we would end up sending a packet for a "secondary"
1449 * source address on non-linux systems.
1450 */
1451 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001452 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001453 return 0;
1454 }
1455
paul718e3742002-12-13 20:15:29 +00001456 /* Make destination address. */
1457 memset (&sin, 0, sizeof (struct sockaddr_in));
1458 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001459#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001460 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001461#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001462
1463 /* When destination is specified, use it's port and address. */
1464 if (to)
1465 {
paul718e3742002-12-13 20:15:29 +00001466 sin.sin_port = to->sin_port;
1467 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001468 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001469 }
1470 else
1471 {
paul2c61ae32005-08-16 15:22:14 +00001472 struct sockaddr_in from;
1473
paul718e3742002-12-13 20:15:29 +00001474 sin.sin_port = htons (RIP_PORT_DEFAULT);
1475 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001476
1477 /* multicast send should bind to local interface address */
1478 from.sin_family = AF_INET;
1479 from.sin_port = htons (RIP_PORT_DEFAULT);
1480 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001481#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001482 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001483#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001484
paul931cd542004-01-23 15:31:42 +00001485 /*
1486 * we have to open a new socket for each packet because this
1487 * is the most portable way to bind to a different source
1488 * ipv4 address for each packet.
1489 */
paul2c61ae32005-08-16 15:22:14 +00001490 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001491 {
paulf69bd9d2005-06-03 18:01:50 +00001492 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001493 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001494 }
paulc49ad8f2004-10-22 10:27:28 +00001495 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001496 }
1497
paul931cd542004-01-23 15:31:42 +00001498 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001499 sizeof (struct sockaddr_in));
1500
1501 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001502 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001503 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001504
1505 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001506 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001507
paul931cd542004-01-23 15:31:42 +00001508 if (!to)
1509 close(send_sock);
1510
paul718e3742002-12-13 20:15:29 +00001511 return ret;
1512}
1513
1514/* Add redistributed route to RIP table. */
1515void
1516rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001517 unsigned int ifindex, struct in_addr *nexthop,
1518 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001519{
1520 int ret;
1521 struct route_node *rp;
1522 struct rip_info *rinfo;
1523
1524 /* Redistribute route */
1525 ret = rip_destination_check (p->prefix);
1526 if (! ret)
1527 return;
1528
1529 rp = route_node_get (rip->table, (struct prefix *) p);
1530
1531 rinfo = rp->info;
1532
1533 if (rinfo)
1534 {
1535 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1536 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1537 && rinfo->metric != RIP_METRIC_INFINITY)
1538 {
1539 route_unlock_node (rp);
1540 return;
1541 }
1542
1543 /* Manually configured RIP route check. */
1544 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001545 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1546 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001547 {
hasso16705132003-05-25 14:49:19 +00001548 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1549 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001550 {
1551 route_unlock_node (rp);
1552 return;
1553 }
1554 }
1555
1556 RIP_TIMER_OFF (rinfo->t_timeout);
1557 RIP_TIMER_OFF (rinfo->t_garbage_collect);
1558
1559 if (rip_route_rte (rinfo))
1560 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
1561 rinfo->metric);
1562 rp->info = NULL;
1563 rip_info_free (rinfo);
1564
1565 route_unlock_node (rp);
1566 }
1567
1568 rinfo = rip_info_new ();
1569
1570 rinfo->type = type;
1571 rinfo->sub_type = sub_type;
1572 rinfo->ifindex = ifindex;
1573 rinfo->metric = 1;
vincentfbf5d032005-09-29 11:25:50 +00001574 rinfo->external_metric = metric;
1575 rinfo->distance = distance;
paul718e3742002-12-13 20:15:29 +00001576 rinfo->rp = rp;
1577
1578 if (nexthop)
1579 rinfo->nexthop = *nexthop;
1580
1581 rinfo->flags |= RIP_RTF_FIB;
1582 rp->info = rinfo;
1583
1584 rinfo->flags |= RIP_RTF_CHANGED;
1585
hasso16705132003-05-25 14:49:19 +00001586 if (IS_RIP_DEBUG_EVENT) {
1587 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001588 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001589 inet_ntoa(p->prefix), p->prefixlen,
1590 ifindex2ifname(ifindex));
1591 else
ajs5d6c3772004-12-08 19:24:06 +00001592 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001593 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1594 ifindex2ifname(ifindex));
1595 }
1596
1597
paul718e3742002-12-13 20:15:29 +00001598 rip_event (RIP_TRIGGERED_UPDATE, 0);
1599}
1600
1601/* Delete redistributed route from RIP table. */
1602void
1603rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1604 unsigned int ifindex)
1605{
1606 int ret;
1607 struct route_node *rp;
1608 struct rip_info *rinfo;
1609
1610 ret = rip_destination_check (p->prefix);
1611 if (! ret)
1612 return;
1613
1614 rp = route_node_lookup (rip->table, (struct prefix *) p);
1615 if (rp)
1616 {
1617 rinfo = rp->info;
1618
1619 if (rinfo != NULL
1620 && rinfo->type == type
1621 && rinfo->sub_type == sub_type
1622 && rinfo->ifindex == ifindex)
1623 {
1624 /* Perform poisoned reverse. */
1625 rinfo->metric = RIP_METRIC_INFINITY;
1626 RIP_TIMER_ON (rinfo->t_garbage_collect,
1627 rip_garbage_collect, rip->garbage_time);
1628 RIP_TIMER_OFF (rinfo->t_timeout);
1629 rinfo->flags |= RIP_RTF_CHANGED;
1630
hasso16705132003-05-25 14:49:19 +00001631 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001632 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso16705132003-05-25 14:49:19 +00001633 inet_ntoa(p->prefix), p->prefixlen,
1634 ifindex2ifname(ifindex));
1635
paul718e3742002-12-13 20:15:29 +00001636 rip_event (RIP_TRIGGERED_UPDATE, 0);
1637 }
1638 }
1639}
1640
1641/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001642static void
paul718e3742002-12-13 20:15:29 +00001643rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001644 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001645{
1646 caddr_t lim;
1647 struct rte *rte;
1648 struct prefix_ipv4 p;
1649 struct route_node *rp;
1650 struct rip_info *rinfo;
1651 struct rip_interface *ri;
1652
hasso16705132003-05-25 14:49:19 +00001653 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001654 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001655 return;
1656
hasso429a0f82004-02-22 23:42:22 +00001657 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001658 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001659 if (! ri->running)
1660 return;
paul718e3742002-12-13 20:15:29 +00001661
1662 /* When passive interface is specified, suppress responses */
1663 if (ri->passive)
1664 return;
paulc49ad8f2004-10-22 10:27:28 +00001665
paul718e3742002-12-13 20:15:29 +00001666 /* RIP peer update. */
1667 rip_peer_update (from, packet->version);
1668
1669 lim = ((caddr_t) packet) + size;
1670 rte = packet->rte;
1671
1672 /* The Request is processed entry by entry. If there are no
1673 entries, no response is given. */
1674 if (lim == (caddr_t) rte)
1675 return;
1676
1677 /* There is one special case. If there is exactly one entry in the
1678 request, and it has an address family identifier of zero and a
1679 metric of infinity (i.e., 16), then this is a request to send the
1680 entire routing table. */
1681 if (lim == ((caddr_t) (rte + 1)) &&
1682 ntohs (rte->family) == 0 &&
1683 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1684 {
paulcc1131a2003-10-15 23:20:17 +00001685 struct prefix_ipv4 saddr;
1686
1687 /* saddr will be used for determining which routes to split-horizon.
1688 Since the source address we'll pick will be on the same subnet as the
1689 destination, for the purpose of split-horizoning, we'll
1690 pretend that "from" is our source address. */
1691 saddr.family = AF_INET;
1692 saddr.prefixlen = IPV4_MAX_BITLEN;
1693 saddr.prefix = from->sin_addr;
1694
paul718e3742002-12-13 20:15:29 +00001695 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001696 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001697 }
1698 else
1699 {
1700 /* Examine the list of RTEs in the Request one by one. For each
1701 entry, look up the destination in the router's routing
1702 database and, if there is a route, put that route's metric in
1703 the metric field of the RTE. If there is no explicit route
1704 to the specified destination, put infinity in the metric
1705 field. Once all the entries have been filled in, change the
1706 command from Request to Response and send the datagram back
1707 to the requestor. */
1708 p.family = AF_INET;
1709
1710 for (; ((caddr_t) rte) < lim; rte++)
1711 {
1712 p.prefix = rte->prefix;
1713 p.prefixlen = ip_masklen (rte->mask);
1714 apply_mask_ipv4 (&p);
1715
1716 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1717 if (rp)
1718 {
1719 rinfo = rp->info;
1720 rte->metric = htonl (rinfo->metric);
1721 route_unlock_node (rp);
1722 }
1723 else
1724 rte->metric = htonl (RIP_METRIC_INFINITY);
1725 }
1726 packet->command = RIP_RESPONSE;
1727
paulc49ad8f2004-10-22 10:27:28 +00001728 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001729 }
1730 rip_global_queries++;
1731}
1732
1733#if RIP_RECVMSG
1734/* Set IPv6 packet info to the socket. */
1735static int
1736setsockopt_pktinfo (int sock)
1737{
1738 int ret;
1739 int val = 1;
1740
1741 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1742 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001743 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001744 return ret;
1745}
1746
1747/* Read RIP packet by recvmsg function. */
1748int
1749rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1750 int *ifindex)
1751{
1752 int ret;
1753 struct msghdr msg;
1754 struct iovec iov;
1755 struct cmsghdr *ptr;
1756 char adata[1024];
1757
1758 msg.msg_name = (void *) from;
1759 msg.msg_namelen = sizeof (struct sockaddr_in);
1760 msg.msg_iov = &iov;
1761 msg.msg_iovlen = 1;
1762 msg.msg_control = (void *) adata;
1763 msg.msg_controllen = sizeof adata;
1764 iov.iov_base = buf;
1765 iov.iov_len = size;
1766
1767 ret = recvmsg (sock, &msg, 0);
1768 if (ret < 0)
1769 return ret;
1770
ajsb99760a2005-01-04 16:24:43 +00001771 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001772 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1773 {
1774 struct in_pktinfo *pktinfo;
1775 int i;
1776
1777 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1778 i = pktinfo->ipi_ifindex;
1779 }
1780 return ret;
1781}
1782
1783/* RIP packet read function. */
1784int
1785rip_read_new (struct thread *t)
1786{
1787 int ret;
1788 int sock;
1789 char buf[RIP_PACKET_MAXSIZ];
1790 struct sockaddr_in from;
1791 unsigned int ifindex;
1792
1793 /* Fetch socket then register myself. */
1794 sock = THREAD_FD (t);
1795 rip_event (RIP_READ, sock);
1796
1797 /* Read RIP packet. */
1798 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1799 if (ret < 0)
1800 {
ajs6099b3b2004-11-20 02:06:59 +00001801 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001802 return ret;
1803 }
1804
1805 return ret;
1806}
1807#endif /* RIP_RECVMSG */
1808
1809/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001810static int
paul718e3742002-12-13 20:15:29 +00001811rip_read (struct thread *t)
1812{
1813 int sock;
1814 int ret;
1815 int rtenum;
1816 union rip_buf rip_buf;
1817 struct rip_packet *packet;
1818 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001819 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001820 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001821 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001822 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001823 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001824 struct rip_interface *ri;
1825
1826 /* Fetch socket then register myself. */
1827 sock = THREAD_FD (t);
1828 rip->t_read = NULL;
1829
1830 /* Add myself to tne next event */
1831 rip_event (RIP_READ, sock);
1832
1833 /* RIPd manages only IPv4. */
1834 memset (&from, 0, sizeof (struct sockaddr_in));
1835 fromlen = sizeof (struct sockaddr_in);
1836
1837 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1838 (struct sockaddr *) &from, &fromlen);
1839 if (len < 0)
1840 {
ajs6099b3b2004-11-20 02:06:59 +00001841 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001842 return len;
1843 }
1844
1845 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001846 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001847 {
1848 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001849 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001850 return -1;
1851 }
1852
1853 /* Which interface is this packet comes from. */
1854 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001855
paul718e3742002-12-13 20:15:29 +00001856 /* RIP packet received */
1857 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001858 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001859 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1860 ifp ? ifp->name : "unknown");
1861
1862 /* If this packet come from unknown interface, ignore it. */
1863 if (ifp == NULL)
1864 {
ajs766a0ca2004-12-15 14:55:51 +00001865 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1866 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001867 return -1;
1868 }
1869
1870 ifc = connected_lookup_address (ifp, from.sin_addr);
1871
1872 if (ifc == NULL)
1873 {
ajs766a0ca2004-12-15 14:55:51 +00001874 zlog_info ("rip_read: cannot find connected address for packet from %s "
1875 "port %d on interface %s",
1876 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001877 return -1;
1878 }
1879
1880 /* Packet length check. */
1881 if (len < RIP_PACKET_MINSIZ)
1882 {
1883 zlog_warn ("packet size %d is smaller than minimum size %d",
1884 len, RIP_PACKET_MINSIZ);
1885 rip_peer_bad_packet (&from);
1886 return len;
1887 }
1888 if (len > RIP_PACKET_MAXSIZ)
1889 {
1890 zlog_warn ("packet size %d is larger than max size %d",
1891 len, RIP_PACKET_MAXSIZ);
1892 rip_peer_bad_packet (&from);
1893 return len;
1894 }
1895
1896 /* Packet alignment check. */
1897 if ((len - RIP_PACKET_MINSIZ) % 20)
1898 {
1899 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1900 rip_peer_bad_packet (&from);
1901 return len;
1902 }
1903
1904 /* Set RTE number. */
1905 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1906
1907 /* For easy to handle. */
1908 packet = &rip_buf.rip_packet;
1909
1910 /* RIP version check. */
1911 if (packet->version == 0)
1912 {
1913 zlog_info ("version 0 with command %d received.", packet->command);
1914 rip_peer_bad_packet (&from);
1915 return -1;
1916 }
1917
1918 /* Dump RIP packet. */
1919 if (IS_RIP_DEBUG_RECV)
1920 rip_packet_dump (packet, len, "RECV");
1921
1922 /* RIP version adjust. This code should rethink now. RFC1058 says
1923 that "Version 1 implementations are to ignore this extra data and
1924 process only the fields specified in this document.". So RIPv3
1925 packet should be treated as RIPv1 ignoring must be zero field. */
1926 if (packet->version > RIPv2)
1927 packet->version = RIPv2;
1928
1929 /* Is RIP running or is this RIP neighbor ?*/
1930 ri = ifp->info;
1931 if (! ri->running && ! rip_neighbor_lookup (&from))
1932 {
1933 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001934 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001935 rip_peer_bad_packet (&from);
1936 return -1;
1937 }
1938
Paul Jakma15a2b082006-05-04 07:36:34 +00001939 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001940 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1941 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001942 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001943 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001944 if (IS_RIP_DEBUG_PACKET)
1945 zlog_debug (" packet's v%d doesn't fit to if version spec",
1946 packet->version);
1947 rip_peer_bad_packet (&from);
1948 return -1;
paul718e3742002-12-13 20:15:29 +00001949 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001950 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1951 {
1952 if (IS_RIP_DEBUG_PACKET)
1953 zlog_debug (" packet's v%d doesn't fit to if version spec",
1954 packet->version);
1955 rip_peer_bad_packet (&from);
1956 return -1;
1957 }
1958
paul718e3742002-12-13 20:15:29 +00001959 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1960 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1961 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001962 if ((ri->auth_type == RIP_NO_AUTH)
1963 && rtenum
paulca5e5162004-06-06 22:06:33 +00001964 && (packet->version == RIPv2)
1965 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001966 {
1967 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001968 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001969 packet->version);
1970 rip_peer_bad_packet (&from);
1971 return -1;
1972 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001973
1974 /* RFC:
1975 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001976 RIP-1 messages and RIP-2 messages which pass authentication
1977 testing shall be accepted; unauthenticated and failed
1978 authentication RIP-2 messages shall be discarded. For maximum
1979 security, RIP-1 messages should be ignored when authentication is
1980 in use (see section 4.1); otherwise, the routing information from
1981 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001982 unauthenticated manner.
1983 */
1984 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1985 * always reply regardless of authentication settings, because:
1986 *
1987 * - if there other authorised routers on-link, the REQUESTor can
1988 * passively obtain the routing updates anyway
1989 * - if there are no other authorised routers on-link, RIP can
1990 * easily be disabled for the link to prevent giving out information
1991 * on state of this routers RIP routing table..
1992 *
1993 * I.e. if RIPv1 has any place anymore these days, it's as a very
1994 * simple way to distribute routing information (e.g. to embedded
1995 * hosts / appliances) and the ability to give out RIPv1
1996 * routing-information freely, while still requiring RIPv2
1997 * authentication for any RESPONSEs might be vaguely useful.
1998 */
1999 if (ri->auth_type != RIP_NO_AUTH
2000 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002001 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002002 /* Discard RIPv1 messages other than REQUESTs */
2003 if (packet->command != RIP_REQUEST)
2004 {
2005 if (IS_RIP_DEBUG_PACKET)
2006 zlog_debug ("RIPv1" " dropped because authentication enabled");
2007 rip_peer_bad_packet (&from);
2008 return -1;
2009 }
2010 }
2011 else if (ri->auth_type != RIP_NO_AUTH)
2012 {
2013 const char *auth_desc;
2014
2015 if (rtenum == 0)
2016 {
2017 /* There definitely is no authentication in the packet. */
2018 if (IS_RIP_DEBUG_PACKET)
2019 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2020 rip_peer_bad_packet (&from);
2021 return -1;
2022 }
2023
2024 /* First RTE must be an Authentication Family RTE */
2025 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2026 {
2027 if (IS_RIP_DEBUG_PACKET)
2028 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002029 rip_peer_bad_packet (&from);
2030 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002031 }
2032
paul718e3742002-12-13 20:15:29 +00002033 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002034 switch (ntohs(packet->rte->tag))
2035 {
2036 case RIP_AUTH_SIMPLE_PASSWORD:
2037 auth_desc = "simple";
2038 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2039 break;
2040
2041 case RIP_AUTH_MD5:
2042 auth_desc = "MD5";
2043 ret = rip_auth_md5 (packet, &from, len, ifp);
2044 /* Reset RIP packet length to trim MD5 data. */
2045 len = ret;
2046 break;
2047
2048 default:
2049 ret = 0;
2050 auth_desc = "unknown type";
2051 if (IS_RIP_DEBUG_PACKET)
2052 zlog_debug ("RIPv2 Unknown authentication type %d",
2053 ntohs (packet->rte->tag));
2054 }
2055
2056 if (ret)
2057 {
2058 if (IS_RIP_DEBUG_PACKET)
2059 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2060 }
2061 else
2062 {
2063 if (IS_RIP_DEBUG_PACKET)
2064 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2065 rip_peer_bad_packet (&from);
2066 return -1;
2067 }
paul718e3742002-12-13 20:15:29 +00002068 }
2069
2070 /* Process each command. */
2071 switch (packet->command)
2072 {
2073 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002074 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002075 break;
2076 case RIP_REQUEST:
2077 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002078 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002079 break;
2080 case RIP_TRACEON:
2081 case RIP_TRACEOFF:
2082 zlog_info ("Obsolete command %s received, please sent it to routed",
2083 lookup (rip_msg, packet->command));
2084 rip_peer_bad_packet (&from);
2085 break;
2086 case RIP_POLL_ENTRY:
2087 zlog_info ("Obsolete command %s received",
2088 lookup (rip_msg, packet->command));
2089 rip_peer_bad_packet (&from);
2090 break;
2091 default:
2092 zlog_info ("Unknown RIP command %d received", packet->command);
2093 rip_peer_bad_packet (&from);
2094 break;
2095 }
2096
2097 return len;
2098}
2099
paul718e3742002-12-13 20:15:29 +00002100/* Write routing table entry to the stream and return next index of
2101 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002102static int
paul718e3742002-12-13 20:15:29 +00002103rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002104 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002105{
2106 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002107
2108 /* Write routing table entry. */
2109 if (version == RIPv1)
2110 {
2111 stream_putw (s, AF_INET);
2112 stream_putw (s, 0);
2113 stream_put_ipv4 (s, p->prefix.s_addr);
2114 stream_put_ipv4 (s, 0);
2115 stream_put_ipv4 (s, 0);
2116 stream_putl (s, rinfo->metric_out);
2117 }
2118 else
2119 {
2120 masklen2ip (p->prefixlen, &mask);
2121
2122 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002123 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002124 stream_put_ipv4 (s, p->prefix.s_addr);
2125 stream_put_ipv4 (s, mask.s_addr);
2126 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2127 stream_putl (s, rinfo->metric_out);
2128 }
2129
2130 return ++num;
2131}
2132
2133/* Send update to the ifp or spcified neighbor. */
2134void
paulc49ad8f2004-10-22 10:27:28 +00002135rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2136 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002137{
2138 int ret;
2139 struct stream *s;
2140 struct route_node *rp;
2141 struct rip_info *rinfo;
2142 struct rip_interface *ri;
2143 struct prefix_ipv4 *p;
2144 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002145 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002146 struct key *key = NULL;
2147 /* this might need to made dynamic if RIP ever supported auth methods
2148 with larger key string sizes */
2149 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002150 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002151 int num = 0;
paul718e3742002-12-13 20:15:29 +00002152 int rtemax;
paul01d09082003-06-08 21:22:18 +00002153 int subnetted = 0;
paul718e3742002-12-13 20:15:29 +00002154
2155 /* Logging output event. */
2156 if (IS_RIP_DEBUG_EVENT)
2157 {
2158 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002159 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002160 else
ajs5d6c3772004-12-08 19:24:06 +00002161 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002162 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002163 }
2164
2165 /* Set output stream. */
2166 s = rip->obuf;
2167
2168 /* Reset stream and RTE counter. */
2169 stream_reset (s);
paul718e3742002-12-13 20:15:29 +00002170 rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
2171
2172 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002173 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002174
2175 /* If output interface is in simple password authentication mode, we
2176 need space for authentication data. */
2177 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2178 rtemax -= 1;
2179
2180 /* If output interface is in MD5 authentication mode, we need space
2181 for authentication header and data. */
2182 if (ri->auth_type == RIP_AUTH_MD5)
2183 rtemax -= 2;
2184
2185 /* If output interface is in simple password authentication mode
2186 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002187 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002188 {
2189 if (ri->key_chain)
2190 {
2191 struct keychain *keychain;
2192
2193 keychain = keychain_lookup (ri->key_chain);
2194 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002195 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002196 }
paulb14ee002005-02-04 23:42:41 +00002197 /* to be passed to auth functions later */
2198 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002199 }
2200
paul727d1042002-12-13 20:50:29 +00002201 if (version == RIPv1)
2202 {
paulc49ad8f2004-10-22 10:27:28 +00002203 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002204 apply_classful_mask_ipv4 (&ifaddrclass);
2205 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002206 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002207 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002208 }
2209
paul718e3742002-12-13 20:15:29 +00002210 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2211 if ((rinfo = rp->info) != NULL)
2212 {
paul727d1042002-12-13 20:50:29 +00002213 /* For RIPv1, if we are subnetted, output subnets in our network */
2214 /* that have the same mask as the output "interface". For other */
2215 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002216
2217 if (version == RIPv1)
2218 {
paul727d1042002-12-13 20:50:29 +00002219 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002220
2221 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002222 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002223 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002224
paul727d1042002-12-13 20:50:29 +00002225 if (subnetted &&
2226 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2227 {
paulc49ad8f2004-10-22 10:27:28 +00002228 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002229 (rp->p.prefixlen != 32))
2230 continue;
2231 }
2232 else
2233 {
2234 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2235 apply_classful_mask_ipv4(&classfull);
2236 if (rp->p.u.prefix4.s_addr != 0 &&
2237 classfull.prefixlen != rp->p.prefixlen)
2238 continue;
2239 }
paul718e3742002-12-13 20:15:29 +00002240 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002241 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002242 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002243 }
2244 else
2245 p = (struct prefix_ipv4 *) &rp->p;
2246
2247 /* Apply output filters. */
2248 ret = rip_outgoing_filter (p, ri);
2249 if (ret < 0)
2250 continue;
2251
2252 /* Changed route only output. */
2253 if (route_type == rip_changed_route &&
2254 (! (rinfo->flags & RIP_RTF_CHANGED)))
2255 continue;
2256
2257 /* Split horizon. */
2258 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002259 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002260 {
paul42d14d92003-11-17 09:15:18 +00002261 /*
2262 * We perform split horizon for RIP and connected route.
2263 * For rip routes, we want to suppress the route if we would
2264 * end up sending the route back on the interface that we
2265 * learned it from, with a higher metric. For connected routes,
2266 * we suppress the route if the prefix is a subset of the
2267 * source address that we are going to use for the packet
2268 * (in order to handle the case when multiple subnets are
2269 * configured on the same interface).
2270 */
2271 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002272 rinfo->ifindex == ifc->ifp->ifindex)
paul42d14d92003-11-17 09:15:18 +00002273 continue;
2274 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002275 prefix_match((struct prefix *)p, ifc->address))
paul718e3742002-12-13 20:15:29 +00002276 continue;
2277 }
2278
2279 /* Preparation for route-map. */
2280 rinfo->metric_set = 0;
2281 rinfo->nexthop_out.s_addr = 0;
2282 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002283 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002284 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002285
hasso16705132003-05-25 14:49:19 +00002286 /* In order to avoid some local loops,
2287 * if the RIP route has a nexthop via this interface, keep the nexthop,
2288 * otherwise set it to 0. The nexthop should not be propagated
2289 * beyond the local broadcast/multicast area in order
2290 * to avoid an IGP multi-level recursive look-up.
2291 * see (4.4)
2292 */
paulc49ad8f2004-10-22 10:27:28 +00002293 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002294 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002295
2296 /* Interface route-map */
2297 if (ri->routemap[RIP_FILTER_OUT])
2298 {
2299 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2300 (struct prefix *) p, RMAP_RIP,
2301 rinfo);
2302
2303 if (ret == RMAP_DENYMATCH)
2304 {
2305 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002306 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002307 inet_ntoa (p->prefix), p->prefixlen);
2308 continue;
2309 }
2310 }
paul718e3742002-12-13 20:15:29 +00002311
hasso16705132003-05-25 14:49:19 +00002312 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002313 if (rip->route_map[rinfo->type].name
2314 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2315 {
2316 ret = route_map_apply (rip->route_map[rinfo->type].map,
2317 (struct prefix *)p, RMAP_RIP, rinfo);
2318
2319 if (ret == RMAP_DENYMATCH)
2320 {
2321 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002322 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002323 inet_ntoa (p->prefix), p->prefixlen);
2324 continue;
2325 }
2326 }
2327
2328 /* When route-map does not set metric. */
2329 if (! rinfo->metric_set)
2330 {
2331 /* If redistribute metric is set. */
2332 if (rip->route_map[rinfo->type].metric_config
2333 && rinfo->metric != RIP_METRIC_INFINITY)
2334 {
2335 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2336 }
2337 else
2338 {
2339 /* If the route is not connected or localy generated
2340 one, use default-metric value*/
2341 if (rinfo->type != ZEBRA_ROUTE_RIP
2342 && rinfo->type != ZEBRA_ROUTE_CONNECT
2343 && rinfo->metric != RIP_METRIC_INFINITY)
2344 rinfo->metric_out = rip->default_metric;
2345 }
2346 }
2347
2348 /* Apply offset-list */
2349 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002350 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002351
2352 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2353 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002354
2355 /* Perform split-horizon with poisoned reverse
2356 * for RIP and connected routes.
2357 **/
2358 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002359 /*
2360 * We perform split horizon for RIP and connected route.
2361 * For rip routes, we want to suppress the route if we would
2362 * end up sending the route back on the interface that we
2363 * learned it from, with a higher metric. For connected routes,
2364 * we suppress the route if the prefix is a subset of the
2365 * source address that we are going to use for the packet
2366 * (in order to handle the case when multiple subnets are
2367 * configured on the same interface).
2368 */
2369 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002370 rinfo->ifindex == ifc->ifp->ifindex)
hasso16705132003-05-25 14:49:19 +00002371 rinfo->metric_out = RIP_METRIC_INFINITY;
paul42d14d92003-11-17 09:15:18 +00002372 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002373 prefix_match((struct prefix *)p, ifc->address))
paul42d14d92003-11-17 09:15:18 +00002374 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002375 }
paulb14ee002005-02-04 23:42:41 +00002376
2377 /* Prepare preamble, auth headers, if needs be */
2378 if (num == 0)
2379 {
2380 stream_putc (s, RIP_RESPONSE);
2381 stream_putc (s, version);
2382 stream_putw (s, 0);
2383
paul0cb8a012005-05-29 11:27:24 +00002384 /* auth header for !v1 && !no_auth */
2385 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002386 doff = rip_auth_header_write (s, ri, key, auth_str,
2387 RIP_AUTH_SIMPLE_SIZE);
2388 }
2389
paul718e3742002-12-13 20:15:29 +00002390 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002391 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002392 if (num == rtemax)
2393 {
2394 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002395 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002396
2397 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002398 to, ifc);
paul718e3742002-12-13 20:15:29 +00002399
2400 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2401 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2402 stream_get_endp(s), "SEND");
2403 num = 0;
2404 stream_reset (s);
2405 }
2406 }
2407
2408 /* Flush unwritten RTE. */
2409 if (num != 0)
2410 {
2411 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002412 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002413
paulc49ad8f2004-10-22 10:27:28 +00002414 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002415
2416 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2417 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2418 stream_get_endp (s), "SEND");
2419 num = 0;
2420 stream_reset (s);
2421 }
2422
2423 /* Statistics updates. */
2424 ri->sent_updates++;
2425}
2426
2427/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002428static void
paulc49ad8f2004-10-22 10:27:28 +00002429rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002430{
paul718e3742002-12-13 20:15:29 +00002431 struct sockaddr_in to;
2432
2433 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002434 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002435 {
2436 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002437 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002438
paulc49ad8f2004-10-22 10:27:28 +00002439 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002440 return;
2441 }
paulc49ad8f2004-10-22 10:27:28 +00002442
paul718e3742002-12-13 20:15:29 +00002443 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002444 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002445 {
paulc49ad8f2004-10-22 10:27:28 +00002446 if (ifc->address->family == AF_INET)
2447 {
2448 /* Destination address and port setting. */
2449 memset (&to, 0, sizeof (struct sockaddr_in));
2450 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002451 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002452 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002453 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002454 /* calculate the appropriate broadcast address */
2455 to.sin_addr.s_addr =
2456 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2457 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002458 else
2459 /* do not know where to send the packet */
2460 return;
paulc49ad8f2004-10-22 10:27:28 +00002461 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002462
paulc49ad8f2004-10-22 10:27:28 +00002463 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002464 zlog_debug("%s announce to %s on %s",
2465 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2466 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002467
paulc49ad8f2004-10-22 10:27:28 +00002468 rip_output_process (ifc, &to, route_type, version);
2469 }
paul718e3742002-12-13 20:15:29 +00002470 }
2471}
2472
2473/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002474static void
paul718e3742002-12-13 20:15:29 +00002475rip_update_process (int route_type)
2476{
paul1eb8ef22005-04-07 07:30:20 +00002477 struct listnode *node;
2478 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002479 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002480 struct interface *ifp;
2481 struct rip_interface *ri;
2482 struct route_node *rp;
2483 struct sockaddr_in to;
2484 struct prefix_ipv4 *p;
2485
2486 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002487 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002488 {
paul718e3742002-12-13 20:15:29 +00002489 if (if_is_loopback (ifp))
2490 continue;
2491
paul2e3b2e42002-12-13 21:03:13 +00002492 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002493 continue;
2494
2495 /* Fetch RIP interface information. */
2496 ri = ifp->info;
2497
2498 /* When passive interface is specified, suppress announce to the
2499 interface. */
2500 if (ri->passive)
2501 continue;
2502
2503 if (ri->running)
2504 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002505 /*
2506 * If there is no version configuration in the interface,
2507 * use rip's version setting.
2508 */
2509 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2510 rip->version_send : ri->ri_send);
2511
paul718e3742002-12-13 20:15:29 +00002512 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002513 zlog_debug("SEND UPDATE to %s ifindex %d",
2514 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002515
paulcc1131a2003-10-15 23:20:17 +00002516 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002517 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002518 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002519 if (connected->address->family == AF_INET)
2520 {
2521 if (vsend & RIPv1)
2522 rip_update_interface (connected, RIPv1, route_type);
2523 if ((vsend & RIPv2) && if_is_multicast(ifp))
2524 rip_update_interface (connected, RIPv2, route_type);
2525 }
2526 }
paul718e3742002-12-13 20:15:29 +00002527 }
2528 }
2529
2530 /* RIP send updates to each neighbor. */
2531 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2532 if (rp->info != NULL)
2533 {
2534 p = (struct prefix_ipv4 *) &rp->p;
2535
2536 ifp = if_lookup_address (p->prefix);
2537 if (! ifp)
2538 {
paulc49ad8f2004-10-22 10:27:28 +00002539 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002540 inet_ntoa (p->prefix));
2541 continue;
2542 }
paulc49ad8f2004-10-22 10:27:28 +00002543
2544 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2545 {
2546 zlog_warn ("Neighbor %s doesnt have connected network",
2547 inet_ntoa (p->prefix));
2548 continue;
2549 }
2550
paul718e3742002-12-13 20:15:29 +00002551 /* Set destination address and port */
2552 memset (&to, 0, sizeof (struct sockaddr_in));
2553 to.sin_addr = p->prefix;
2554 to.sin_port = htons (RIP_PORT_DEFAULT);
2555
2556 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002557 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002558 }
2559}
2560
2561/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002562static int
paul718e3742002-12-13 20:15:29 +00002563rip_update (struct thread *t)
2564{
2565 /* Clear timer pointer. */
2566 rip->t_update = NULL;
2567
2568 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002569 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002570
2571 /* Process update output. */
2572 rip_update_process (rip_all_route);
2573
2574 /* Triggered updates may be suppressed if a regular update is due by
2575 the time the triggered update would be sent. */
2576 if (rip->t_triggered_interval)
2577 {
2578 thread_cancel (rip->t_triggered_interval);
2579 rip->t_triggered_interval = NULL;
2580 }
2581 rip->trigger = 0;
2582
2583 /* Register myself. */
2584 rip_event (RIP_UPDATE_EVENT, 0);
2585
2586 return 0;
2587}
2588
2589/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002590static void
paul216565a2005-10-25 23:35:28 +00002591rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002592{
2593 struct route_node *rp;
2594 struct rip_info *rinfo;
2595
2596 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2597 if ((rinfo = rp->info) != NULL)
2598 if (rinfo->flags & RIP_RTF_CHANGED)
2599 rinfo->flags &= ~RIP_RTF_CHANGED;
2600}
2601
2602/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002603static int
paul718e3742002-12-13 20:15:29 +00002604rip_triggered_interval (struct thread *t)
2605{
2606 int rip_triggered_update (struct thread *);
2607
2608 rip->t_triggered_interval = NULL;
2609
2610 if (rip->trigger)
2611 {
2612 rip->trigger = 0;
2613 rip_triggered_update (t);
2614 }
2615 return 0;
2616}
2617
2618/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002619static int
paul718e3742002-12-13 20:15:29 +00002620rip_triggered_update (struct thread *t)
2621{
2622 int interval;
2623
2624 /* Clear thred pointer. */
2625 rip->t_triggered_update = NULL;
2626
2627 /* Cancel interval timer. */
2628 if (rip->t_triggered_interval)
2629 {
2630 thread_cancel (rip->t_triggered_interval);
2631 rip->t_triggered_interval = NULL;
2632 }
2633 rip->trigger = 0;
2634
2635 /* Logging triggered update. */
2636 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002637 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002638
2639 /* Split Horizon processing is done when generating triggered
2640 updates as well as normal updates (see section 2.6). */
2641 rip_update_process (rip_changed_route);
2642
2643 /* Once all of the triggered updates have been generated, the route
2644 change flags should be cleared. */
2645 rip_clear_changed_flag ();
2646
2647 /* After a triggered update is sent, a timer should be set for a
2648 random interval between 1 and 5 seconds. If other changes that
2649 would trigger updates occur before the timer expires, a single
2650 update is triggered when the timer expires. */
2651 interval = (random () % 5) + 1;
2652
2653 rip->t_triggered_interval =
2654 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2655
2656 return 0;
2657}
2658
2659/* Withdraw redistributed route. */
2660void
2661rip_redistribute_withdraw (int type)
2662{
2663 struct route_node *rp;
2664 struct rip_info *rinfo;
2665
2666 if (!rip)
2667 return;
2668
2669 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2670 if ((rinfo = rp->info) != NULL)
2671 {
2672 if (rinfo->type == type
2673 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2674 {
2675 /* Perform poisoned reverse. */
2676 rinfo->metric = RIP_METRIC_INFINITY;
2677 RIP_TIMER_ON (rinfo->t_garbage_collect,
2678 rip_garbage_collect, rip->garbage_time);
2679 RIP_TIMER_OFF (rinfo->t_timeout);
2680 rinfo->flags |= RIP_RTF_CHANGED;
2681
hasso16705132003-05-25 14:49:19 +00002682 if (IS_RIP_DEBUG_EVENT) {
2683 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2684
ajs5d6c3772004-12-08 19:24:06 +00002685 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002686 inet_ntoa(p->prefix), p->prefixlen,
2687 ifindex2ifname(rinfo->ifindex));
2688 }
2689
paul718e3742002-12-13 20:15:29 +00002690 rip_event (RIP_TRIGGERED_UPDATE, 0);
2691 }
2692 }
2693}
2694
2695/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002696static int
2697rip_create (void)
paul718e3742002-12-13 20:15:29 +00002698{
2699 rip = XMALLOC (MTYPE_RIP, sizeof (struct rip));
2700 memset (rip, 0, sizeof (struct rip));
2701
2702 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002703 rip->version_send = RI_RIP_VERSION_2;
2704 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002705 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2706 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2707 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2708 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2709
2710 /* Initialize RIP routig table. */
2711 rip->table = route_table_init ();
2712 rip->route = route_table_init ();
2713 rip->neighbor = route_table_init ();
2714
2715 /* Make output stream. */
2716 rip->obuf = stream_new (1500);
2717
2718 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002719 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002720 if (rip->sock < 0)
2721 return rip->sock;
2722
2723 /* Create read and timer thread. */
2724 rip_event (RIP_READ, rip->sock);
2725 rip_event (RIP_UPDATE_EVENT, 1);
2726
2727 return 0;
2728}
2729
2730/* Sned RIP request to the destination. */
2731int
2732rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002733 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002734{
2735 struct rte *rte;
2736 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002737 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002738
2739 memset (&rip_packet, 0, sizeof (rip_packet));
2740
2741 rip_packet.command = RIP_REQUEST;
2742 rip_packet.version = version;
2743 rte = rip_packet.rte;
2744 rte->metric = htonl (RIP_METRIC_INFINITY);
2745
paul931cd542004-01-23 15:31:42 +00002746 if (connected)
2747 {
2748 /*
2749 * connected is only sent for ripv1 case, or when
2750 * interface does not support multicast. Caller loops
2751 * over each connected address for this case.
2752 */
paul11dde9c2004-05-31 14:00:00 +00002753 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002754 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002755 return -1;
2756 else
2757 return sizeof (rip_packet);
2758 }
2759
paulcc1131a2003-10-15 23:20:17 +00002760 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002761 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002762 {
2763 struct prefix_ipv4 *p;
2764
2765 p = (struct prefix_ipv4 *) connected->address;
2766
2767 if (p->family != AF_INET)
2768 continue;
2769
paul11dde9c2004-05-31 14:00:00 +00002770 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002771 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002772 return -1;
2773 }
2774 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002775}
2776
pauldc63bfd2005-10-25 23:31:05 +00002777static int
paul718e3742002-12-13 20:15:29 +00002778rip_update_jitter (unsigned long time)
2779{
paul239389b2004-05-05 14:09:37 +00002780#define JITTER_BOUND 4
2781 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2782 Given that, we cannot let time be less than JITTER_BOUND seconds.
2783 The RIPv2 RFC says jitter should be small compared to
2784 update_time. We consider 1/JITTER_BOUND to be small.
2785 */
2786
2787 int jitter_input = time;
2788 int jitter;
2789
2790 if (jitter_input < JITTER_BOUND)
2791 jitter_input = JITTER_BOUND;
2792
2793 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2794
2795 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002796}
2797
2798void
2799rip_event (enum rip_event event, int sock)
2800{
2801 int jitter = 0;
2802
2803 switch (event)
2804 {
2805 case RIP_READ:
2806 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2807 break;
2808 case RIP_UPDATE_EVENT:
2809 if (rip->t_update)
2810 {
2811 thread_cancel (rip->t_update);
2812 rip->t_update = NULL;
2813 }
2814 jitter = rip_update_jitter (rip->update_time);
2815 rip->t_update =
2816 thread_add_timer (master, rip_update, NULL,
2817 sock ? 2 : rip->update_time + jitter);
2818 break;
2819 case RIP_TRIGGERED_UPDATE:
2820 if (rip->t_triggered_interval)
2821 rip->trigger = 1;
2822 else if (! rip->t_triggered_update)
2823 rip->t_triggered_update =
2824 thread_add_event (master, rip_triggered_update, NULL, 0);
2825 break;
2826 default:
2827 break;
2828 }
2829}
2830
2831DEFUN (router_rip,
2832 router_rip_cmd,
2833 "router rip",
2834 "Enable a routing process\n"
2835 "Routing Information Protocol (RIP)\n")
2836{
2837 int ret;
2838
2839 /* If rip is not enabled before. */
2840 if (! rip)
2841 {
2842 ret = rip_create ();
2843 if (ret < 0)
2844 {
2845 zlog_info ("Can't create RIP");
2846 return CMD_WARNING;
2847 }
2848 }
2849 vty->node = RIP_NODE;
2850 vty->index = rip;
2851
2852 return CMD_SUCCESS;
2853}
2854
2855DEFUN (no_router_rip,
2856 no_router_rip_cmd,
2857 "no router rip",
2858 NO_STR
2859 "Enable a routing process\n"
2860 "Routing Information Protocol (RIP)\n")
2861{
2862 if (rip)
2863 rip_clean ();
2864 return CMD_SUCCESS;
2865}
2866
2867DEFUN (rip_version,
2868 rip_version_cmd,
2869 "version <1-2>",
2870 "Set routing protocol version\n"
2871 "version\n")
2872{
2873 int version;
2874
2875 version = atoi (argv[0]);
2876 if (version != RIPv1 && version != RIPv2)
2877 {
2878 vty_out (vty, "invalid rip version %d%s", version,
2879 VTY_NEWLINE);
2880 return CMD_WARNING;
2881 }
paulf38a4712003-06-07 01:10:00 +00002882 rip->version_send = version;
2883 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002884
2885 return CMD_SUCCESS;
2886}
2887
2888DEFUN (no_rip_version,
2889 no_rip_version_cmd,
2890 "no version",
2891 NO_STR
2892 "Set routing protocol version\n")
2893{
2894 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002895 rip->version_send = RI_RIP_VERSION_2;
2896 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002897
2898 return CMD_SUCCESS;
2899}
2900
2901ALIAS (no_rip_version,
2902 no_rip_version_val_cmd,
2903 "no version <1-2>",
2904 NO_STR
2905 "Set routing protocol version\n"
2906 "version\n")
2907
2908DEFUN (rip_route,
2909 rip_route_cmd,
2910 "route A.B.C.D/M",
2911 "RIP static route configuration\n"
2912 "IP prefix <network>/<length>\n")
2913{
2914 int ret;
2915 struct prefix_ipv4 p;
2916 struct route_node *node;
2917
2918 ret = str2prefix_ipv4 (argv[0], &p);
2919 if (ret < 0)
2920 {
2921 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2922 return CMD_WARNING;
2923 }
2924 apply_mask_ipv4 (&p);
2925
2926 /* For router rip configuration. */
2927 node = route_node_get (rip->route, (struct prefix *) &p);
2928
2929 if (node->info)
2930 {
2931 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2932 route_unlock_node (node);
2933 return CMD_WARNING;
2934 }
2935
hasso8a676be2004-10-08 06:36:38 +00002936 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002937
vincentfbf5d032005-09-29 11:25:50 +00002938 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002939
2940 return CMD_SUCCESS;
2941}
2942
2943DEFUN (no_rip_route,
2944 no_rip_route_cmd,
2945 "no route A.B.C.D/M",
2946 NO_STR
2947 "RIP static route configuration\n"
2948 "IP prefix <network>/<length>\n")
2949{
2950 int ret;
2951 struct prefix_ipv4 p;
2952 struct route_node *node;
2953
2954 ret = str2prefix_ipv4 (argv[0], &p);
2955 if (ret < 0)
2956 {
2957 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2958 return CMD_WARNING;
2959 }
2960 apply_mask_ipv4 (&p);
2961
2962 /* For router rip configuration. */
2963 node = route_node_lookup (rip->route, (struct prefix *) &p);
2964 if (! node)
2965 {
2966 vty_out (vty, "Can't find route %s.%s", argv[0],
2967 VTY_NEWLINE);
2968 return CMD_WARNING;
2969 }
2970
2971 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2972 route_unlock_node (node);
2973
2974 node->info = NULL;
2975 route_unlock_node (node);
2976
2977 return CMD_SUCCESS;
2978}
2979
pauldc63bfd2005-10-25 23:31:05 +00002980static void
paul216565a2005-10-25 23:35:28 +00002981rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002982{
2983 struct route_node *np;
2984 struct rip_info *rinfo;
2985
2986 for (np = route_top (rip->table); np; np = route_next (np))
2987 if ((rinfo = np->info) != NULL)
2988 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2989 rinfo->metric = rip->default_metric;
2990}
2991
2992DEFUN (rip_default_metric,
2993 rip_default_metric_cmd,
2994 "default-metric <1-16>",
2995 "Set a metric of redistribute routes\n"
2996 "Default metric\n")
2997{
2998 if (rip)
2999 {
3000 rip->default_metric = atoi (argv[0]);
3001 /* rip_update_default_metric (); */
3002 }
3003 return CMD_SUCCESS;
3004}
3005
3006DEFUN (no_rip_default_metric,
3007 no_rip_default_metric_cmd,
3008 "no default-metric",
3009 NO_STR
3010 "Set a metric of redistribute routes\n"
3011 "Default metric\n")
3012{
3013 if (rip)
3014 {
3015 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3016 /* rip_update_default_metric (); */
3017 }
3018 return CMD_SUCCESS;
3019}
3020
3021ALIAS (no_rip_default_metric,
3022 no_rip_default_metric_val_cmd,
3023 "no default-metric <1-16>",
3024 NO_STR
3025 "Set a metric of redistribute routes\n"
3026 "Default metric\n")
3027
3028DEFUN (rip_timers,
3029 rip_timers_cmd,
3030 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3031 "Adjust routing timers\n"
3032 "Basic routing protocol update timers\n"
3033 "Routing table update timer value in second. Default is 30.\n"
3034 "Routing information timeout timer. Default is 180.\n"
3035 "Garbage collection timer. Default is 120.\n")
3036{
3037 unsigned long update;
3038 unsigned long timeout;
3039 unsigned long garbage;
3040 char *endptr = NULL;
3041 unsigned long RIP_TIMER_MAX = 2147483647;
3042 unsigned long RIP_TIMER_MIN = 5;
3043
3044 update = strtoul (argv[0], &endptr, 10);
3045 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3046 {
3047 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3048 return CMD_WARNING;
3049 }
3050
3051 timeout = strtoul (argv[1], &endptr, 10);
3052 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3053 {
3054 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3055 return CMD_WARNING;
3056 }
3057
3058 garbage = strtoul (argv[2], &endptr, 10);
3059 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3060 {
3061 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3062 return CMD_WARNING;
3063 }
3064
3065 /* Set each timer value. */
3066 rip->update_time = update;
3067 rip->timeout_time = timeout;
3068 rip->garbage_time = garbage;
3069
3070 /* Reset update timer thread. */
3071 rip_event (RIP_UPDATE_EVENT, 0);
3072
3073 return CMD_SUCCESS;
3074}
3075
3076DEFUN (no_rip_timers,
3077 no_rip_timers_cmd,
3078 "no timers basic",
3079 NO_STR
3080 "Adjust routing timers\n"
3081 "Basic routing protocol update timers\n")
3082{
3083 /* Set each timer value to the default. */
3084 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3085 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3086 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3087
3088 /* Reset update timer thread. */
3089 rip_event (RIP_UPDATE_EVENT, 0);
3090
3091 return CMD_SUCCESS;
3092}
hasso16705132003-05-25 14:49:19 +00003093
3094ALIAS (no_rip_timers,
3095 no_rip_timers_val_cmd,
3096 "no timers basic <0-65535> <0-65535> <0-65535>",
3097 NO_STR
3098 "Adjust routing timers\n"
3099 "Basic routing protocol update timers\n"
3100 "Routing table update timer value in second. Default is 30.\n"
3101 "Routing information timeout timer. Default is 180.\n"
3102 "Garbage collection timer. Default is 120.\n")
3103
paul718e3742002-12-13 20:15:29 +00003104
3105struct route_table *rip_distance_table;
3106
3107struct rip_distance
3108{
3109 /* Distance value for the IP source prefix. */
3110 u_char distance;
3111
3112 /* Name of the access-list to be matched. */
3113 char *access_list;
3114};
3115
pauldc63bfd2005-10-25 23:31:05 +00003116static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003117rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003118{
3119 struct rip_distance *new;
3120 new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
3121 memset (new, 0, sizeof (struct rip_distance));
3122 return new;
3123}
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}
3375
3376/* 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;
3511 extern 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
3554 if (ri->enable_network || ri->enable_interface)
3555 {
3556 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003557 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003558 else
3559 send_version = lookup (ri_version_msg, ri->ri_send);
3560
3561 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003562 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003563 else
3564 receive_version = lookup (ri_version_msg, ri->ri_receive);
3565
3566 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3567 send_version,
3568 receive_version,
3569 ri->key_chain ? ri->key_chain : "",
3570 VTY_NEWLINE);
3571 }
3572 }
3573
3574 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3575 config_write_rip_network (vty, 0);
3576
paul4aaff3f2003-06-07 01:04:45 +00003577 {
3578 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003579 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003580 {
paul4aaff3f2003-06-07 01:04:45 +00003581 ri = ifp->info;
3582
3583 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3584 {
3585 if (!found_passive)
3586 {
3587 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3588 found_passive = 1;
3589 }
3590 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3591 }
3592 }
3593 }
3594
paul718e3742002-12-13 20:15:29 +00003595 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3596 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3597 rip_peer_display (vty);
3598
3599 rip_distance_show (vty);
3600
3601 return CMD_SUCCESS;
3602}
3603
3604/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003605static int
paul718e3742002-12-13 20:15:29 +00003606config_write_rip (struct vty *vty)
3607{
3608 int write = 0;
3609 struct route_node *rn;
3610 struct rip_distance *rdistance;
3611
3612 if (rip)
3613 {
3614 /* Router RIP statement. */
3615 vty_out (vty, "router rip%s", VTY_NEWLINE);
3616 write++;
3617
3618 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003619 if (rip->version_send != RI_RIP_VERSION_2
3620 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3621 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003622 VTY_NEWLINE);
3623
3624 /* RIP timer configuration. */
3625 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3626 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3627 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3628 vty_out (vty, " timers basic %lu %lu %lu%s",
3629 rip->update_time,
3630 rip->timeout_time,
3631 rip->garbage_time,
3632 VTY_NEWLINE);
3633
3634 /* Default information configuration. */
3635 if (rip->default_information)
3636 {
3637 if (rip->default_information_route_map)
3638 vty_out (vty, " default-information originate route-map %s%s",
3639 rip->default_information_route_map, VTY_NEWLINE);
3640 else
3641 vty_out (vty, " default-information originate%s",
3642 VTY_NEWLINE);
3643 }
3644
3645 /* Redistribute configuration. */
3646 config_write_rip_redistribute (vty, 1);
3647
3648 /* RIP offset-list configuration. */
3649 config_write_rip_offset_list (vty);
3650
3651 /* RIP enabled network and interface configuration. */
3652 config_write_rip_network (vty, 1);
3653
3654 /* RIP default metric configuration */
3655 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3656 vty_out (vty, " default-metric %d%s",
3657 rip->default_metric, VTY_NEWLINE);
3658
3659 /* Distribute configuration. */
3660 write += config_write_distribute (vty);
3661
hasso16705132003-05-25 14:49:19 +00003662 /* Interface routemap configuration */
3663 write += config_write_if_rmap (vty);
3664
paul718e3742002-12-13 20:15:29 +00003665 /* Distance configuration. */
3666 if (rip->distance)
3667 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3668
3669 /* RIP source IP prefix distance configuration. */
3670 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3671 if ((rdistance = rn->info) != NULL)
3672 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3673 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3674 rdistance->access_list ? rdistance->access_list : "",
3675 VTY_NEWLINE);
3676
3677 /* RIP static route configuration. */
3678 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3679 if (rn->info)
3680 vty_out (vty, " route %s/%d%s",
3681 inet_ntoa (rn->p.u.prefix4),
3682 rn->p.prefixlen,
3683 VTY_NEWLINE);
3684
3685 }
3686 return write;
3687}
3688
3689/* RIP node structure. */
3690struct cmd_node rip_node =
3691{
3692 RIP_NODE,
3693 "%s(config-router)# ",
3694 1
3695};
3696
3697/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003698static void
paul718e3742002-12-13 20:15:29 +00003699rip_distribute_update (struct distribute *dist)
3700{
3701 struct interface *ifp;
3702 struct rip_interface *ri;
3703 struct access_list *alist;
3704 struct prefix_list *plist;
3705
3706 if (! dist->ifname)
3707 return;
3708
3709 ifp = if_lookup_by_name (dist->ifname);
3710 if (ifp == NULL)
3711 return;
3712
3713 ri = ifp->info;
3714
3715 if (dist->list[DISTRIBUTE_IN])
3716 {
3717 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3718 if (alist)
3719 ri->list[RIP_FILTER_IN] = alist;
3720 else
3721 ri->list[RIP_FILTER_IN] = NULL;
3722 }
3723 else
3724 ri->list[RIP_FILTER_IN] = NULL;
3725
3726 if (dist->list[DISTRIBUTE_OUT])
3727 {
3728 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3729 if (alist)
3730 ri->list[RIP_FILTER_OUT] = alist;
3731 else
3732 ri->list[RIP_FILTER_OUT] = NULL;
3733 }
3734 else
3735 ri->list[RIP_FILTER_OUT] = NULL;
3736
3737 if (dist->prefix[DISTRIBUTE_IN])
3738 {
3739 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3740 if (plist)
3741 ri->prefix[RIP_FILTER_IN] = plist;
3742 else
3743 ri->prefix[RIP_FILTER_IN] = NULL;
3744 }
3745 else
3746 ri->prefix[RIP_FILTER_IN] = NULL;
3747
3748 if (dist->prefix[DISTRIBUTE_OUT])
3749 {
3750 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3751 if (plist)
3752 ri->prefix[RIP_FILTER_OUT] = plist;
3753 else
3754 ri->prefix[RIP_FILTER_OUT] = NULL;
3755 }
3756 else
3757 ri->prefix[RIP_FILTER_OUT] = NULL;
3758}
3759
3760void
3761rip_distribute_update_interface (struct interface *ifp)
3762{
3763 struct distribute *dist;
3764
3765 dist = distribute_lookup (ifp->name);
3766 if (dist)
3767 rip_distribute_update (dist);
3768}
3769
3770/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003771/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003772static void
paul02ff83c2004-06-11 11:27:03 +00003773rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003774{
3775 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003776 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003777
paul1eb8ef22005-04-07 07:30:20 +00003778 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3779 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003780}
paul11dde9c2004-05-31 14:00:00 +00003781/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003782static void
paul11dde9c2004-05-31 14:00:00 +00003783rip_distribute_update_all_wrapper(struct access_list *notused)
3784{
paul02ff83c2004-06-11 11:27:03 +00003785 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003786}
paul718e3742002-12-13 20:15:29 +00003787
3788/* Delete all added rip route. */
3789void
paul216565a2005-10-25 23:35:28 +00003790rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003791{
3792 int i;
3793 struct route_node *rp;
3794 struct rip_info *rinfo;
3795
3796 if (rip)
3797 {
3798 /* Clear RIP routes */
3799 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3800 if ((rinfo = rp->info) != NULL)
3801 {
3802 if (rinfo->type == ZEBRA_ROUTE_RIP &&
3803 rinfo->sub_type == RIP_ROUTE_RTE)
3804 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
3805 &rinfo->nexthop, rinfo->metric);
3806
3807 RIP_TIMER_OFF (rinfo->t_timeout);
3808 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3809
3810 rp->info = NULL;
3811 route_unlock_node (rp);
3812
3813 rip_info_free (rinfo);
3814 }
3815
3816 /* Cancel RIP related timers. */
3817 RIP_TIMER_OFF (rip->t_update);
3818 RIP_TIMER_OFF (rip->t_triggered_update);
3819 RIP_TIMER_OFF (rip->t_triggered_interval);
3820
3821 /* Cancel read thread. */
3822 if (rip->t_read)
3823 {
3824 thread_cancel (rip->t_read);
3825 rip->t_read = NULL;
3826 }
3827
3828 /* Close RIP socket. */
3829 if (rip->sock >= 0)
3830 {
3831 close (rip->sock);
3832 rip->sock = -1;
3833 }
3834
3835 /* Static RIP route configuration. */
3836 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3837 if (rp->info)
3838 {
3839 rp->info = NULL;
3840 route_unlock_node (rp);
3841 }
3842
3843 /* RIP neighbor configuration. */
3844 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3845 if (rp->info)
3846 {
3847 rp->info = NULL;
3848 route_unlock_node (rp);
3849 }
3850
3851 /* Redistribute related clear. */
3852 if (rip->default_information_route_map)
3853 free (rip->default_information_route_map);
3854
3855 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3856 if (rip->route_map[i].name)
3857 free (rip->route_map[i].name);
3858
3859 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3860 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3861 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3862
3863 XFREE (MTYPE_RIP, rip);
3864 rip = NULL;
3865 }
3866
3867 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003868 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003869 rip_offset_clean ();
3870 rip_interface_clean ();
3871 rip_distance_reset ();
3872 rip_redistribute_clean ();
3873}
3874
3875/* Reset all values to the default settings. */
3876void
paul216565a2005-10-25 23:35:28 +00003877rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003878{
3879 /* Reset global counters. */
3880 rip_global_route_changes = 0;
3881 rip_global_queries = 0;
3882
3883 /* Call ripd related reset functions. */
3884 rip_debug_reset ();
3885 rip_route_map_reset ();
3886
3887 /* Call library reset functions. */
3888 vty_reset ();
3889 access_list_reset ();
3890 prefix_list_reset ();
3891
3892 distribute_list_reset ();
3893
3894 rip_interface_reset ();
3895 rip_distance_reset ();
3896
3897 rip_zclient_reset ();
3898}
3899
pauldc63bfd2005-10-25 23:31:05 +00003900static void
hasso16705132003-05-25 14:49:19 +00003901rip_if_rmap_update (struct if_rmap *if_rmap)
3902{
3903 struct interface *ifp;
3904 struct rip_interface *ri;
3905 struct route_map *rmap;
3906
3907 ifp = if_lookup_by_name (if_rmap->ifname);
3908 if (ifp == NULL)
3909 return;
3910
3911 ri = ifp->info;
3912
3913 if (if_rmap->routemap[IF_RMAP_IN])
3914 {
3915 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3916 if (rmap)
3917 ri->routemap[IF_RMAP_IN] = rmap;
3918 else
3919 ri->routemap[IF_RMAP_IN] = NULL;
3920 }
3921 else
3922 ri->routemap[RIP_FILTER_IN] = NULL;
3923
3924 if (if_rmap->routemap[IF_RMAP_OUT])
3925 {
3926 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3927 if (rmap)
3928 ri->routemap[IF_RMAP_OUT] = rmap;
3929 else
3930 ri->routemap[IF_RMAP_OUT] = NULL;
3931 }
3932 else
3933 ri->routemap[RIP_FILTER_OUT] = NULL;
3934}
3935
3936void
3937rip_if_rmap_update_interface (struct interface *ifp)
3938{
3939 struct if_rmap *if_rmap;
3940
3941 if_rmap = if_rmap_lookup (ifp->name);
3942 if (if_rmap)
3943 rip_if_rmap_update (if_rmap);
3944}
3945
pauldc63bfd2005-10-25 23:31:05 +00003946static void
hasso16705132003-05-25 14:49:19 +00003947rip_routemap_update_redistribute (void)
3948{
3949 int i;
3950
3951 if (rip)
3952 {
3953 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3954 {
3955 if (rip->route_map[i].name)
3956 rip->route_map[i].map =
3957 route_map_lookup_by_name (rip->route_map[i].name);
3958 }
3959 }
3960}
3961
paul11dde9c2004-05-31 14:00:00 +00003962/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003963static void
hasso98b718a2004-10-11 12:57:57 +00003964rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00003965{
3966 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003967 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00003968
paul1eb8ef22005-04-07 07:30:20 +00003969 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3970 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00003971
3972 rip_routemap_update_redistribute ();
3973}
3974
paul718e3742002-12-13 20:15:29 +00003975/* Allocate new rip structure and set default value. */
3976void
pauldc63bfd2005-10-25 23:31:05 +00003977rip_init (void)
paul718e3742002-12-13 20:15:29 +00003978{
3979 /* Randomize for triggered update random(). */
3980 srand (time (NULL));
3981
3982 /* Install top nodes. */
3983 install_node (&rip_node, config_write_rip);
3984
3985 /* Install rip commands. */
3986 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003987 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003988 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003989 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003990 install_element (CONFIG_NODE, &router_rip_cmd);
3991 install_element (CONFIG_NODE, &no_router_rip_cmd);
3992
3993 install_default (RIP_NODE);
3994 install_element (RIP_NODE, &rip_version_cmd);
3995 install_element (RIP_NODE, &no_rip_version_cmd);
3996 install_element (RIP_NODE, &no_rip_version_val_cmd);
3997 install_element (RIP_NODE, &rip_default_metric_cmd);
3998 install_element (RIP_NODE, &no_rip_default_metric_cmd);
3999 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4000 install_element (RIP_NODE, &rip_timers_cmd);
4001 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004002 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004003 install_element (RIP_NODE, &rip_route_cmd);
4004 install_element (RIP_NODE, &no_rip_route_cmd);
4005 install_element (RIP_NODE, &rip_distance_cmd);
4006 install_element (RIP_NODE, &no_rip_distance_cmd);
4007 install_element (RIP_NODE, &rip_distance_source_cmd);
4008 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4009 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4010 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
4011
4012 /* Debug related init. */
4013 rip_debug_init ();
4014
paul718e3742002-12-13 20:15:29 +00004015 /* SNMP init. */
4016#ifdef HAVE_SNMP
4017 rip_snmp_init ();
4018#endif /* HAVE_SNMP */
4019
4020 /* Access list install. */
4021 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004022 access_list_add_hook (rip_distribute_update_all_wrapper);
4023 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004024
4025 /* Prefix list initialize.*/
4026 prefix_list_init ();
4027 prefix_list_add_hook (rip_distribute_update_all);
4028 prefix_list_delete_hook (rip_distribute_update_all);
4029
4030 /* Distribute list install. */
4031 distribute_list_init (RIP_NODE);
4032 distribute_list_add_hook (rip_distribute_update);
4033 distribute_list_delete_hook (rip_distribute_update);
4034
hasso16705132003-05-25 14:49:19 +00004035 /* Route-map */
4036 rip_route_map_init ();
4037 rip_offset_init ();
4038
4039 route_map_add_hook (rip_routemap_update);
4040 route_map_delete_hook (rip_routemap_update);
4041
4042 if_rmap_init (RIP_NODE);
4043 if_rmap_hook_add (rip_if_rmap_update);
4044 if_rmap_hook_delete (rip_if_rmap_update);
4045
paul718e3742002-12-13 20:15:29 +00004046 /* Distance control. */
4047 rip_distance_table = route_table_init ();
4048}