blob: 2525679c45232f0ce7bdb209aa2ea9d2d14f380b [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. */
Stephen Hemminger1423c802008-08-14 17:59:25 +010079static const struct message rip_msg[] =
paul718e3742002-12-13 20:15:29 +000080{
81 {RIP_REQUEST, "REQUEST"},
82 {RIP_RESPONSE, "RESPONSE"},
83 {RIP_TRACEON, "TRACEON"},
84 {RIP_TRACEOFF, "TRACEOFF"},
85 {RIP_POLL, "POLL"},
86 {RIP_POLL_ENTRY, "POLL ENTRY"},
Stephen Hemminger1423c802008-08-14 17:59:25 +010087 {0, NULL},
paul718e3742002-12-13 20:15:29 +000088};
paul718e3742002-12-13 20:15:29 +000089
90/* Utility function to set boradcast option to the socket. */
pauldc63bfd2005-10-25 23:31:05 +000091static int
paul718e3742002-12-13 20:15:29 +000092sockopt_broadcast (int sock)
93{
94 int ret;
95 int on = 1;
96
97 ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
98 if (ret < 0)
99 {
100 zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
101 return -1;
102 }
103 return 0;
104}
105
pauldc63bfd2005-10-25 23:31:05 +0000106static int
paul718e3742002-12-13 20:15:29 +0000107rip_route_rte (struct rip_info *rinfo)
108{
109 return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE);
110}
111
pauldc63bfd2005-10-25 23:31:05 +0000112static struct rip_info *
paul718e3742002-12-13 20:15:29 +0000113rip_info_new ()
114{
115 struct rip_info *new;
116
117 new = XMALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
118 memset (new, 0, sizeof (struct rip_info));
119 return new;
120}
121
122void
123rip_info_free (struct rip_info *rinfo)
124{
125 XFREE (MTYPE_RIP_INFO, rinfo);
126}
127
128/* RIP route garbage collect timer. */
pauldc63bfd2005-10-25 23:31:05 +0000129static int
paul718e3742002-12-13 20:15:29 +0000130rip_garbage_collect (struct thread *t)
131{
132 struct rip_info *rinfo;
133 struct route_node *rp;
134
135 rinfo = THREAD_ARG (t);
136 rinfo->t_garbage_collect = NULL;
137
138 /* Off timeout timer. */
139 RIP_TIMER_OFF (rinfo->t_timeout);
140
141 /* Get route_node pointer. */
142 rp = rinfo->rp;
143
144 /* Unlock route_node. */
145 rp->info = NULL;
146 route_unlock_node (rp);
147
148 /* Free RIP routing information. */
149 rip_info_free (rinfo);
150
151 return 0;
152}
153
154/* Timeout RIP routes. */
pauldc63bfd2005-10-25 23:31:05 +0000155static int
paul718e3742002-12-13 20:15:29 +0000156rip_timeout (struct thread *t)
157{
158 struct rip_info *rinfo;
159 struct route_node *rn;
160
161 rinfo = THREAD_ARG (t);
162 rinfo->t_timeout = NULL;
163
164 rn = rinfo->rp;
165
166 /* - The garbage-collection timer is set for 120 seconds. */
167 RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
168 rip->garbage_time);
169
170 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
171 rinfo->metric);
172 /* - The metric for the route is set to 16 (infinity). This causes
173 the route to be removed from service. */
174 rinfo->metric = RIP_METRIC_INFINITY;
175 rinfo->flags &= ~RIP_RTF_FIB;
176
177 /* - The route change flag is to indicate that this entry has been
178 changed. */
179 rinfo->flags |= RIP_RTF_CHANGED;
180
181 /* - The output process is signalled to trigger a response. */
182 rip_event (RIP_TRIGGERED_UPDATE, 0);
183
184 return 0;
185}
186
pauldc63bfd2005-10-25 23:31:05 +0000187static void
paul718e3742002-12-13 20:15:29 +0000188rip_timeout_update (struct rip_info *rinfo)
189{
190 if (rinfo->metric != RIP_METRIC_INFINITY)
191 {
192 RIP_TIMER_OFF (rinfo->t_timeout);
193 RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
194 }
195}
196
pauldc63bfd2005-10-25 23:31:05 +0000197static int
paul718e3742002-12-13 20:15:29 +0000198rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
199{
200 struct distribute *dist;
201 struct access_list *alist;
202 struct prefix_list *plist;
203
204 /* Input distribute-list filtering. */
205 if (ri->list[RIP_FILTER_IN])
206 {
207 if (access_list_apply (ri->list[RIP_FILTER_IN],
208 (struct prefix *) p) == FILTER_DENY)
209 {
210 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000211 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000212 inet_ntoa (p->prefix), p->prefixlen);
213 return -1;
214 }
215 }
216 if (ri->prefix[RIP_FILTER_IN])
217 {
218 if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
219 (struct prefix *) p) == PREFIX_DENY)
220 {
221 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000222 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000223 inet_ntoa (p->prefix), p->prefixlen);
224 return -1;
225 }
226 }
227
228 /* All interface filter check. */
229 dist = distribute_lookup (NULL);
230 if (dist)
231 {
232 if (dist->list[DISTRIBUTE_IN])
233 {
234 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
235
236 if (alist)
237 {
238 if (access_list_apply (alist,
239 (struct prefix *) p) == FILTER_DENY)
240 {
241 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000242 zlog_debug ("%s/%d filtered by distribute in",
paul718e3742002-12-13 20:15:29 +0000243 inet_ntoa (p->prefix), p->prefixlen);
244 return -1;
245 }
246 }
247 }
248 if (dist->prefix[DISTRIBUTE_IN])
249 {
250 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
251
252 if (plist)
253 {
254 if (prefix_list_apply (plist,
255 (struct prefix *) p) == PREFIX_DENY)
256 {
257 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000258 zlog_debug ("%s/%d filtered by prefix-list in",
paul718e3742002-12-13 20:15:29 +0000259 inet_ntoa (p->prefix), p->prefixlen);
260 return -1;
261 }
262 }
263 }
264 }
265 return 0;
266}
267
pauldc63bfd2005-10-25 23:31:05 +0000268static int
paul718e3742002-12-13 20:15:29 +0000269rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
270{
271 struct distribute *dist;
272 struct access_list *alist;
273 struct prefix_list *plist;
274
275 if (ri->list[RIP_FILTER_OUT])
276 {
277 if (access_list_apply (ri->list[RIP_FILTER_OUT],
278 (struct prefix *) p) == FILTER_DENY)
279 {
280 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000281 zlog_debug ("%s/%d is filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000282 inet_ntoa (p->prefix), p->prefixlen);
283 return -1;
284 }
285 }
286 if (ri->prefix[RIP_FILTER_OUT])
287 {
288 if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
289 (struct prefix *) p) == PREFIX_DENY)
290 {
291 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000292 zlog_debug ("%s/%d is filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000293 inet_ntoa (p->prefix), p->prefixlen);
294 return -1;
295 }
296 }
297
298 /* All interface filter check. */
299 dist = distribute_lookup (NULL);
300 if (dist)
301 {
302 if (dist->list[DISTRIBUTE_OUT])
303 {
304 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
305
306 if (alist)
307 {
308 if (access_list_apply (alist,
309 (struct prefix *) p) == FILTER_DENY)
310 {
311 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000312 zlog_debug ("%s/%d filtered by distribute out",
paul718e3742002-12-13 20:15:29 +0000313 inet_ntoa (p->prefix), p->prefixlen);
314 return -1;
315 }
316 }
317 }
318 if (dist->prefix[DISTRIBUTE_OUT])
319 {
320 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
321
322 if (plist)
323 {
324 if (prefix_list_apply (plist,
325 (struct prefix *) p) == PREFIX_DENY)
326 {
327 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000328 zlog_debug ("%s/%d filtered by prefix-list out",
paul718e3742002-12-13 20:15:29 +0000329 inet_ntoa (p->prefix), p->prefixlen);
330 return -1;
331 }
332 }
333 }
334 }
335 return 0;
336}
337
338/* Check nexthop address validity. */
339static int
340rip_nexthop_check (struct in_addr *addr)
341{
hasso52dc7ee2004-09-23 19:18:23 +0000342 struct listnode *node;
343 struct listnode *cnode;
paul718e3742002-12-13 20:15:29 +0000344 struct interface *ifp;
345 struct connected *ifc;
346 struct prefix *p;
347
348 /* If nexthop address matches local configured address then it is
349 invalid nexthop. */
paul1eb8ef22005-04-07 07:30:20 +0000350 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +0000351 {
paul1eb8ef22005-04-07 07:30:20 +0000352 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
paul718e3742002-12-13 20:15:29 +0000353 {
paul718e3742002-12-13 20:15:29 +0000354 p = ifc->address;
355
356 if (p->family == AF_INET
357 && IPV4_ADDR_SAME (&p->u.prefix4, addr))
358 return -1;
359 }
360 }
361 return 0;
362}
363
364/* RIP add route to routing table. */
pauldc63bfd2005-10-25 23:31:05 +0000365static void
paul718e3742002-12-13 20:15:29 +0000366rip_rte_process (struct rte *rte, struct sockaddr_in *from,
paula87552c2004-05-03 20:00:17 +0000367 struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000368{
369 int ret;
370 struct prefix_ipv4 p;
371 struct route_node *rp;
paulb94f9db2004-05-01 20:45:38 +0000372 struct rip_info *rinfo, rinfotmp;
paul718e3742002-12-13 20:15:29 +0000373 struct rip_interface *ri;
374 struct in_addr *nexthop;
375 u_char oldmetric;
376 int same = 0;
vincentfbf5d032005-09-29 11:25:50 +0000377 int route_reuse = 0;
378 unsigned char old_dist, new_dist;
paul718e3742002-12-13 20:15:29 +0000379
380 /* Make prefix structure. */
381 memset (&p, 0, sizeof (struct prefix_ipv4));
382 p.family = AF_INET;
383 p.prefix = rte->prefix;
384 p.prefixlen = ip_masklen (rte->mask);
385
386 /* Make sure mask is applied. */
387 apply_mask_ipv4 (&p);
388
389 /* Apply input filters. */
390 ri = ifp->info;
391
392 ret = rip_incoming_filter (&p, ri);
393 if (ret < 0)
394 return;
395
hasso16705132003-05-25 14:49:19 +0000396 /* Modify entry according to the interface routemap. */
397 if (ri->routemap[RIP_FILTER_IN])
398 {
399 int ret;
400 struct rip_info newinfo;
401
402 memset (&newinfo, 0, sizeof (newinfo));
403 newinfo.type = ZEBRA_ROUTE_RIP;
404 newinfo.sub_type = RIP_ROUTE_RTE;
paula87552c2004-05-03 20:00:17 +0000405 newinfo.nexthop = rte->nexthop;
406 newinfo.from = from->sin_addr;
407 newinfo.ifindex = ifp->ifindex;
hasso16705132003-05-25 14:49:19 +0000408 newinfo.metric = rte->metric;
409 newinfo.metric_out = rte->metric; /* XXX */
paula87552c2004-05-03 20:00:17 +0000410 newinfo.tag = ntohs (rte->tag); /* XXX */
hasso16705132003-05-25 14:49:19 +0000411
412 /* The object should be of the type of rip_info */
paula87552c2004-05-03 20:00:17 +0000413 ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
414 (struct prefix *) &p, RMAP_RIP, &newinfo);
hasso16705132003-05-25 14:49:19 +0000415
416 if (ret == RMAP_DENYMATCH)
paula87552c2004-05-03 20:00:17 +0000417 {
418 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000419 zlog_debug ("RIP %s/%d is filtered by route-map in",
paula87552c2004-05-03 20:00:17 +0000420 inet_ntoa (p.prefix), p.prefixlen);
421 return;
422 }
hasso16705132003-05-25 14:49:19 +0000423
424 /* Get back the object */
paula87552c2004-05-03 20:00:17 +0000425 rte->nexthop = newinfo.nexthop_out;
426 rte->tag = htons (newinfo.tag_out); /* XXX */
427 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
hasso16705132003-05-25 14:49:19 +0000428 }
429
paul718e3742002-12-13 20:15:29 +0000430 /* Once the entry has been validated, update the metric by
431 adding the cost of the network on wich the message
432 arrived. If the result is greater than infinity, use infinity
433 (RFC2453 Sec. 3.9.2) */
434 /* Zebra ripd can handle offset-list in. */
435 ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
436
437 /* If offset-list does not modify the metric use interface's
438 metric. */
paula87552c2004-05-03 20:00:17 +0000439 if (!ret)
paul718e3742002-12-13 20:15:29 +0000440 rte->metric += ifp->metric;
441
442 if (rte->metric > RIP_METRIC_INFINITY)
443 rte->metric = RIP_METRIC_INFINITY;
444
445 /* Set nexthop pointer. */
446 if (rte->nexthop.s_addr == 0)
447 nexthop = &from->sin_addr;
448 else
449 nexthop = &rte->nexthop;
450
hasso16705132003-05-25 14:49:19 +0000451 /* Check if nexthop address is myself, then do nothing. */
paul718e3742002-12-13 20:15:29 +0000452 if (rip_nexthop_check (nexthop) < 0)
453 {
454 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +0000455 zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
paul718e3742002-12-13 20:15:29 +0000456 return;
457 }
458
459 /* Get index for the prefix. */
460 rp = route_node_get (rip->table, (struct prefix *) &p);
461
462 /* Check to see whether there is already RIP route on the table. */
463 rinfo = rp->info;
464
465 if (rinfo)
466 {
paul718e3742002-12-13 20:15:29 +0000467 /* Local static route. */
468 if (rinfo->type == ZEBRA_ROUTE_RIP
paula87552c2004-05-03 20:00:17 +0000469 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
470 (rinfo->sub_type == RIP_ROUTE_DEFAULT))
471 && rinfo->metric != RIP_METRIC_INFINITY)
vincentfbf5d032005-09-29 11:25:50 +0000472 {
473 route_unlock_node (rp);
474 return;
475 }
476
477 /* Redistributed route check. */
478 if (rinfo->type != ZEBRA_ROUTE_RIP
479 && rinfo->metric != RIP_METRIC_INFINITY)
480 {
481 /* Fill in a minimaly temporary rip_info structure, for a future
482 rip_distance_apply() use) */
483 memset (&rinfotmp, 0, sizeof (rinfotmp));
484 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
485 rinfotmp.rp = rinfo->rp;
486 new_dist = rip_distance_apply (&rinfotmp);
487 new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
488 old_dist = rinfo->distance;
vincent7a383332006-01-30 18:12:42 +0000489 /* Only connected routes may have a valid NULL distance */
490 if (rinfo->type != ZEBRA_ROUTE_CONNECT)
491 old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
vincentfbf5d032005-09-29 11:25:50 +0000492 /* If imported route does not have STRICT precedence,
493 mark it as a ghost */
494 if (new_dist > old_dist
495 || rte->metric == RIP_METRIC_INFINITY)
496 {
497 route_unlock_node (rp);
498 return;
499 }
500 else
501 {
502 RIP_TIMER_OFF (rinfo->t_timeout);
503 RIP_TIMER_OFF (rinfo->t_garbage_collect);
504
505 rp->info = NULL;
506 if (rip_route_rte (rinfo))
507 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
508 &rinfo->nexthop, rinfo->metric);
509 rip_info_free (rinfo);
510 rinfo = NULL;
511 route_reuse = 1;
512 }
513 }
paul718e3742002-12-13 20:15:29 +0000514 }
paula87552c2004-05-03 20:00:17 +0000515
516 if (!rinfo)
paul718e3742002-12-13 20:15:29 +0000517 {
518 /* Now, check to see whether there is already an explicit route
paula87552c2004-05-03 20:00:17 +0000519 for the destination prefix. If there is no such route, add
520 this route to the routing table, unless the metric is
521 infinity (there is no point in adding a route which
522 unusable). */
paul718e3742002-12-13 20:15:29 +0000523 if (rte->metric != RIP_METRIC_INFINITY)
paula87552c2004-05-03 20:00:17 +0000524 {
525 rinfo = rip_info_new ();
paul718e3742002-12-13 20:15:29 +0000526
paula87552c2004-05-03 20:00:17 +0000527 /* - Setting the destination prefix and length to those in
528 the RTE. */
529 rinfo->rp = rp;
paul718e3742002-12-13 20:15:29 +0000530
paula87552c2004-05-03 20:00:17 +0000531 /* - Setting the metric to the newly calculated metric (as
532 described above). */
533 rinfo->metric = rte->metric;
534 rinfo->tag = ntohs (rte->tag);
paul718e3742002-12-13 20:15:29 +0000535
paula87552c2004-05-03 20:00:17 +0000536 /* - Set the next hop address to be the address of the router
537 from which the datagram came or the next hop address
538 specified by a next hop RTE. */
539 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
540 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
541 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000542
paula87552c2004-05-03 20:00:17 +0000543 /* - Initialize the timeout for the route. If the
544 garbage-collection timer is running for this route, stop it
545 (see section 2.3 for a discussion of the timers). */
546 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000547
paula87552c2004-05-03 20:00:17 +0000548 /* - Set the route change flag. */
549 rinfo->flags |= RIP_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +0000550
paula87552c2004-05-03 20:00:17 +0000551 /* - Signal the output process to trigger an update (see section
552 2.5). */
553 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000554
paula87552c2004-05-03 20:00:17 +0000555 /* Finally, route goes into the kernel. */
556 rinfo->type = ZEBRA_ROUTE_RIP;
557 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000558
paula87552c2004-05-03 20:00:17 +0000559 /* Set distance value. */
560 rinfo->distance = rip_distance_apply (rinfo);
561
562 rp->info = rinfo;
563 rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
564 rinfo->distance);
565 rinfo->flags |= RIP_RTF_FIB;
566 }
vincentfbf5d032005-09-29 11:25:50 +0000567
568 /* Unlock temporary lock, i.e. same behaviour */
569 if (route_reuse)
570 route_unlock_node (rp);
paul718e3742002-12-13 20:15:29 +0000571 }
572 else
573 {
574 /* Route is there but we are not sure the route is RIP or not. */
575 rinfo = rp->info;
paula87552c2004-05-03 20:00:17 +0000576
paul718e3742002-12-13 20:15:29 +0000577 /* If there is an existing route, compare the next hop address
paula87552c2004-05-03 20:00:17 +0000578 to the address of the router from which the datagram came.
579 If this datagram is from the same router as the existing
580 route, reinitialize the timeout. */
hasso16705132003-05-25 14:49:19 +0000581 same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
paula87552c2004-05-03 20:00:17 +0000582 && (rinfo->ifindex == ifp->ifindex));
paul718e3742002-12-13 20:15:29 +0000583
584 if (same)
paula87552c2004-05-03 20:00:17 +0000585 rip_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000586
paulb94f9db2004-05-01 20:45:38 +0000587
588 /* Fill in a minimaly temporary rip_info structure, for a future
589 rip_distance_apply() use) */
paula87552c2004-05-03 20:00:17 +0000590 memset (&rinfotmp, 0, sizeof (rinfotmp));
paulb94f9db2004-05-01 20:45:38 +0000591 IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
paula87552c2004-05-03 20:00:17 +0000592 rinfotmp.rp = rinfo->rp;
paulb94f9db2004-05-01 20:45:38 +0000593
594
paul718e3742002-12-13 20:15:29 +0000595 /* Next, compare the metrics. If the datagram is from the same
paula87552c2004-05-03 20:00:17 +0000596 router as the existing route, and the new metric is different
597 than the old one; or, if the new metric is lower than the old
598 one, or if the tag has been changed; or if there is a route
599 with a lower administrave distance; or an update of the
600 distance on the actual route; do the following actions: */
601 if ((same && rinfo->metric != rte->metric)
602 || (rte->metric < rinfo->metric)
603 || ((same)
604 && (rinfo->metric == rte->metric)
605 && ntohs (rte->tag) != rinfo->tag)
606 || (rinfo->distance > rip_distance_apply (&rinfotmp))
607 || ((rinfo->distance != rip_distance_apply (rinfo)) && same))
608 {
609 /* - Adopt the route from the datagram. That is, put the
610 new metric in, and adjust the next hop address (if
611 necessary). */
612 oldmetric = rinfo->metric;
613 rinfo->metric = rte->metric;
614 rinfo->tag = ntohs (rte->tag);
615 IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
616 rinfo->ifindex = ifp->ifindex;
617 rinfo->distance = rip_distance_apply (rinfo);
paul718e3742002-12-13 20:15:29 +0000618
paula87552c2004-05-03 20:00:17 +0000619 /* Should a new route to this network be established
620 while the garbage-collection timer is running, the
621 new route will replace the one that is about to be
622 deleted. In this case the garbage-collection timer
623 must be cleared. */
paul718e3742002-12-13 20:15:29 +0000624
paula87552c2004-05-03 20:00:17 +0000625 if (oldmetric == RIP_METRIC_INFINITY &&
626 rinfo->metric < RIP_METRIC_INFINITY)
627 {
628 rinfo->type = ZEBRA_ROUTE_RIP;
629 rinfo->sub_type = RIP_ROUTE_RTE;
paul718e3742002-12-13 20:15:29 +0000630
paula87552c2004-05-03 20:00:17 +0000631 RIP_TIMER_OFF (rinfo->t_garbage_collect);
paul718e3742002-12-13 20:15:29 +0000632
paula87552c2004-05-03 20:00:17 +0000633 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
634 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000635
paula87552c2004-05-03 20:00:17 +0000636 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
637 rinfo->distance);
638 rinfo->flags |= RIP_RTF_FIB;
639 }
paul718e3742002-12-13 20:15:29 +0000640
paula87552c2004-05-03 20:00:17 +0000641 /* Update nexthop and/or metric value. */
642 if (oldmetric != RIP_METRIC_INFINITY)
643 {
644 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
645 rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
646 rinfo->distance);
647 rinfo->flags |= RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000648
paula87552c2004-05-03 20:00:17 +0000649 if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
650 IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
651 }
paul718e3742002-12-13 20:15:29 +0000652
paula87552c2004-05-03 20:00:17 +0000653 /* - Set the route change flag and signal the output process
654 to trigger an update. */
655 rinfo->flags |= RIP_RTF_CHANGED;
656 rip_event (RIP_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +0000657
paula87552c2004-05-03 20:00:17 +0000658 /* - If the new metric is infinity, start the deletion
659 process (described above); */
660 if (rinfo->metric == RIP_METRIC_INFINITY)
661 {
662 /* If the new metric is infinity, the deletion process
663 begins for the route, which is no longer used for
664 routing packets. Note that the deletion process is
665 started only when the metric is first set to
666 infinity. If the metric was already infinity, then a
667 new deletion process is not started. */
668 if (oldmetric != RIP_METRIC_INFINITY)
669 {
670 /* - The garbage-collection timer is set for 120 seconds. */
671 RIP_TIMER_ON (rinfo->t_garbage_collect,
672 rip_garbage_collect, rip->garbage_time);
673 RIP_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +0000674
paula87552c2004-05-03 20:00:17 +0000675 /* - The metric for the route is set to 16
676 (infinity). This causes the route to be removed
677 from service. */
678 rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
679 rinfo->flags &= ~RIP_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000680
paula87552c2004-05-03 20:00:17 +0000681 /* - The route change flag is to indicate that this
682 entry has been changed. */
683 /* - The output process is signalled to trigger a
paul718e3742002-12-13 20:15:29 +0000684 response. */
paula87552c2004-05-03 20:00:17 +0000685 ; /* Above processes are already done previously. */
686 }
687 }
688 else
689 {
690 /* otherwise, re-initialize the timeout. */
691 rip_timeout_update (rinfo);
692 }
693 }
paul718e3742002-12-13 20:15:29 +0000694 /* Unlock tempolary lock of the route. */
695 route_unlock_node (rp);
696 }
697}
698
699/* Dump RIP packet */
pauldc63bfd2005-10-25 23:31:05 +0000700static void
hasso8a676be2004-10-08 06:36:38 +0000701rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000702{
703 caddr_t lim;
704 struct rte *rte;
hasso8a676be2004-10-08 06:36:38 +0000705 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000706 char pbuf[BUFSIZ], nbuf[BUFSIZ];
707 u_char netmask = 0;
708 u_char *p;
709
710 /* Set command string. */
711 if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
712 command_str = lookup (rip_msg, packet->command);
713 else
714 command_str = "unknown";
715
716 /* Dump packet header. */
ajs5d6c3772004-12-08 19:24:06 +0000717 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000718 sndrcv, command_str, packet->version, size);
719
720 /* Dump each routing table entry. */
721 rte = packet->rte;
722
723 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
724 {
725 if (packet->version == RIPv2)
726 {
727 netmask = ip_masklen (rte->mask);
728
paulca5e5162004-06-06 22:06:33 +0000729 if (rte->family == htons (RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +0000730 {
paulca5e5162004-06-06 22:06:33 +0000731 if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000732 {
733 p = (u_char *)&rte->prefix;
734
ajs5d6c3772004-12-08 19:24:06 +0000735 zlog_debug (" family 0x%X type %d auth string: %s",
paul718e3742002-12-13 20:15:29 +0000736 ntohs (rte->family), ntohs (rte->tag), p);
737 }
paulca5e5162004-06-06 22:06:33 +0000738 else if (rte->tag == htons (RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000739 {
740 struct rip_md5_info *md5;
741
742 md5 = (struct rip_md5_info *) &packet->rte;
743
ajs5d6c3772004-12-08 19:24:06 +0000744 zlog_debug (" family 0x%X type %d (MD5 authentication)",
paul718e3742002-12-13 20:15:29 +0000745 ntohs (md5->family), ntohs (md5->type));
ajs5d6c3772004-12-08 19:24:06 +0000746 zlog_debug (" RIP-2 packet len %d Key ID %d"
paulca5e5162004-06-06 22:06:33 +0000747 " Auth Data len %d",
748 ntohs (md5->packet_len), md5->keyid,
749 md5->auth_len);
ajs5d6c3772004-12-08 19:24:06 +0000750 zlog_debug (" Sequence Number %ld",
paulca5e5162004-06-06 22:06:33 +0000751 (u_long) ntohl (md5->sequence));
paul718e3742002-12-13 20:15:29 +0000752 }
paulca5e5162004-06-06 22:06:33 +0000753 else if (rte->tag == htons (RIP_AUTH_DATA))
paul718e3742002-12-13 20:15:29 +0000754 {
755 p = (u_char *)&rte->prefix;
756
ajs5d6c3772004-12-08 19:24:06 +0000757 zlog_debug (" family 0x%X type %d (MD5 data)",
paul718e3742002-12-13 20:15:29 +0000758 ntohs (rte->family), ntohs (rte->tag));
ajs5d6c3772004-12-08 19:24:06 +0000759 zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
paul718e3742002-12-13 20:15:29 +0000760 "%02X%02X%02X%02X%02X%02X%02X",
paulca5e5162004-06-06 22:06:33 +0000761 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
762 p[7], p[9], p[10], p[11], p[12], p[13],
763 p[14], p[15]);
paul718e3742002-12-13 20:15:29 +0000764 }
765 else
766 {
ajs5d6c3772004-12-08 19:24:06 +0000767 zlog_debug (" family 0x%X type %d (Unknown auth type)",
paul718e3742002-12-13 20:15:29 +0000768 ntohs (rte->family), ntohs (rte->tag));
769 }
770 }
771 else
ajs5d6c3772004-12-08 19:24:06 +0000772 zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
paulca5e5162004-06-06 22:06:33 +0000773 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
774 netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
775 BUFSIZ), ntohs (rte->family),
776 ntohs (rte->tag), (u_long) ntohl (rte->metric));
paul718e3742002-12-13 20:15:29 +0000777 }
778 else
779 {
ajs5d6c3772004-12-08 19:24:06 +0000780 zlog_debug (" %s family %d tag %d metric %ld",
paul718e3742002-12-13 20:15:29 +0000781 inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
782 ntohs (rte->family), ntohs (rte->tag),
783 (u_long)ntohl (rte->metric));
784 }
785 }
786}
787
788/* Check if the destination address is valid (unicast; not net 0
789 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
790 check net 0 because we accept default route. */
pauldc63bfd2005-10-25 23:31:05 +0000791static int
paul718e3742002-12-13 20:15:29 +0000792rip_destination_check (struct in_addr addr)
793{
794 u_int32_t destination;
795
796 /* Convert to host byte order. */
797 destination = ntohl (addr.s_addr);
798
799 if (IPV4_NET127 (destination))
800 return 0;
801
802 /* Net 0 may match to the default route. */
803 if (IPV4_NET0 (destination) && destination != 0)
804 return 0;
805
806 /* Unicast address must belong to class A, B, C. */
807 if (IN_CLASSA (destination))
808 return 1;
809 if (IN_CLASSB (destination))
810 return 1;
811 if (IN_CLASSC (destination))
812 return 1;
813
814 return 0;
815}
816
817/* RIP version 2 authentication. */
pauldc63bfd2005-10-25 23:31:05 +0000818static int
paul718e3742002-12-13 20:15:29 +0000819rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
820 struct interface *ifp)
821{
822 struct rip_interface *ri;
823 char *auth_str;
824
825 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000826 zlog_debug ("RIPv2 simple password authentication from %s",
paul718e3742002-12-13 20:15:29 +0000827 inet_ntoa (from->sin_addr));
828
829 ri = ifp->info;
830
831 if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
paulca5e5162004-06-06 22:06:33 +0000832 || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
paul718e3742002-12-13 20:15:29 +0000833 return 0;
834
835 /* Simple password authentication. */
836 if (ri->auth_str)
837 {
838 auth_str = (char *) &rte->prefix;
839
840 if (strncmp (auth_str, ri->auth_str, 16) == 0)
841 return 1;
842 }
843 if (ri->key_chain)
844 {
845 struct keychain *keychain;
846 struct key *key;
847
848 keychain = keychain_lookup (ri->key_chain);
849 if (keychain == NULL)
850 return 0;
851
852 key = key_match_for_accept (keychain, (char *) &rte->prefix);
853 if (key)
854 return 1;
855 }
856 return 0;
857}
858
859/* RIP version 2 authentication with MD5. */
pauldc63bfd2005-10-25 23:31:05 +0000860static int
paul718e3742002-12-13 20:15:29 +0000861rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
paulca5e5162004-06-06 22:06:33 +0000862 int length, struct interface *ifp)
paul718e3742002-12-13 20:15:29 +0000863{
864 struct rip_interface *ri;
865 struct rip_md5_info *md5;
866 struct rip_md5_data *md5data;
867 struct keychain *keychain;
868 struct key *key;
vincentc1a03d42005-09-28 15:47:44 +0000869 MD5_CTX ctx;
paul718e3742002-12-13 20:15:29 +0000870 u_char digest[RIP_AUTH_MD5_SIZE];
871 u_int16_t packet_len;
paul98fd1e62006-01-17 17:26:25 +0000872 char auth_str[RIP_AUTH_MD5_SIZE];
paul718e3742002-12-13 20:15:29 +0000873
874 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000875 zlog_debug ("RIPv2 MD5 authentication from %s",
paulca5e5162004-06-06 22:06:33 +0000876 inet_ntoa (from->sin_addr));
paul718e3742002-12-13 20:15:29 +0000877
878 ri = ifp->info;
879 md5 = (struct rip_md5_info *) &packet->rte;
880
881 /* Check auth type. */
paulca5e5162004-06-06 22:06:33 +0000882 if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
paul718e3742002-12-13 20:15:29 +0000883 return 0;
884
paulca5e5162004-06-06 22:06:33 +0000885 /* If the authentication length is less than 16, then it must be wrong for
886 * any interpretation of rfc2082. Some implementations also interpret
887 * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
paul98fd1e62006-01-17 17:26:25 +0000888 */
paulca5e5162004-06-06 22:06:33 +0000889 if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
890 || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
paulc2bfbcc2004-06-04 01:42:38 +0000891 {
892 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000893 zlog_debug ("RIPv2 MD5 authentication, strange authentication "
paulca5e5162004-06-06 22:06:33 +0000894 "length field %d", md5->auth_len);
paul718e3742002-12-13 20:15:29 +0000895 return 0;
paulc2bfbcc2004-06-04 01:42:38 +0000896 }
paul718e3742002-12-13 20:15:29 +0000897
paulca5e5162004-06-06 22:06:33 +0000898 /* grab and verify check packet length */
899 packet_len = ntohs (md5->packet_len);
900
901 if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
902 {
903 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +0000904 zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
paulca5e5162004-06-06 22:06:33 +0000905 "greater than received length %d!",
906 md5->packet_len, length);
907 return 0;
908 }
909
910 /* retrieve authentication data */
911 md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
paul98fd1e62006-01-17 17:26:25 +0000912
913 memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
paulca5e5162004-06-06 22:06:33 +0000914
paul718e3742002-12-13 20:15:29 +0000915 if (ri->key_chain)
916 {
917 keychain = keychain_lookup (ri->key_chain);
918 if (keychain == NULL)
919 return 0;
920
921 key = key_lookup_for_accept (keychain, md5->keyid);
922 if (key == NULL)
923 return 0;
924
paul98fd1e62006-01-17 17:26:25 +0000925 strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000926 }
paul98fd1e62006-01-17 17:26:25 +0000927 else if (ri->auth_str)
928 strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
paul718e3742002-12-13 20:15:29 +0000929
Paul Jakmafa93b162008-05-29 19:03:08 +0000930 if (auth_str[0] == 0)
paul718e3742002-12-13 20:15:29 +0000931 return 0;
paul98fd1e62006-01-17 17:26:25 +0000932
paul718e3742002-12-13 20:15:29 +0000933 /* MD5 digest authentication. */
vincentc1a03d42005-09-28 15:47:44 +0000934 memset (&ctx, 0, sizeof(ctx));
935 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +0000936 MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
937 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
vincentc1a03d42005-09-28 15:47:44 +0000938 MD5Final(digest, &ctx);
paul98fd1e62006-01-17 17:26:25 +0000939
940 if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
paul718e3742002-12-13 20:15:29 +0000941 return packet_len;
942 else
943 return 0;
944}
945
paulb14ee002005-02-04 23:42:41 +0000946/* Pick correct auth string for sends, prepare auth_str buffer for use.
947 * (left justified and padded).
948 *
949 * presumes one of ri or key is valid, and that the auth strings they point
950 * to are nul terminated. If neither are present, auth_str will be fully
951 * zero padded.
952 *
953 */
954static void
955rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
956 char *auth_str, int len)
paul718e3742002-12-13 20:15:29 +0000957{
paulb14ee002005-02-04 23:42:41 +0000958 assert (ri || key);
paul718e3742002-12-13 20:15:29 +0000959
paulb14ee002005-02-04 23:42:41 +0000960 memset (auth_str, 0, len);
961 if (key && key->string)
962 strncpy (auth_str, key->string, len);
963 else if (ri->auth_str)
964 strncpy (auth_str, ri->auth_str, len);
paul718e3742002-12-13 20:15:29 +0000965
paulb14ee002005-02-04 23:42:41 +0000966 return;
967}
paul718e3742002-12-13 20:15:29 +0000968
paulb14ee002005-02-04 23:42:41 +0000969/* Write RIPv2 simple password authentication information
970 *
971 * auth_str is presumed to be 2 bytes and correctly prepared
972 * (left justified and zero padded).
973 */
974static void
975rip_auth_simple_write (struct stream *s, char *auth_str, int len)
976{
977 assert (s && len == RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +0000978
paulb14ee002005-02-04 23:42:41 +0000979 stream_putw (s, RIP_FAMILY_AUTH);
980 stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
981 stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
982
983 return;
984}
985
986/* write RIPv2 MD5 "authentication header"
987 * (uses the auth key data field)
988 *
989 * Digest offset field is set to 0.
990 *
991 * returns: offset of the digest offset field, which must be set when
992 * length to the auth-data MD5 digest is known.
993 */
994static size_t
995rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
996 struct key *key)
997{
paul98fd1e62006-01-17 17:26:25 +0000998 size_t doff = 0;
paulb14ee002005-02-04 23:42:41 +0000999
1000 assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
paul718e3742002-12-13 20:15:29 +00001001
1002 /* MD5 authentication. */
paulca5e5162004-06-06 22:06:33 +00001003 stream_putw (s, RIP_FAMILY_AUTH);
paul718e3742002-12-13 20:15:29 +00001004 stream_putw (s, RIP_AUTH_MD5);
1005
paulb14ee002005-02-04 23:42:41 +00001006 /* MD5 AH digest offset field.
1007 *
1008 * Set to placeholder value here, to true value when RIP-2 Packet length
1009 * is known. Actual value is set in .....().
1010 */
paul98fd1e62006-01-17 17:26:25 +00001011 doff = stream_get_endp(s);
paulb14ee002005-02-04 23:42:41 +00001012 stream_putw (s, 0);
paul718e3742002-12-13 20:15:29 +00001013
1014 /* Key ID. */
1015 if (key)
1016 stream_putc (s, key->index % 256);
1017 else
1018 stream_putc (s, 1);
1019
paulca5e5162004-06-06 22:06:33 +00001020 /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
1021 * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
1022 * to be configurable.
1023 */
1024 stream_putc (s, ri->md5_auth_len);
paul718e3742002-12-13 20:15:29 +00001025
1026 /* Sequence Number (non-decreasing). */
1027 /* RFC2080: The value used in the sequence number is
1028 arbitrary, but two suggestions are the time of the
1029 message's creation or a simple message counter. */
1030 stream_putl (s, time (NULL));
1031
1032 /* Reserved field must be zero. */
1033 stream_putl (s, 0);
1034 stream_putl (s, 0);
1035
paul98fd1e62006-01-17 17:26:25 +00001036 return doff;
paulb14ee002005-02-04 23:42:41 +00001037}
paul718e3742002-12-13 20:15:29 +00001038
paulb14ee002005-02-04 23:42:41 +00001039/* If authentication is in used, write the appropriate header
1040 * returns stream offset to which length must later be written
1041 * or 0 if this is not required
1042 */
1043static size_t
1044rip_auth_header_write (struct stream *s, struct rip_interface *ri,
1045 struct key *key, char *auth_str, int len)
1046{
1047 assert (ri->auth_type != RIP_NO_AUTH);
1048
1049 switch (ri->auth_type)
1050 {
1051 case RIP_AUTH_SIMPLE_PASSWORD:
1052 rip_auth_prepare_str_send (ri, key, auth_str, len);
1053 rip_auth_simple_write (s, auth_str, len);
1054 return 0;
1055 case RIP_AUTH_MD5:
1056 return rip_auth_md5_ah_write (s, ri, key);
1057 }
1058 assert (1);
paul98fd1e62006-01-17 17:26:25 +00001059 return 0;
paulb14ee002005-02-04 23:42:41 +00001060}
1061
1062/* Write RIPv2 MD5 authentication data trailer */
1063static void
1064rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
1065 char *auth_str, int authlen)
1066{
1067 unsigned long len;
vincentc1a03d42005-09-28 15:47:44 +00001068 MD5_CTX ctx;
paulb14ee002005-02-04 23:42:41 +00001069 unsigned char digest[RIP_AUTH_MD5_SIZE];
1070
1071 /* Make it sure this interface is configured as MD5
1072 authentication. */
1073 assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
1074 assert (doff > 0);
1075
1076 /* Get packet length. */
1077 len = stream_get_endp(s);
1078
1079 /* Check packet length. */
1080 if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
1081 {
1082 zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
1083 return;
1084 }
1085
1086 /* Set the digest offset length in the header */
1087 stream_putw_at (s, doff, len);
1088
paul718e3742002-12-13 20:15:29 +00001089 /* Set authentication data. */
paulca5e5162004-06-06 22:06:33 +00001090 stream_putw (s, RIP_FAMILY_AUTH);
1091 stream_putw (s, RIP_AUTH_DATA);
paul718e3742002-12-13 20:15:29 +00001092
1093 /* Generate a digest for the RIP packet. */
vincentc1a03d42005-09-28 15:47:44 +00001094 memset(&ctx, 0, sizeof(ctx));
1095 MD5Init(&ctx);
paul98fd1e62006-01-17 17:26:25 +00001096 MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
vincentc1a03d42005-09-28 15:47:44 +00001097 MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
1098 MD5Final(digest, &ctx);
paul718e3742002-12-13 20:15:29 +00001099
1100 /* Copy the digest to the packet. */
1101 stream_write (s, digest, RIP_AUTH_MD5_SIZE);
1102}
1103
1104/* RIP routing information. */
pauldc63bfd2005-10-25 23:31:05 +00001105static void
paul718e3742002-12-13 20:15:29 +00001106rip_response_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001107 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001108{
1109 caddr_t lim;
1110 struct rte *rte;
paul727d1042002-12-13 20:50:29 +00001111 struct prefix_ipv4 ifaddr;
1112 struct prefix_ipv4 ifaddrclass;
paul727d1042002-12-13 20:50:29 +00001113 int subnetted;
paul718e3742002-12-13 20:15:29 +00001114
paul727d1042002-12-13 20:50:29 +00001115 /* We don't know yet. */
1116 subnetted = -1;
1117
paul718e3742002-12-13 20:15:29 +00001118 /* The Response must be ignored if it is not from the RIP
1119 port. (RFC2453 - Sec. 3.9.2)*/
paulca5e5162004-06-06 22:06:33 +00001120 if (from->sin_port != htons(RIP_PORT_DEFAULT))
paul718e3742002-12-13 20:15:29 +00001121 {
1122 zlog_info ("response doesn't come from RIP port: %d",
1123 from->sin_port);
1124 rip_peer_bad_packet (from);
1125 return;
1126 }
1127
1128 /* The datagram's IPv4 source address should be checked to see
1129 whether the datagram is from a valid neighbor; the source of the
ajs35a60c22005-10-30 23:51:32 +00001130 datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
1131 if (if_lookup_address(from->sin_addr) == NULL)
paul718e3742002-12-13 20:15:29 +00001132 {
1133 zlog_info ("This datagram doesn't came from a valid neighbor: %s",
1134 inet_ntoa (from->sin_addr));
1135 rip_peer_bad_packet (from);
1136 return;
1137 }
1138
1139 /* It is also worth checking to see whether the response is from one
1140 of the router's own addresses. */
1141
1142 ; /* Alredy done in rip_read () */
1143
1144 /* Update RIP peer. */
1145 rip_peer_update (from, packet->version);
1146
1147 /* Set RTE pointer. */
1148 rte = packet->rte;
1149
1150 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
1151 {
1152 /* RIPv2 authentication check. */
1153 /* If the Address Family Identifier of the first (and only the
1154 first) entry in the message is 0xFFFF, then the remainder of
1155 the entry contains the authentication. */
1156 /* If the packet gets here it means authentication enabled */
1157 /* Check is done in rip_read(). So, just skipping it */
1158 if (packet->version == RIPv2 &&
1159 rte == packet->rte &&
paulca5e5162004-06-06 22:06:33 +00001160 rte->family == htons(RIP_FAMILY_AUTH))
paul718e3742002-12-13 20:15:29 +00001161 continue;
1162
paulca5e5162004-06-06 22:06:33 +00001163 if (rte->family != htons(AF_INET))
paul718e3742002-12-13 20:15:29 +00001164 {
1165 /* Address family check. RIP only supports AF_INET. */
1166 zlog_info ("Unsupported family %d from %s.",
1167 ntohs (rte->family), inet_ntoa (from->sin_addr));
1168 continue;
1169 }
1170
1171 /* - is the destination address valid (e.g., unicast; not net 0
1172 or 127) */
1173 if (! rip_destination_check (rte->prefix))
1174 {
1175 zlog_info ("Network is net 0 or net 127 or it is not unicast network");
1176 rip_peer_bad_route (from);
1177 continue;
1178 }
1179
1180 /* Convert metric value to host byte order. */
1181 rte->metric = ntohl (rte->metric);
1182
1183 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1184 if (! (rte->metric >= 1 && rte->metric <= 16))
1185 {
1186 zlog_info ("Route's metric is not in the 1-16 range.");
1187 rip_peer_bad_route (from);
1188 continue;
1189 }
1190
1191 /* RIPv1 does not have nexthop value. */
1192 if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
1193 {
1194 zlog_info ("RIPv1 packet with nexthop value %s",
1195 inet_ntoa (rte->nexthop));
1196 rip_peer_bad_route (from);
1197 continue;
1198 }
1199
1200 /* That is, if the provided information is ignored, a possibly
1201 sub-optimal, but absolutely valid, route may be taken. If
1202 the received Next Hop is not directly reachable, it should be
1203 treated as 0.0.0.0. */
1204 if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
1205 {
1206 u_int32_t addrval;
1207
1208 /* Multicast address check. */
1209 addrval = ntohl (rte->nexthop.s_addr);
1210 if (IN_CLASSD (addrval))
1211 {
1212 zlog_info ("Nexthop %s is multicast address, skip this rte",
1213 inet_ntoa (rte->nexthop));
1214 continue;
1215 }
1216
1217 if (! if_lookup_address (rte->nexthop))
1218 {
1219 struct route_node *rn;
1220 struct rip_info *rinfo;
1221
1222 rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
1223
1224 if (rn)
1225 {
1226 rinfo = rn->info;
1227
1228 if (rinfo->type == ZEBRA_ROUTE_RIP
1229 && rinfo->sub_type == RIP_ROUTE_RTE)
1230 {
1231 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001232 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 +00001233 rte->nexthop = rinfo->from;
1234 }
1235 else
1236 {
1237 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001238 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 +00001239 rte->nexthop.s_addr = 0;
1240 }
1241
1242 route_unlock_node (rn);
1243 }
1244 else
1245 {
1246 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001247 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 +00001248 rte->nexthop.s_addr = 0;
1249 }
1250
1251 }
1252 }
1253
1254 /* For RIPv1, there won't be a valid netmask.
1255
1256 This is a best guess at the masks. If everyone was using old
1257 Ciscos before the 'ip subnet zero' option, it would be almost
1258 right too :-)
1259
1260 Cisco summarize ripv1 advertisments to the classful boundary
1261 (/16 for class B's) except when the RIP packet does to inside
1262 the classful network in question. */
1263
1264 if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
1265 || (packet->version == RIPv2
1266 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
1267 {
1268 u_int32_t destination;
1269
paul727d1042002-12-13 20:50:29 +00001270 if (subnetted == -1)
paulc49ad8f2004-10-22 10:27:28 +00001271 {
1272 memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
1273 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
1274 apply_classful_mask_ipv4 (&ifaddrclass);
1275 subnetted = 0;
1276 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
1277 subnetted = 1;
1278 }
paul727d1042002-12-13 20:50:29 +00001279
paul718e3742002-12-13 20:15:29 +00001280 destination = ntohl (rte->prefix.s_addr);
1281
paul727d1042002-12-13 20:50:29 +00001282 if (IN_CLASSA (destination))
paul718e3742002-12-13 20:15:29 +00001283 masklen2ip (8, &rte->mask);
paul727d1042002-12-13 20:50:29 +00001284 else if (IN_CLASSB (destination))
1285 masklen2ip (16, &rte->mask);
1286 else if (IN_CLASSC (destination))
1287 masklen2ip (24, &rte->mask);
1288
1289 if (subnetted == 1)
1290 masklen2ip (ifaddrclass.prefixlen,
1291 (struct in_addr *) &destination);
1292 if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
1293 ifaddrclass.prefix.s_addr))
1294 {
1295 masklen2ip (ifaddr.prefixlen, &rte->mask);
1296 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1297 masklen2ip (32, &rte->mask);
1298 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001299 zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
paul727d1042002-12-13 20:50:29 +00001300 }
1301 else
1302 {
1303 if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
1304 continue;
1305 }
1306
1307 if (IS_RIP_DEBUG_EVENT)
1308 {
ajs5d6c3772004-12-08 19:24:06 +00001309 zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
1310 zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
paul718e3742002-12-13 20:15:29 +00001311 }
1312 }
1313
1314 /* In case of RIPv2, if prefix in RTE is not netmask applied one
1315 ignore the entry. */
1316 if ((packet->version == RIPv2)
1317 && (rte->mask.s_addr != 0)
1318 && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
1319 {
1320 zlog_warn ("RIPv2 address %s is not mask /%d applied one",
1321 inet_ntoa (rte->prefix), ip_masklen (rte->mask));
1322 rip_peer_bad_route (from);
1323 continue;
1324 }
1325
1326 /* Default route's netmask is ignored. */
1327 if (packet->version == RIPv2
1328 && (rte->prefix.s_addr == 0)
1329 && (rte->mask.s_addr != 0))
1330 {
1331 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001332 zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
paul718e3742002-12-13 20:15:29 +00001333 rte->mask.s_addr = 0;
1334 }
1335
1336 /* Routing table updates. */
paulc49ad8f2004-10-22 10:27:28 +00001337 rip_rte_process (rte, from, ifc->ifp);
paul718e3742002-12-13 20:15:29 +00001338 }
1339}
1340
paula4e987e2005-06-03 17:46:49 +00001341/* Make socket for RIP protocol. */
paulf69bd9d2005-06-03 18:01:50 +00001342static int
paul2c61ae32005-08-16 15:22:14 +00001343rip_create_socket (struct sockaddr_in *from)
paula4e987e2005-06-03 17:46:49 +00001344{
1345 int ret;
1346 int sock;
1347 struct sockaddr_in addr;
paulf69bd9d2005-06-03 18:01:50 +00001348
paul2c61ae32005-08-16 15:22:14 +00001349 memset (&addr, 0, sizeof (struct sockaddr_in));
1350
1351 if (!from)
paulf69bd9d2005-06-03 18:01:50 +00001352 {
paulf69bd9d2005-06-03 18:01:50 +00001353 addr.sin_family = AF_INET;
1354 addr.sin_addr.s_addr = INADDR_ANY;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001355#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001356 addr.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001357#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
jardin38d3c162005-10-19 19:29:59 +00001358 } else {
1359 memcpy(&addr, from, sizeof(addr));
paulf69bd9d2005-06-03 18:01:50 +00001360 }
1361
paul2c61ae32005-08-16 15:22:14 +00001362 /* sending port must always be the RIP port */
1363 addr.sin_port = htons (RIP_PORT_DEFAULT);
1364
paula4e987e2005-06-03 17:46:49 +00001365 /* Make datagram socket. */
1366 sock = socket (AF_INET, SOCK_DGRAM, 0);
1367 if (sock < 0)
1368 {
1369 zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
1370 exit (1);
1371 }
1372
1373 sockopt_broadcast (sock);
1374 sockopt_reuseaddr (sock);
1375 sockopt_reuseport (sock);
paula4e987e2005-06-03 17:46:49 +00001376#ifdef RIP_RECVMSG
1377 setsockopt_pktinfo (sock);
1378#endif /* RIP_RECVMSG */
1379
1380 if (ripd_privs.change (ZPRIVS_RAISE))
1381 zlog_err ("rip_create_socket: could not raise privs");
paulf69bd9d2005-06-03 18:01:50 +00001382 setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
1383 if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
1384
paula4e987e2005-06-03 17:46:49 +00001385 {
1386 int save_errno = errno;
1387 if (ripd_privs.change (ZPRIVS_LOWER))
1388 zlog_err ("rip_create_socket: could not lower privs");
paul2c61ae32005-08-16 15:22:14 +00001389
1390 zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
1391 sock, inet_ntoa(addr.sin_addr),
1392 (int) ntohs(addr.sin_port),
1393 safe_strerror(save_errno));
1394
paulf69bd9d2005-06-03 18:01:50 +00001395 close (sock);
paula4e987e2005-06-03 17:46:49 +00001396 return ret;
1397 }
paulf69bd9d2005-06-03 18:01:50 +00001398
paula4e987e2005-06-03 17:46:49 +00001399 if (ripd_privs.change (ZPRIVS_LOWER))
1400 zlog_err ("rip_create_socket: could not lower privs");
1401
1402 return sock;
1403}
1404
paulc49ad8f2004-10-22 10:27:28 +00001405/* RIP packet send to destination address, on interface denoted by
1406 * by connected argument. NULL to argument denotes destination should be
1407 * should be RIP multicast group
1408 */
pauldc63bfd2005-10-25 23:31:05 +00001409static int
paulc49ad8f2004-10-22 10:27:28 +00001410rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
1411 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001412{
paul931cd542004-01-23 15:31:42 +00001413 int ret, send_sock;
paul718e3742002-12-13 20:15:29 +00001414 struct sockaddr_in sin;
paulc49ad8f2004-10-22 10:27:28 +00001415
1416 assert (ifc != NULL);
1417
paul931cd542004-01-23 15:31:42 +00001418 if (IS_RIP_DEBUG_PACKET)
1419 {
paulf69bd9d2005-06-03 18:01:50 +00001420#define ADDRESS_SIZE 20
1421 char dst[ADDRESS_SIZE];
1422 dst[ADDRESS_SIZE - 1] = '\0';
1423
paul931cd542004-01-23 15:31:42 +00001424 if (to)
1425 {
paulf69bd9d2005-06-03 18:01:50 +00001426 strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001427 }
1428 else
1429 {
1430 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paulf69bd9d2005-06-03 18:01:50 +00001431 strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
paul931cd542004-01-23 15:31:42 +00001432 }
paulf69bd9d2005-06-03 18:01:50 +00001433#undef ADDRESS_SIZE
ajs5d6c3772004-12-08 19:24:06 +00001434 zlog_debug("rip_send_packet %s > %s (%s)",
paulc49ad8f2004-10-22 10:27:28 +00001435 inet_ntoa(ifc->address->u.prefix4),
1436 dst, ifc->ifp->name);
paul931cd542004-01-23 15:31:42 +00001437 }
paulf69bd9d2005-06-03 18:01:50 +00001438
paulc49ad8f2004-10-22 10:27:28 +00001439 if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
paul931cd542004-01-23 15:31:42 +00001440 {
1441 /*
1442 * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
1443 * with multiple addresses on the same subnet: the first address
1444 * on the subnet is configured "primary", and all subsequent addresses
1445 * on that subnet are treated as "secondary" addresses.
1446 * In order to avoid routing-table bloat on other rip listeners,
1447 * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
1448 * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
1449 * flag is set, we would end up sending a packet for a "secondary"
1450 * source address on non-linux systems.
1451 */
1452 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001453 zlog_debug("duplicate dropped");
paul931cd542004-01-23 15:31:42 +00001454 return 0;
1455 }
1456
paul718e3742002-12-13 20:15:29 +00001457 /* Make destination address. */
1458 memset (&sin, 0, sizeof (struct sockaddr_in));
1459 sin.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001460#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +00001461 sin.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001462#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +00001463
1464 /* When destination is specified, use it's port and address. */
1465 if (to)
1466 {
paul718e3742002-12-13 20:15:29 +00001467 sin.sin_port = to->sin_port;
1468 sin.sin_addr = to->sin_addr;
paul931cd542004-01-23 15:31:42 +00001469 send_sock = rip->sock;
paul718e3742002-12-13 20:15:29 +00001470 }
1471 else
1472 {
paul2c61ae32005-08-16 15:22:14 +00001473 struct sockaddr_in from;
1474
paul718e3742002-12-13 20:15:29 +00001475 sin.sin_port = htons (RIP_PORT_DEFAULT);
1476 sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
paul2c61ae32005-08-16 15:22:14 +00001477
1478 /* multicast send should bind to local interface address */
1479 from.sin_family = AF_INET;
1480 from.sin_port = htons (RIP_PORT_DEFAULT);
1481 from.sin_addr = ifc->address->u.prefix4;
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001482#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul2c61ae32005-08-16 15:22:14 +00001483 from.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00001484#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul2c61ae32005-08-16 15:22:14 +00001485
paul931cd542004-01-23 15:31:42 +00001486 /*
1487 * we have to open a new socket for each packet because this
1488 * is the most portable way to bind to a different source
1489 * ipv4 address for each packet.
1490 */
paul2c61ae32005-08-16 15:22:14 +00001491 if ( (send_sock = rip_create_socket (&from)) < 0)
paul931cd542004-01-23 15:31:42 +00001492 {
paulf69bd9d2005-06-03 18:01:50 +00001493 zlog_warn("rip_send_packet could not create socket.");
paul931cd542004-01-23 15:31:42 +00001494 return -1;
paulf69bd9d2005-06-03 18:01:50 +00001495 }
paulc49ad8f2004-10-22 10:27:28 +00001496 rip_interface_multicast_set (send_sock, ifc);
paul718e3742002-12-13 20:15:29 +00001497 }
1498
paul931cd542004-01-23 15:31:42 +00001499 ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
paul718e3742002-12-13 20:15:29 +00001500 sizeof (struct sockaddr_in));
1501
1502 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001503 zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
paulcc1131a2003-10-15 23:20:17 +00001504 ntohs (sin.sin_port));
paul718e3742002-12-13 20:15:29 +00001505
1506 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001507 zlog_warn ("can't send packet : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001508
paul931cd542004-01-23 15:31:42 +00001509 if (!to)
1510 close(send_sock);
1511
paul718e3742002-12-13 20:15:29 +00001512 return ret;
1513}
1514
1515/* Add redistributed route to RIP table. */
1516void
1517rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
vincentfbf5d032005-09-29 11:25:50 +00001518 unsigned int ifindex, struct in_addr *nexthop,
1519 unsigned int metric, unsigned char distance)
paul718e3742002-12-13 20:15:29 +00001520{
1521 int ret;
1522 struct route_node *rp;
1523 struct rip_info *rinfo;
1524
1525 /* Redistribute route */
1526 ret = rip_destination_check (p->prefix);
1527 if (! ret)
1528 return;
1529
1530 rp = route_node_get (rip->table, (struct prefix *) p);
1531
1532 rinfo = rp->info;
1533
1534 if (rinfo)
1535 {
1536 if (rinfo->type == ZEBRA_ROUTE_CONNECT
1537 && rinfo->sub_type == RIP_ROUTE_INTERFACE
1538 && rinfo->metric != RIP_METRIC_INFINITY)
1539 {
1540 route_unlock_node (rp);
1541 return;
1542 }
1543
1544 /* Manually configured RIP route check. */
1545 if (rinfo->type == ZEBRA_ROUTE_RIP
hasso16705132003-05-25 14:49:19 +00001546 && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
1547 (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
paul718e3742002-12-13 20:15:29 +00001548 {
hasso16705132003-05-25 14:49:19 +00001549 if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
1550 (sub_type != RIP_ROUTE_DEFAULT)))
paul718e3742002-12-13 20:15:29 +00001551 {
1552 route_unlock_node (rp);
1553 return;
1554 }
1555 }
1556
1557 RIP_TIMER_OFF (rinfo->t_timeout);
1558 RIP_TIMER_OFF (rinfo->t_garbage_collect);
1559
1560 if (rip_route_rte (rinfo))
1561 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
1562 rinfo->metric);
1563 rp->info = NULL;
1564 rip_info_free (rinfo);
1565
1566 route_unlock_node (rp);
1567 }
1568
1569 rinfo = rip_info_new ();
1570
1571 rinfo->type = type;
1572 rinfo->sub_type = sub_type;
1573 rinfo->ifindex = ifindex;
1574 rinfo->metric = 1;
vincentfbf5d032005-09-29 11:25:50 +00001575 rinfo->external_metric = metric;
1576 rinfo->distance = distance;
paul718e3742002-12-13 20:15:29 +00001577 rinfo->rp = rp;
1578
1579 if (nexthop)
1580 rinfo->nexthop = *nexthop;
1581
1582 rinfo->flags |= RIP_RTF_FIB;
1583 rp->info = rinfo;
1584
1585 rinfo->flags |= RIP_RTF_CHANGED;
1586
hasso16705132003-05-25 14:49:19 +00001587 if (IS_RIP_DEBUG_EVENT) {
1588 if (!nexthop)
ajs5d6c3772004-12-08 19:24:06 +00001589 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso16705132003-05-25 14:49:19 +00001590 inet_ntoa(p->prefix), p->prefixlen,
1591 ifindex2ifname(ifindex));
1592 else
ajs5d6c3772004-12-08 19:24:06 +00001593 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso16705132003-05-25 14:49:19 +00001594 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
1595 ifindex2ifname(ifindex));
1596 }
1597
1598
paul718e3742002-12-13 20:15:29 +00001599 rip_event (RIP_TRIGGERED_UPDATE, 0);
1600}
1601
1602/* Delete redistributed route from RIP table. */
1603void
1604rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
1605 unsigned int ifindex)
1606{
1607 int ret;
1608 struct route_node *rp;
1609 struct rip_info *rinfo;
1610
1611 ret = rip_destination_check (p->prefix);
1612 if (! ret)
1613 return;
1614
1615 rp = route_node_lookup (rip->table, (struct prefix *) p);
1616 if (rp)
1617 {
1618 rinfo = rp->info;
1619
1620 if (rinfo != NULL
1621 && rinfo->type == type
1622 && rinfo->sub_type == sub_type
1623 && rinfo->ifindex == ifindex)
1624 {
1625 /* Perform poisoned reverse. */
1626 rinfo->metric = RIP_METRIC_INFINITY;
1627 RIP_TIMER_ON (rinfo->t_garbage_collect,
1628 rip_garbage_collect, rip->garbage_time);
1629 RIP_TIMER_OFF (rinfo->t_timeout);
1630 rinfo->flags |= RIP_RTF_CHANGED;
1631
hasso16705132003-05-25 14:49:19 +00001632 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001633 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso16705132003-05-25 14:49:19 +00001634 inet_ntoa(p->prefix), p->prefixlen,
1635 ifindex2ifname(ifindex));
1636
paul718e3742002-12-13 20:15:29 +00001637 rip_event (RIP_TRIGGERED_UPDATE, 0);
1638 }
1639 }
1640}
1641
1642/* Response to request called from rip_read ().*/
pauldc63bfd2005-10-25 23:31:05 +00001643static void
paul718e3742002-12-13 20:15:29 +00001644rip_request_process (struct rip_packet *packet, int size,
paulc49ad8f2004-10-22 10:27:28 +00001645 struct sockaddr_in *from, struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001646{
1647 caddr_t lim;
1648 struct rte *rte;
1649 struct prefix_ipv4 p;
1650 struct route_node *rp;
1651 struct rip_info *rinfo;
1652 struct rip_interface *ri;
1653
hasso16705132003-05-25 14:49:19 +00001654 /* Does not reponse to the requests on the loopback interfaces */
paulc49ad8f2004-10-22 10:27:28 +00001655 if (if_is_loopback (ifc->ifp))
hasso16705132003-05-25 14:49:19 +00001656 return;
1657
hasso429a0f82004-02-22 23:42:22 +00001658 /* Check RIP process is enabled on this interface. */
paulc49ad8f2004-10-22 10:27:28 +00001659 ri = ifc->ifp->info;
hasso16705132003-05-25 14:49:19 +00001660 if (! ri->running)
1661 return;
paul718e3742002-12-13 20:15:29 +00001662
1663 /* When passive interface is specified, suppress responses */
1664 if (ri->passive)
1665 return;
paulc49ad8f2004-10-22 10:27:28 +00001666
paul718e3742002-12-13 20:15:29 +00001667 /* RIP peer update. */
1668 rip_peer_update (from, packet->version);
1669
1670 lim = ((caddr_t) packet) + size;
1671 rte = packet->rte;
1672
1673 /* The Request is processed entry by entry. If there are no
1674 entries, no response is given. */
1675 if (lim == (caddr_t) rte)
1676 return;
1677
1678 /* There is one special case. If there is exactly one entry in the
1679 request, and it has an address family identifier of zero and a
1680 metric of infinity (i.e., 16), then this is a request to send the
1681 entire routing table. */
1682 if (lim == ((caddr_t) (rte + 1)) &&
1683 ntohs (rte->family) == 0 &&
1684 ntohl (rte->metric) == RIP_METRIC_INFINITY)
1685 {
paulcc1131a2003-10-15 23:20:17 +00001686 struct prefix_ipv4 saddr;
1687
1688 /* saddr will be used for determining which routes to split-horizon.
1689 Since the source address we'll pick will be on the same subnet as the
1690 destination, for the purpose of split-horizoning, we'll
1691 pretend that "from" is our source address. */
1692 saddr.family = AF_INET;
1693 saddr.prefixlen = IPV4_MAX_BITLEN;
1694 saddr.prefix = from->sin_addr;
1695
paul718e3742002-12-13 20:15:29 +00001696 /* All route with split horizon */
paulc49ad8f2004-10-22 10:27:28 +00001697 rip_output_process (ifc, from, rip_all_route, packet->version);
paul718e3742002-12-13 20:15:29 +00001698 }
1699 else
1700 {
1701 /* Examine the list of RTEs in the Request one by one. For each
1702 entry, look up the destination in the router's routing
1703 database and, if there is a route, put that route's metric in
1704 the metric field of the RTE. If there is no explicit route
1705 to the specified destination, put infinity in the metric
1706 field. Once all the entries have been filled in, change the
1707 command from Request to Response and send the datagram back
1708 to the requestor. */
1709 p.family = AF_INET;
1710
1711 for (; ((caddr_t) rte) < lim; rte++)
1712 {
1713 p.prefix = rte->prefix;
1714 p.prefixlen = ip_masklen (rte->mask);
1715 apply_mask_ipv4 (&p);
1716
1717 rp = route_node_lookup (rip->table, (struct prefix *) &p);
1718 if (rp)
1719 {
1720 rinfo = rp->info;
1721 rte->metric = htonl (rinfo->metric);
1722 route_unlock_node (rp);
1723 }
1724 else
1725 rte->metric = htonl (RIP_METRIC_INFINITY);
1726 }
1727 packet->command = RIP_RESPONSE;
1728
paulc49ad8f2004-10-22 10:27:28 +00001729 rip_send_packet ((u_char *)packet, size, from, ifc);
paul718e3742002-12-13 20:15:29 +00001730 }
1731 rip_global_queries++;
1732}
1733
1734#if RIP_RECVMSG
1735/* Set IPv6 packet info to the socket. */
1736static int
1737setsockopt_pktinfo (int sock)
1738{
1739 int ret;
1740 int val = 1;
1741
1742 ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
1743 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001744 zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001745 return ret;
1746}
1747
1748/* Read RIP packet by recvmsg function. */
1749int
1750rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
1751 int *ifindex)
1752{
1753 int ret;
1754 struct msghdr msg;
1755 struct iovec iov;
1756 struct cmsghdr *ptr;
1757 char adata[1024];
1758
1759 msg.msg_name = (void *) from;
1760 msg.msg_namelen = sizeof (struct sockaddr_in);
1761 msg.msg_iov = &iov;
1762 msg.msg_iovlen = 1;
1763 msg.msg_control = (void *) adata;
1764 msg.msg_controllen = sizeof adata;
1765 iov.iov_base = buf;
1766 iov.iov_len = size;
1767
1768 ret = recvmsg (sock, &msg, 0);
1769 if (ret < 0)
1770 return ret;
1771
ajsb99760a2005-01-04 16:24:43 +00001772 for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
paul718e3742002-12-13 20:15:29 +00001773 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
1774 {
1775 struct in_pktinfo *pktinfo;
1776 int i;
1777
1778 pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
1779 i = pktinfo->ipi_ifindex;
1780 }
1781 return ret;
1782}
1783
1784/* RIP packet read function. */
1785int
1786rip_read_new (struct thread *t)
1787{
1788 int ret;
1789 int sock;
1790 char buf[RIP_PACKET_MAXSIZ];
1791 struct sockaddr_in from;
1792 unsigned int ifindex;
1793
1794 /* Fetch socket then register myself. */
1795 sock = THREAD_FD (t);
1796 rip_event (RIP_READ, sock);
1797
1798 /* Read RIP packet. */
1799 ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
1800 if (ret < 0)
1801 {
ajs6099b3b2004-11-20 02:06:59 +00001802 zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001803 return ret;
1804 }
1805
1806 return ret;
1807}
1808#endif /* RIP_RECVMSG */
1809
1810/* First entry point of RIP packet. */
pauldc63bfd2005-10-25 23:31:05 +00001811static int
paul718e3742002-12-13 20:15:29 +00001812rip_read (struct thread *t)
1813{
1814 int sock;
1815 int ret;
1816 int rtenum;
1817 union rip_buf rip_buf;
1818 struct rip_packet *packet;
1819 struct sockaddr_in from;
paul11dde9c2004-05-31 14:00:00 +00001820 int len;
Paul Jakma3e557ae2006-09-11 02:10:40 +00001821 int vrecv;
paul11dde9c2004-05-31 14:00:00 +00001822 socklen_t fromlen;
paul718e3742002-12-13 20:15:29 +00001823 struct interface *ifp;
paulc49ad8f2004-10-22 10:27:28 +00001824 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +00001825 struct rip_interface *ri;
1826
1827 /* Fetch socket then register myself. */
1828 sock = THREAD_FD (t);
1829 rip->t_read = NULL;
1830
1831 /* Add myself to tne next event */
1832 rip_event (RIP_READ, sock);
1833
1834 /* RIPd manages only IPv4. */
1835 memset (&from, 0, sizeof (struct sockaddr_in));
1836 fromlen = sizeof (struct sockaddr_in);
1837
1838 len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
1839 (struct sockaddr *) &from, &fromlen);
1840 if (len < 0)
1841 {
ajs6099b3b2004-11-20 02:06:59 +00001842 zlog_info ("recvfrom failed: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001843 return len;
1844 }
1845
1846 /* Check is this packet comming from myself? */
paul31a476c2003-09-29 19:54:53 +00001847 if (if_check_address (from.sin_addr))
paul718e3742002-12-13 20:15:29 +00001848 {
1849 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00001850 zlog_debug ("ignore packet comes from myself");
paul718e3742002-12-13 20:15:29 +00001851 return -1;
1852 }
1853
1854 /* Which interface is this packet comes from. */
1855 ifp = if_lookup_address (from.sin_addr);
paulc49ad8f2004-10-22 10:27:28 +00001856
paul718e3742002-12-13 20:15:29 +00001857 /* RIP packet received */
1858 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001859 zlog_debug ("RECV packet from %s port %d on %s",
paul718e3742002-12-13 20:15:29 +00001860 inet_ntoa (from.sin_addr), ntohs (from.sin_port),
1861 ifp ? ifp->name : "unknown");
1862
1863 /* If this packet come from unknown interface, ignore it. */
1864 if (ifp == NULL)
1865 {
ajs766a0ca2004-12-15 14:55:51 +00001866 zlog_info ("rip_read: cannot find interface for packet from %s port %d",
1867 inet_ntoa(from.sin_addr), ntohs (from.sin_port));
paulc49ad8f2004-10-22 10:27:28 +00001868 return -1;
1869 }
1870
1871 ifc = connected_lookup_address (ifp, from.sin_addr);
1872
1873 if (ifc == NULL)
1874 {
ajs766a0ca2004-12-15 14:55:51 +00001875 zlog_info ("rip_read: cannot find connected address for packet from %s "
1876 "port %d on interface %s",
1877 inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
paul718e3742002-12-13 20:15:29 +00001878 return -1;
1879 }
1880
1881 /* Packet length check. */
1882 if (len < RIP_PACKET_MINSIZ)
1883 {
1884 zlog_warn ("packet size %d is smaller than minimum size %d",
1885 len, RIP_PACKET_MINSIZ);
1886 rip_peer_bad_packet (&from);
1887 return len;
1888 }
1889 if (len > RIP_PACKET_MAXSIZ)
1890 {
1891 zlog_warn ("packet size %d is larger than max size %d",
1892 len, RIP_PACKET_MAXSIZ);
1893 rip_peer_bad_packet (&from);
1894 return len;
1895 }
1896
1897 /* Packet alignment check. */
1898 if ((len - RIP_PACKET_MINSIZ) % 20)
1899 {
1900 zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
1901 rip_peer_bad_packet (&from);
1902 return len;
1903 }
1904
1905 /* Set RTE number. */
1906 rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
1907
1908 /* For easy to handle. */
1909 packet = &rip_buf.rip_packet;
1910
1911 /* RIP version check. */
1912 if (packet->version == 0)
1913 {
1914 zlog_info ("version 0 with command %d received.", packet->command);
1915 rip_peer_bad_packet (&from);
1916 return -1;
1917 }
1918
1919 /* Dump RIP packet. */
1920 if (IS_RIP_DEBUG_RECV)
1921 rip_packet_dump (packet, len, "RECV");
1922
1923 /* RIP version adjust. This code should rethink now. RFC1058 says
1924 that "Version 1 implementations are to ignore this extra data and
1925 process only the fields specified in this document.". So RIPv3
1926 packet should be treated as RIPv1 ignoring must be zero field. */
1927 if (packet->version > RIPv2)
1928 packet->version = RIPv2;
1929
1930 /* Is RIP running or is this RIP neighbor ?*/
1931 ri = ifp->info;
1932 if (! ri->running && ! rip_neighbor_lookup (&from))
1933 {
1934 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001935 zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
paul718e3742002-12-13 20:15:29 +00001936 rip_peer_bad_packet (&from);
1937 return -1;
1938 }
1939
Paul Jakma15a2b082006-05-04 07:36:34 +00001940 /* RIP Version check. RFC2453, 4.6 and 5.1 */
Paul Jakma3e557ae2006-09-11 02:10:40 +00001941 vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
1942 rip->version_recv : ri->ri_receive);
Paul Jakma15a2b082006-05-04 07:36:34 +00001943 if ((packet->version == RIPv1) && !(vrecv & RIPv1))
paul718e3742002-12-13 20:15:29 +00001944 {
Paul Jakma15a2b082006-05-04 07:36:34 +00001945 if (IS_RIP_DEBUG_PACKET)
1946 zlog_debug (" packet's v%d doesn't fit to if version spec",
1947 packet->version);
1948 rip_peer_bad_packet (&from);
1949 return -1;
paul718e3742002-12-13 20:15:29 +00001950 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001951 if ((packet->version == RIPv2) && !(vrecv & RIPv2))
1952 {
1953 if (IS_RIP_DEBUG_PACKET)
1954 zlog_debug (" packet's v%d doesn't fit to if version spec",
1955 packet->version);
1956 rip_peer_bad_packet (&from);
1957 return -1;
1958 }
1959
paul718e3742002-12-13 20:15:29 +00001960 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
1961 messages, then RIP-1 and unauthenticated RIP-2 messages will be
1962 accepted; authenticated RIP-2 messages shall be discarded. */
paul718e3742002-12-13 20:15:29 +00001963 if ((ri->auth_type == RIP_NO_AUTH)
1964 && rtenum
paulca5e5162004-06-06 22:06:33 +00001965 && (packet->version == RIPv2)
1966 && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
paul718e3742002-12-13 20:15:29 +00001967 {
1968 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00001969 zlog_debug ("packet RIPv%d is dropped because authentication disabled",
paul718e3742002-12-13 20:15:29 +00001970 packet->version);
1971 rip_peer_bad_packet (&from);
1972 return -1;
1973 }
Paul Jakma15a2b082006-05-04 07:36:34 +00001974
1975 /* RFC:
1976 If the router is configured to authenticate RIP-2 messages, then
paul718e3742002-12-13 20:15:29 +00001977 RIP-1 messages and RIP-2 messages which pass authentication
1978 testing shall be accepted; unauthenticated and failed
1979 authentication RIP-2 messages shall be discarded. For maximum
1980 security, RIP-1 messages should be ignored when authentication is
1981 in use (see section 4.1); otherwise, the routing information from
1982 authenticated messages will be propagated by RIP-1 routers in an
Paul Jakma15a2b082006-05-04 07:36:34 +00001983 unauthenticated manner.
1984 */
1985 /* We make an exception for RIPv1 REQUEST packets, to which we'll
1986 * always reply regardless of authentication settings, because:
1987 *
1988 * - if there other authorised routers on-link, the REQUESTor can
1989 * passively obtain the routing updates anyway
1990 * - if there are no other authorised routers on-link, RIP can
1991 * easily be disabled for the link to prevent giving out information
1992 * on state of this routers RIP routing table..
1993 *
1994 * I.e. if RIPv1 has any place anymore these days, it's as a very
1995 * simple way to distribute routing information (e.g. to embedded
1996 * hosts / appliances) and the ability to give out RIPv1
1997 * routing-information freely, while still requiring RIPv2
1998 * authentication for any RESPONSEs might be vaguely useful.
1999 */
2000 if (ri->auth_type != RIP_NO_AUTH
2001 && packet->version == RIPv1)
paul718e3742002-12-13 20:15:29 +00002002 {
Paul Jakma15a2b082006-05-04 07:36:34 +00002003 /* Discard RIPv1 messages other than REQUESTs */
2004 if (packet->command != RIP_REQUEST)
2005 {
2006 if (IS_RIP_DEBUG_PACKET)
2007 zlog_debug ("RIPv1" " dropped because authentication enabled");
2008 rip_peer_bad_packet (&from);
2009 return -1;
2010 }
2011 }
2012 else if (ri->auth_type != RIP_NO_AUTH)
2013 {
2014 const char *auth_desc;
2015
2016 if (rtenum == 0)
2017 {
2018 /* There definitely is no authentication in the packet. */
2019 if (IS_RIP_DEBUG_PACKET)
2020 zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
2021 rip_peer_bad_packet (&from);
2022 return -1;
2023 }
2024
2025 /* First RTE must be an Authentication Family RTE */
2026 if (packet->rte->family != htons(RIP_FAMILY_AUTH))
2027 {
2028 if (IS_RIP_DEBUG_PACKET)
2029 zlog_debug ("RIPv2" " dropped because authentication enabled");
paul718e3742002-12-13 20:15:29 +00002030 rip_peer_bad_packet (&from);
2031 return -1;
Paul Jakma15a2b082006-05-04 07:36:34 +00002032 }
2033
paul718e3742002-12-13 20:15:29 +00002034 /* Check RIPv2 authentication. */
Paul Jakma15a2b082006-05-04 07:36:34 +00002035 switch (ntohs(packet->rte->tag))
2036 {
2037 case RIP_AUTH_SIMPLE_PASSWORD:
2038 auth_desc = "simple";
2039 ret = rip_auth_simple_password (packet->rte, &from, ifp);
2040 break;
2041
2042 case RIP_AUTH_MD5:
2043 auth_desc = "MD5";
2044 ret = rip_auth_md5 (packet, &from, len, ifp);
2045 /* Reset RIP packet length to trim MD5 data. */
2046 len = ret;
2047 break;
2048
2049 default:
2050 ret = 0;
2051 auth_desc = "unknown type";
2052 if (IS_RIP_DEBUG_PACKET)
2053 zlog_debug ("RIPv2 Unknown authentication type %d",
2054 ntohs (packet->rte->tag));
2055 }
2056
2057 if (ret)
2058 {
2059 if (IS_RIP_DEBUG_PACKET)
2060 zlog_debug ("RIPv2 %s authentication success", auth_desc);
2061 }
2062 else
2063 {
2064 if (IS_RIP_DEBUG_PACKET)
2065 zlog_debug ("RIPv2 %s authentication failure", auth_desc);
2066 rip_peer_bad_packet (&from);
2067 return -1;
2068 }
paul718e3742002-12-13 20:15:29 +00002069 }
2070
2071 /* Process each command. */
2072 switch (packet->command)
2073 {
2074 case RIP_RESPONSE:
paulc49ad8f2004-10-22 10:27:28 +00002075 rip_response_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002076 break;
2077 case RIP_REQUEST:
2078 case RIP_POLL:
paulc49ad8f2004-10-22 10:27:28 +00002079 rip_request_process (packet, len, &from, ifc);
paul718e3742002-12-13 20:15:29 +00002080 break;
2081 case RIP_TRACEON:
2082 case RIP_TRACEOFF:
2083 zlog_info ("Obsolete command %s received, please sent it to routed",
2084 lookup (rip_msg, packet->command));
2085 rip_peer_bad_packet (&from);
2086 break;
2087 case RIP_POLL_ENTRY:
2088 zlog_info ("Obsolete command %s received",
2089 lookup (rip_msg, packet->command));
2090 rip_peer_bad_packet (&from);
2091 break;
2092 default:
2093 zlog_info ("Unknown RIP command %d received", packet->command);
2094 rip_peer_bad_packet (&from);
2095 break;
2096 }
2097
2098 return len;
2099}
2100
paul718e3742002-12-13 20:15:29 +00002101/* Write routing table entry to the stream and return next index of
2102 the routing table entry in the stream. */
pauldc63bfd2005-10-25 23:31:05 +00002103static int
paul718e3742002-12-13 20:15:29 +00002104rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
paulb14ee002005-02-04 23:42:41 +00002105 u_char version, struct rip_info *rinfo)
paul718e3742002-12-13 20:15:29 +00002106{
2107 struct in_addr mask;
paul718e3742002-12-13 20:15:29 +00002108
2109 /* Write routing table entry. */
2110 if (version == RIPv1)
2111 {
2112 stream_putw (s, AF_INET);
2113 stream_putw (s, 0);
2114 stream_put_ipv4 (s, p->prefix.s_addr);
2115 stream_put_ipv4 (s, 0);
2116 stream_put_ipv4 (s, 0);
2117 stream_putl (s, rinfo->metric_out);
2118 }
2119 else
2120 {
2121 masklen2ip (p->prefixlen, &mask);
2122
2123 stream_putw (s, AF_INET);
hasso16705132003-05-25 14:49:19 +00002124 stream_putw (s, rinfo->tag_out);
paul718e3742002-12-13 20:15:29 +00002125 stream_put_ipv4 (s, p->prefix.s_addr);
2126 stream_put_ipv4 (s, mask.s_addr);
2127 stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
2128 stream_putl (s, rinfo->metric_out);
2129 }
2130
2131 return ++num;
2132}
2133
2134/* Send update to the ifp or spcified neighbor. */
2135void
paulc49ad8f2004-10-22 10:27:28 +00002136rip_output_process (struct connected *ifc, struct sockaddr_in *to,
2137 int route_type, u_char version)
paul718e3742002-12-13 20:15:29 +00002138{
2139 int ret;
2140 struct stream *s;
2141 struct route_node *rp;
2142 struct rip_info *rinfo;
2143 struct rip_interface *ri;
2144 struct prefix_ipv4 *p;
2145 struct prefix_ipv4 classfull;
paul727d1042002-12-13 20:50:29 +00002146 struct prefix_ipv4 ifaddrclass;
paulb14ee002005-02-04 23:42:41 +00002147 struct key *key = NULL;
2148 /* this might need to made dynamic if RIP ever supported auth methods
2149 with larger key string sizes */
2150 char auth_str[RIP_AUTH_SIMPLE_SIZE];
pauldc63bfd2005-10-25 23:31:05 +00002151 size_t doff = 0; /* offset of digest offset field */
paul2c61ae32005-08-16 15:22:14 +00002152 int num = 0;
paul718e3742002-12-13 20:15:29 +00002153 int rtemax;
paul01d09082003-06-08 21:22:18 +00002154 int subnetted = 0;
paul718e3742002-12-13 20:15:29 +00002155
2156 /* Logging output event. */
2157 if (IS_RIP_DEBUG_EVENT)
2158 {
2159 if (to)
ajs5d6c3772004-12-08 19:24:06 +00002160 zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
paul718e3742002-12-13 20:15:29 +00002161 else
ajs5d6c3772004-12-08 19:24:06 +00002162 zlog_debug ("update routes on interface %s ifindex %d",
paulc49ad8f2004-10-22 10:27:28 +00002163 ifc->ifp->name, ifc->ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002164 }
2165
2166 /* Set output stream. */
2167 s = rip->obuf;
2168
2169 /* Reset stream and RTE counter. */
2170 stream_reset (s);
paul718e3742002-12-13 20:15:29 +00002171 rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
2172
2173 /* Get RIP interface. */
paulc49ad8f2004-10-22 10:27:28 +00002174 ri = ifc->ifp->info;
paul718e3742002-12-13 20:15:29 +00002175
2176 /* If output interface is in simple password authentication mode, we
2177 need space for authentication data. */
2178 if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
2179 rtemax -= 1;
2180
2181 /* If output interface is in MD5 authentication mode, we need space
2182 for authentication header and data. */
2183 if (ri->auth_type == RIP_AUTH_MD5)
2184 rtemax -= 2;
2185
2186 /* If output interface is in simple password authentication mode
2187 and string or keychain is specified we need space for auth. data */
paulb14ee002005-02-04 23:42:41 +00002188 if (ri->auth_type != RIP_NO_AUTH)
paul718e3742002-12-13 20:15:29 +00002189 {
2190 if (ri->key_chain)
2191 {
2192 struct keychain *keychain;
2193
2194 keychain = keychain_lookup (ri->key_chain);
2195 if (keychain)
paulb14ee002005-02-04 23:42:41 +00002196 key = key_lookup_for_send (keychain);
paul718e3742002-12-13 20:15:29 +00002197 }
paulb14ee002005-02-04 23:42:41 +00002198 /* to be passed to auth functions later */
2199 rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002200 }
2201
paul727d1042002-12-13 20:50:29 +00002202 if (version == RIPv1)
2203 {
paulc49ad8f2004-10-22 10:27:28 +00002204 memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
paul727d1042002-12-13 20:50:29 +00002205 apply_classful_mask_ipv4 (&ifaddrclass);
2206 subnetted = 0;
paulc49ad8f2004-10-22 10:27:28 +00002207 if (ifc->address->prefixlen > ifaddrclass.prefixlen)
paul01d09082003-06-08 21:22:18 +00002208 subnetted = 1;
paul727d1042002-12-13 20:50:29 +00002209 }
2210
paul718e3742002-12-13 20:15:29 +00002211 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2212 if ((rinfo = rp->info) != NULL)
2213 {
paul727d1042002-12-13 20:50:29 +00002214 /* For RIPv1, if we are subnetted, output subnets in our network */
2215 /* that have the same mask as the output "interface". For other */
2216 /* networks, only the classfull version is output. */
paul718e3742002-12-13 20:15:29 +00002217
2218 if (version == RIPv1)
2219 {
paul727d1042002-12-13 20:50:29 +00002220 p = (struct prefix_ipv4 *) &rp->p;
paul718e3742002-12-13 20:15:29 +00002221
2222 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002223 zlog_debug("RIPv1 mask check, %s/%d considered for output",
paul727d1042002-12-13 20:50:29 +00002224 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002225
paul727d1042002-12-13 20:50:29 +00002226 if (subnetted &&
2227 prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
2228 {
paulc49ad8f2004-10-22 10:27:28 +00002229 if ((ifc->address->prefixlen != rp->p.prefixlen) &&
paul727d1042002-12-13 20:50:29 +00002230 (rp->p.prefixlen != 32))
2231 continue;
2232 }
2233 else
2234 {
2235 memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
2236 apply_classful_mask_ipv4(&classfull);
2237 if (rp->p.u.prefix4.s_addr != 0 &&
2238 classfull.prefixlen != rp->p.prefixlen)
2239 continue;
2240 }
paul718e3742002-12-13 20:15:29 +00002241 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002242 zlog_debug("RIPv1 mask check, %s/%d made it through",
paul727d1042002-12-13 20:50:29 +00002243 inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
paul718e3742002-12-13 20:15:29 +00002244 }
2245 else
2246 p = (struct prefix_ipv4 *) &rp->p;
2247
2248 /* Apply output filters. */
2249 ret = rip_outgoing_filter (p, ri);
2250 if (ret < 0)
2251 continue;
2252
2253 /* Changed route only output. */
2254 if (route_type == rip_changed_route &&
2255 (! (rinfo->flags & RIP_RTF_CHANGED)))
2256 continue;
2257
2258 /* Split horizon. */
2259 /* if (split_horizon == rip_split_horizon) */
hasso16705132003-05-25 14:49:19 +00002260 if (ri->split_horizon == RIP_SPLIT_HORIZON)
paul718e3742002-12-13 20:15:29 +00002261 {
paul42d14d92003-11-17 09:15:18 +00002262 /*
2263 * We perform split horizon for RIP and connected route.
2264 * For rip routes, we want to suppress the route if we would
2265 * end up sending the route back on the interface that we
2266 * learned it from, with a higher metric. For connected routes,
2267 * we suppress the route if the prefix is a subset of the
2268 * source address that we are going to use for the packet
2269 * (in order to handle the case when multiple subnets are
2270 * configured on the same interface).
2271 */
2272 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002273 rinfo->ifindex == ifc->ifp->ifindex)
paul42d14d92003-11-17 09:15:18 +00002274 continue;
2275 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002276 prefix_match((struct prefix *)p, ifc->address))
paul718e3742002-12-13 20:15:29 +00002277 continue;
2278 }
2279
2280 /* Preparation for route-map. */
2281 rinfo->metric_set = 0;
2282 rinfo->nexthop_out.s_addr = 0;
2283 rinfo->metric_out = rinfo->metric;
hasso16705132003-05-25 14:49:19 +00002284 rinfo->tag_out = rinfo->tag;
paulc49ad8f2004-10-22 10:27:28 +00002285 rinfo->ifindex_out = ifc->ifp->ifindex;
paul718e3742002-12-13 20:15:29 +00002286
hasso16705132003-05-25 14:49:19 +00002287 /* In order to avoid some local loops,
2288 * if the RIP route has a nexthop via this interface, keep the nexthop,
2289 * otherwise set it to 0. The nexthop should not be propagated
2290 * beyond the local broadcast/multicast area in order
2291 * to avoid an IGP multi-level recursive look-up.
2292 * see (4.4)
2293 */
paulc49ad8f2004-10-22 10:27:28 +00002294 if (rinfo->ifindex == ifc->ifp->ifindex)
paul718e3742002-12-13 20:15:29 +00002295 rinfo->nexthop_out = rinfo->nexthop;
hasso16705132003-05-25 14:49:19 +00002296
2297 /* Interface route-map */
2298 if (ri->routemap[RIP_FILTER_OUT])
2299 {
2300 ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
2301 (struct prefix *) p, RMAP_RIP,
2302 rinfo);
2303
2304 if (ret == RMAP_DENYMATCH)
2305 {
2306 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002307 zlog_debug ("RIP %s/%d is filtered by route-map out",
hasso16705132003-05-25 14:49:19 +00002308 inet_ntoa (p->prefix), p->prefixlen);
2309 continue;
2310 }
2311 }
paul718e3742002-12-13 20:15:29 +00002312
hasso16705132003-05-25 14:49:19 +00002313 /* Apply redistribute route map - continue, if deny */
paul718e3742002-12-13 20:15:29 +00002314 if (rip->route_map[rinfo->type].name
2315 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2316 {
2317 ret = route_map_apply (rip->route_map[rinfo->type].map,
2318 (struct prefix *)p, RMAP_RIP, rinfo);
2319
2320 if (ret == RMAP_DENYMATCH)
2321 {
2322 if (IS_RIP_DEBUG_PACKET)
ajs5d6c3772004-12-08 19:24:06 +00002323 zlog_debug ("%s/%d is filtered by route-map",
paul718e3742002-12-13 20:15:29 +00002324 inet_ntoa (p->prefix), p->prefixlen);
2325 continue;
2326 }
2327 }
2328
2329 /* When route-map does not set metric. */
2330 if (! rinfo->metric_set)
2331 {
2332 /* If redistribute metric is set. */
2333 if (rip->route_map[rinfo->type].metric_config
2334 && rinfo->metric != RIP_METRIC_INFINITY)
2335 {
2336 rinfo->metric_out = rip->route_map[rinfo->type].metric;
2337 }
2338 else
2339 {
2340 /* If the route is not connected or localy generated
2341 one, use default-metric value*/
2342 if (rinfo->type != ZEBRA_ROUTE_RIP
2343 && rinfo->type != ZEBRA_ROUTE_CONNECT
2344 && rinfo->metric != RIP_METRIC_INFINITY)
2345 rinfo->metric_out = rip->default_metric;
2346 }
2347 }
2348
2349 /* Apply offset-list */
2350 if (rinfo->metric != RIP_METRIC_INFINITY)
paulc49ad8f2004-10-22 10:27:28 +00002351 rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00002352
2353 if (rinfo->metric_out > RIP_METRIC_INFINITY)
2354 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002355
2356 /* Perform split-horizon with poisoned reverse
2357 * for RIP and connected routes.
2358 **/
2359 if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
paul42d14d92003-11-17 09:15:18 +00002360 /*
2361 * We perform split horizon for RIP and connected route.
2362 * For rip routes, we want to suppress the route if we would
2363 * end up sending the route back on the interface that we
2364 * learned it from, with a higher metric. For connected routes,
2365 * we suppress the route if the prefix is a subset of the
2366 * source address that we are going to use for the packet
2367 * (in order to handle the case when multiple subnets are
2368 * configured on the same interface).
2369 */
2370 if (rinfo->type == ZEBRA_ROUTE_RIP &&
paulc49ad8f2004-10-22 10:27:28 +00002371 rinfo->ifindex == ifc->ifp->ifindex)
hasso16705132003-05-25 14:49:19 +00002372 rinfo->metric_out = RIP_METRIC_INFINITY;
paul42d14d92003-11-17 09:15:18 +00002373 if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
paulc49ad8f2004-10-22 10:27:28 +00002374 prefix_match((struct prefix *)p, ifc->address))
paul42d14d92003-11-17 09:15:18 +00002375 rinfo->metric_out = RIP_METRIC_INFINITY;
hasso16705132003-05-25 14:49:19 +00002376 }
paulb14ee002005-02-04 23:42:41 +00002377
2378 /* Prepare preamble, auth headers, if needs be */
2379 if (num == 0)
2380 {
2381 stream_putc (s, RIP_RESPONSE);
2382 stream_putc (s, version);
2383 stream_putw (s, 0);
2384
paul0cb8a012005-05-29 11:27:24 +00002385 /* auth header for !v1 && !no_auth */
2386 if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
paulb14ee002005-02-04 23:42:41 +00002387 doff = rip_auth_header_write (s, ri, key, auth_str,
2388 RIP_AUTH_SIMPLE_SIZE);
2389 }
2390
paul718e3742002-12-13 20:15:29 +00002391 /* Write RTE to the stream. */
paulb14ee002005-02-04 23:42:41 +00002392 num = rip_write_rte (num, s, p, version, rinfo);
paul718e3742002-12-13 20:15:29 +00002393 if (num == rtemax)
2394 {
2395 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002396 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002397
2398 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
paulc49ad8f2004-10-22 10:27:28 +00002399 to, ifc);
paul718e3742002-12-13 20:15:29 +00002400
2401 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2402 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2403 stream_get_endp(s), "SEND");
2404 num = 0;
2405 stream_reset (s);
2406 }
2407 }
2408
2409 /* Flush unwritten RTE. */
2410 if (num != 0)
2411 {
2412 if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
paulb14ee002005-02-04 23:42:41 +00002413 rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
paul718e3742002-12-13 20:15:29 +00002414
paulc49ad8f2004-10-22 10:27:28 +00002415 ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
paul718e3742002-12-13 20:15:29 +00002416
2417 if (ret >= 0 && IS_RIP_DEBUG_SEND)
2418 rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
2419 stream_get_endp (s), "SEND");
2420 num = 0;
2421 stream_reset (s);
2422 }
2423
2424 /* Statistics updates. */
2425 ri->sent_updates++;
2426}
2427
2428/* Send RIP packet to the interface. */
pauldc63bfd2005-10-25 23:31:05 +00002429static void
paulc49ad8f2004-10-22 10:27:28 +00002430rip_update_interface (struct connected *ifc, u_char version, int route_type)
paul718e3742002-12-13 20:15:29 +00002431{
paul718e3742002-12-13 20:15:29 +00002432 struct sockaddr_in to;
2433
2434 /* When RIP version is 2 and multicast enable interface. */
paulc49ad8f2004-10-22 10:27:28 +00002435 if (version == RIPv2 && if_is_multicast (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002436 {
2437 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002438 zlog_debug ("multicast announce on %s ", ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002439
paulc49ad8f2004-10-22 10:27:28 +00002440 rip_output_process (ifc, NULL, route_type, version);
paul718e3742002-12-13 20:15:29 +00002441 return;
2442 }
paulc49ad8f2004-10-22 10:27:28 +00002443
paul718e3742002-12-13 20:15:29 +00002444 /* If we can't send multicast packet, send it with unicast. */
paulc49ad8f2004-10-22 10:27:28 +00002445 if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
paul718e3742002-12-13 20:15:29 +00002446 {
paulc49ad8f2004-10-22 10:27:28 +00002447 if (ifc->address->family == AF_INET)
2448 {
2449 /* Destination address and port setting. */
2450 memset (&to, 0, sizeof (struct sockaddr_in));
2451 if (ifc->destination)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002452 /* use specified broadcast or peer destination addr */
paulc49ad8f2004-10-22 10:27:28 +00002453 to.sin_addr = ifc->destination->u.prefix4;
Andrew J. Schorre4529632006-12-12 19:18:21 +00002454 else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
paulc49ad8f2004-10-22 10:27:28 +00002455 /* calculate the appropriate broadcast address */
2456 to.sin_addr.s_addr =
2457 ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
2458 ifc->address->prefixlen);
Andrew J. Schorre4529632006-12-12 19:18:21 +00002459 else
2460 /* do not know where to send the packet */
2461 return;
paulc49ad8f2004-10-22 10:27:28 +00002462 to.sin_port = htons (RIP_PORT_DEFAULT);
paul718e3742002-12-13 20:15:29 +00002463
paulc49ad8f2004-10-22 10:27:28 +00002464 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorre4529632006-12-12 19:18:21 +00002465 zlog_debug("%s announce to %s on %s",
2466 CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
2467 inet_ntoa (to.sin_addr), ifc->ifp->name);
paul718e3742002-12-13 20:15:29 +00002468
paulc49ad8f2004-10-22 10:27:28 +00002469 rip_output_process (ifc, &to, route_type, version);
2470 }
paul718e3742002-12-13 20:15:29 +00002471 }
2472}
2473
2474/* Update send to all interface and neighbor. */
pauldc63bfd2005-10-25 23:31:05 +00002475static void
paul718e3742002-12-13 20:15:29 +00002476rip_update_process (int route_type)
2477{
paul1eb8ef22005-04-07 07:30:20 +00002478 struct listnode *node;
2479 struct listnode *ifnode, *ifnnode;
paulcc1131a2003-10-15 23:20:17 +00002480 struct connected *connected;
paul718e3742002-12-13 20:15:29 +00002481 struct interface *ifp;
2482 struct rip_interface *ri;
2483 struct route_node *rp;
2484 struct sockaddr_in to;
2485 struct prefix_ipv4 *p;
2486
2487 /* Send RIP update to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00002488 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00002489 {
paul718e3742002-12-13 20:15:29 +00002490 if (if_is_loopback (ifp))
2491 continue;
2492
paul2e3b2e42002-12-13 21:03:13 +00002493 if (! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +00002494 continue;
2495
2496 /* Fetch RIP interface information. */
2497 ri = ifp->info;
2498
2499 /* When passive interface is specified, suppress announce to the
2500 interface. */
2501 if (ri->passive)
2502 continue;
2503
2504 if (ri->running)
2505 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002506 /*
2507 * If there is no version configuration in the interface,
2508 * use rip's version setting.
2509 */
2510 int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
2511 rip->version_send : ri->ri_send);
2512
paul718e3742002-12-13 20:15:29 +00002513 if (IS_RIP_DEBUG_EVENT)
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002514 zlog_debug("SEND UPDATE to %s ifindex %d",
2515 (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
paul718e3742002-12-13 20:15:29 +00002516
paulcc1131a2003-10-15 23:20:17 +00002517 /* send update on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002518 for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002519 {
Andrew J. Schorrb9d92882006-04-28 16:22:36 +00002520 if (connected->address->family == AF_INET)
2521 {
2522 if (vsend & RIPv1)
2523 rip_update_interface (connected, RIPv1, route_type);
2524 if ((vsend & RIPv2) && if_is_multicast(ifp))
2525 rip_update_interface (connected, RIPv2, route_type);
2526 }
2527 }
paul718e3742002-12-13 20:15:29 +00002528 }
2529 }
2530
2531 /* RIP send updates to each neighbor. */
2532 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
2533 if (rp->info != NULL)
2534 {
2535 p = (struct prefix_ipv4 *) &rp->p;
2536
2537 ifp = if_lookup_address (p->prefix);
2538 if (! ifp)
2539 {
paulc49ad8f2004-10-22 10:27:28 +00002540 zlog_warn ("Neighbor %s doesnt have connected interface!",
paul718e3742002-12-13 20:15:29 +00002541 inet_ntoa (p->prefix));
2542 continue;
2543 }
paulc49ad8f2004-10-22 10:27:28 +00002544
2545 if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
2546 {
2547 zlog_warn ("Neighbor %s doesnt have connected network",
2548 inet_ntoa (p->prefix));
2549 continue;
2550 }
2551
paul718e3742002-12-13 20:15:29 +00002552 /* Set destination address and port */
2553 memset (&to, 0, sizeof (struct sockaddr_in));
2554 to.sin_addr = p->prefix;
2555 to.sin_port = htons (RIP_PORT_DEFAULT);
2556
2557 /* RIP version is rip's configuration. */
paulc49ad8f2004-10-22 10:27:28 +00002558 rip_output_process (connected, &to, route_type, rip->version_send);
paul718e3742002-12-13 20:15:29 +00002559 }
2560}
2561
2562/* RIP's periodical timer. */
pauldc63bfd2005-10-25 23:31:05 +00002563static int
paul718e3742002-12-13 20:15:29 +00002564rip_update (struct thread *t)
2565{
2566 /* Clear timer pointer. */
2567 rip->t_update = NULL;
2568
2569 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002570 zlog_debug ("update timer fire!");
paul718e3742002-12-13 20:15:29 +00002571
2572 /* Process update output. */
2573 rip_update_process (rip_all_route);
2574
2575 /* Triggered updates may be suppressed if a regular update is due by
2576 the time the triggered update would be sent. */
2577 if (rip->t_triggered_interval)
2578 {
2579 thread_cancel (rip->t_triggered_interval);
2580 rip->t_triggered_interval = NULL;
2581 }
2582 rip->trigger = 0;
2583
2584 /* Register myself. */
2585 rip_event (RIP_UPDATE_EVENT, 0);
2586
2587 return 0;
2588}
2589
2590/* Walk down the RIP routing table then clear changed flag. */
pauldc63bfd2005-10-25 23:31:05 +00002591static void
paul216565a2005-10-25 23:35:28 +00002592rip_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00002593{
2594 struct route_node *rp;
2595 struct rip_info *rinfo;
2596
2597 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2598 if ((rinfo = rp->info) != NULL)
2599 if (rinfo->flags & RIP_RTF_CHANGED)
2600 rinfo->flags &= ~RIP_RTF_CHANGED;
2601}
2602
2603/* Triggered update interval timer. */
pauldc63bfd2005-10-25 23:31:05 +00002604static int
paul718e3742002-12-13 20:15:29 +00002605rip_triggered_interval (struct thread *t)
2606{
2607 int rip_triggered_update (struct thread *);
2608
2609 rip->t_triggered_interval = NULL;
2610
2611 if (rip->trigger)
2612 {
2613 rip->trigger = 0;
2614 rip_triggered_update (t);
2615 }
2616 return 0;
2617}
2618
2619/* Execute triggered update. */
pauldc63bfd2005-10-25 23:31:05 +00002620static int
paul718e3742002-12-13 20:15:29 +00002621rip_triggered_update (struct thread *t)
2622{
2623 int interval;
2624
2625 /* Clear thred pointer. */
2626 rip->t_triggered_update = NULL;
2627
2628 /* Cancel interval timer. */
2629 if (rip->t_triggered_interval)
2630 {
2631 thread_cancel (rip->t_triggered_interval);
2632 rip->t_triggered_interval = NULL;
2633 }
2634 rip->trigger = 0;
2635
2636 /* Logging triggered update. */
2637 if (IS_RIP_DEBUG_EVENT)
ajs5d6c3772004-12-08 19:24:06 +00002638 zlog_debug ("triggered update!");
paul718e3742002-12-13 20:15:29 +00002639
2640 /* Split Horizon processing is done when generating triggered
2641 updates as well as normal updates (see section 2.6). */
2642 rip_update_process (rip_changed_route);
2643
2644 /* Once all of the triggered updates have been generated, the route
2645 change flags should be cleared. */
2646 rip_clear_changed_flag ();
2647
2648 /* After a triggered update is sent, a timer should be set for a
2649 random interval between 1 and 5 seconds. If other changes that
2650 would trigger updates occur before the timer expires, a single
2651 update is triggered when the timer expires. */
2652 interval = (random () % 5) + 1;
2653
2654 rip->t_triggered_interval =
2655 thread_add_timer (master, rip_triggered_interval, NULL, interval);
2656
2657 return 0;
2658}
2659
2660/* Withdraw redistributed route. */
2661void
2662rip_redistribute_withdraw (int type)
2663{
2664 struct route_node *rp;
2665 struct rip_info *rinfo;
2666
2667 if (!rip)
2668 return;
2669
2670 for (rp = route_top (rip->table); rp; rp = route_next (rp))
2671 if ((rinfo = rp->info) != NULL)
2672 {
2673 if (rinfo->type == type
2674 && rinfo->sub_type != RIP_ROUTE_INTERFACE)
2675 {
2676 /* Perform poisoned reverse. */
2677 rinfo->metric = RIP_METRIC_INFINITY;
2678 RIP_TIMER_ON (rinfo->t_garbage_collect,
2679 rip_garbage_collect, rip->garbage_time);
2680 RIP_TIMER_OFF (rinfo->t_timeout);
2681 rinfo->flags |= RIP_RTF_CHANGED;
2682
hasso16705132003-05-25 14:49:19 +00002683 if (IS_RIP_DEBUG_EVENT) {
2684 struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
2685
ajs5d6c3772004-12-08 19:24:06 +00002686 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
hasso16705132003-05-25 14:49:19 +00002687 inet_ntoa(p->prefix), p->prefixlen,
2688 ifindex2ifname(rinfo->ifindex));
2689 }
2690
paul718e3742002-12-13 20:15:29 +00002691 rip_event (RIP_TRIGGERED_UPDATE, 0);
2692 }
2693 }
2694}
2695
2696/* Create new RIP instance and set it to global variable. */
pauldc63bfd2005-10-25 23:31:05 +00002697static int
2698rip_create (void)
paul718e3742002-12-13 20:15:29 +00002699{
2700 rip = XMALLOC (MTYPE_RIP, sizeof (struct rip));
2701 memset (rip, 0, sizeof (struct rip));
2702
2703 /* Set initial value. */
paulf38a4712003-06-07 01:10:00 +00002704 rip->version_send = RI_RIP_VERSION_2;
2705 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002706 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
2707 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
2708 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
2709 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
2710
2711 /* Initialize RIP routig table. */
2712 rip->table = route_table_init ();
2713 rip->route = route_table_init ();
2714 rip->neighbor = route_table_init ();
2715
2716 /* Make output stream. */
2717 rip->obuf = stream_new (1500);
2718
2719 /* Make socket. */
paulf69bd9d2005-06-03 18:01:50 +00002720 rip->sock = rip_create_socket (NULL);
paul718e3742002-12-13 20:15:29 +00002721 if (rip->sock < 0)
2722 return rip->sock;
2723
2724 /* Create read and timer thread. */
2725 rip_event (RIP_READ, rip->sock);
2726 rip_event (RIP_UPDATE_EVENT, 1);
2727
2728 return 0;
2729}
2730
2731/* Sned RIP request to the destination. */
2732int
2733rip_request_send (struct sockaddr_in *to, struct interface *ifp,
paul931cd542004-01-23 15:31:42 +00002734 u_char version, struct connected *connected)
paul718e3742002-12-13 20:15:29 +00002735{
2736 struct rte *rte;
2737 struct rip_packet rip_packet;
paul1eb8ef22005-04-07 07:30:20 +00002738 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00002739
2740 memset (&rip_packet, 0, sizeof (rip_packet));
2741
2742 rip_packet.command = RIP_REQUEST;
2743 rip_packet.version = version;
2744 rte = rip_packet.rte;
2745 rte->metric = htonl (RIP_METRIC_INFINITY);
2746
paul931cd542004-01-23 15:31:42 +00002747 if (connected)
2748 {
2749 /*
2750 * connected is only sent for ripv1 case, or when
2751 * interface does not support multicast. Caller loops
2752 * over each connected address for this case.
2753 */
paul11dde9c2004-05-31 14:00:00 +00002754 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002755 to, connected) != sizeof (rip_packet))
paul931cd542004-01-23 15:31:42 +00002756 return -1;
2757 else
2758 return sizeof (rip_packet);
2759 }
2760
paulcc1131a2003-10-15 23:20:17 +00002761 /* send request on each connected network */
paul1eb8ef22005-04-07 07:30:20 +00002762 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
paulcc1131a2003-10-15 23:20:17 +00002763 {
2764 struct prefix_ipv4 *p;
2765
2766 p = (struct prefix_ipv4 *) connected->address;
2767
2768 if (p->family != AF_INET)
2769 continue;
2770
paul11dde9c2004-05-31 14:00:00 +00002771 if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
paulc49ad8f2004-10-22 10:27:28 +00002772 to, connected) != sizeof (rip_packet))
paulcc1131a2003-10-15 23:20:17 +00002773 return -1;
2774 }
2775 return sizeof (rip_packet);
paul718e3742002-12-13 20:15:29 +00002776}
2777
pauldc63bfd2005-10-25 23:31:05 +00002778static int
paul718e3742002-12-13 20:15:29 +00002779rip_update_jitter (unsigned long time)
2780{
paul239389b2004-05-05 14:09:37 +00002781#define JITTER_BOUND 4
2782 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
2783 Given that, we cannot let time be less than JITTER_BOUND seconds.
2784 The RIPv2 RFC says jitter should be small compared to
2785 update_time. We consider 1/JITTER_BOUND to be small.
2786 */
2787
2788 int jitter_input = time;
2789 int jitter;
2790
2791 if (jitter_input < JITTER_BOUND)
2792 jitter_input = JITTER_BOUND;
2793
2794 jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
2795
2796 return jitter/JITTER_BOUND;
paul718e3742002-12-13 20:15:29 +00002797}
2798
2799void
2800rip_event (enum rip_event event, int sock)
2801{
2802 int jitter = 0;
2803
2804 switch (event)
2805 {
2806 case RIP_READ:
2807 rip->t_read = thread_add_read (master, rip_read, NULL, sock);
2808 break;
2809 case RIP_UPDATE_EVENT:
2810 if (rip->t_update)
2811 {
2812 thread_cancel (rip->t_update);
2813 rip->t_update = NULL;
2814 }
2815 jitter = rip_update_jitter (rip->update_time);
2816 rip->t_update =
2817 thread_add_timer (master, rip_update, NULL,
2818 sock ? 2 : rip->update_time + jitter);
2819 break;
2820 case RIP_TRIGGERED_UPDATE:
2821 if (rip->t_triggered_interval)
2822 rip->trigger = 1;
2823 else if (! rip->t_triggered_update)
2824 rip->t_triggered_update =
2825 thread_add_event (master, rip_triggered_update, NULL, 0);
2826 break;
2827 default:
2828 break;
2829 }
2830}
2831
2832DEFUN (router_rip,
2833 router_rip_cmd,
2834 "router rip",
2835 "Enable a routing process\n"
2836 "Routing Information Protocol (RIP)\n")
2837{
2838 int ret;
2839
2840 /* If rip is not enabled before. */
2841 if (! rip)
2842 {
2843 ret = rip_create ();
2844 if (ret < 0)
2845 {
2846 zlog_info ("Can't create RIP");
2847 return CMD_WARNING;
2848 }
2849 }
2850 vty->node = RIP_NODE;
2851 vty->index = rip;
2852
2853 return CMD_SUCCESS;
2854}
2855
2856DEFUN (no_router_rip,
2857 no_router_rip_cmd,
2858 "no router rip",
2859 NO_STR
2860 "Enable a routing process\n"
2861 "Routing Information Protocol (RIP)\n")
2862{
2863 if (rip)
2864 rip_clean ();
2865 return CMD_SUCCESS;
2866}
2867
2868DEFUN (rip_version,
2869 rip_version_cmd,
2870 "version <1-2>",
2871 "Set routing protocol version\n"
2872 "version\n")
2873{
2874 int version;
2875
2876 version = atoi (argv[0]);
2877 if (version != RIPv1 && version != RIPv2)
2878 {
2879 vty_out (vty, "invalid rip version %d%s", version,
2880 VTY_NEWLINE);
2881 return CMD_WARNING;
2882 }
paulf38a4712003-06-07 01:10:00 +00002883 rip->version_send = version;
2884 rip->version_recv = version;
paul718e3742002-12-13 20:15:29 +00002885
2886 return CMD_SUCCESS;
2887}
2888
2889DEFUN (no_rip_version,
2890 no_rip_version_cmd,
2891 "no version",
2892 NO_STR
2893 "Set routing protocol version\n")
2894{
2895 /* Set RIP version to the default. */
paulf38a4712003-06-07 01:10:00 +00002896 rip->version_send = RI_RIP_VERSION_2;
2897 rip->version_recv = RI_RIP_VERSION_1_AND_2;
paul718e3742002-12-13 20:15:29 +00002898
2899 return CMD_SUCCESS;
2900}
2901
2902ALIAS (no_rip_version,
2903 no_rip_version_val_cmd,
2904 "no version <1-2>",
2905 NO_STR
2906 "Set routing protocol version\n"
2907 "version\n")
2908
2909DEFUN (rip_route,
2910 rip_route_cmd,
2911 "route A.B.C.D/M",
2912 "RIP static route configuration\n"
2913 "IP prefix <network>/<length>\n")
2914{
2915 int ret;
2916 struct prefix_ipv4 p;
2917 struct route_node *node;
2918
2919 ret = str2prefix_ipv4 (argv[0], &p);
2920 if (ret < 0)
2921 {
2922 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2923 return CMD_WARNING;
2924 }
2925 apply_mask_ipv4 (&p);
2926
2927 /* For router rip configuration. */
2928 node = route_node_get (rip->route, (struct prefix *) &p);
2929
2930 if (node->info)
2931 {
2932 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2933 route_unlock_node (node);
2934 return CMD_WARNING;
2935 }
2936
hasso8a676be2004-10-08 06:36:38 +00002937 node->info = (char *)"static";
paul718e3742002-12-13 20:15:29 +00002938
vincentfbf5d032005-09-29 11:25:50 +00002939 rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
paul718e3742002-12-13 20:15:29 +00002940
2941 return CMD_SUCCESS;
2942}
2943
2944DEFUN (no_rip_route,
2945 no_rip_route_cmd,
2946 "no route A.B.C.D/M",
2947 NO_STR
2948 "RIP static route configuration\n"
2949 "IP prefix <network>/<length>\n")
2950{
2951 int ret;
2952 struct prefix_ipv4 p;
2953 struct route_node *node;
2954
2955 ret = str2prefix_ipv4 (argv[0], &p);
2956 if (ret < 0)
2957 {
2958 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2959 return CMD_WARNING;
2960 }
2961 apply_mask_ipv4 (&p);
2962
2963 /* For router rip configuration. */
2964 node = route_node_lookup (rip->route, (struct prefix *) &p);
2965 if (! node)
2966 {
2967 vty_out (vty, "Can't find route %s.%s", argv[0],
2968 VTY_NEWLINE);
2969 return CMD_WARNING;
2970 }
2971
2972 rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
2973 route_unlock_node (node);
2974
2975 node->info = NULL;
2976 route_unlock_node (node);
2977
2978 return CMD_SUCCESS;
2979}
2980
pauldc63bfd2005-10-25 23:31:05 +00002981static void
paul216565a2005-10-25 23:35:28 +00002982rip_update_default_metric (void)
paul718e3742002-12-13 20:15:29 +00002983{
2984 struct route_node *np;
2985 struct rip_info *rinfo;
2986
2987 for (np = route_top (rip->table); np; np = route_next (np))
2988 if ((rinfo = np->info) != NULL)
2989 if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
2990 rinfo->metric = rip->default_metric;
2991}
2992
2993DEFUN (rip_default_metric,
2994 rip_default_metric_cmd,
2995 "default-metric <1-16>",
2996 "Set a metric of redistribute routes\n"
2997 "Default metric\n")
2998{
2999 if (rip)
3000 {
3001 rip->default_metric = atoi (argv[0]);
3002 /* rip_update_default_metric (); */
3003 }
3004 return CMD_SUCCESS;
3005}
3006
3007DEFUN (no_rip_default_metric,
3008 no_rip_default_metric_cmd,
3009 "no default-metric",
3010 NO_STR
3011 "Set a metric of redistribute routes\n"
3012 "Default metric\n")
3013{
3014 if (rip)
3015 {
3016 rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
3017 /* rip_update_default_metric (); */
3018 }
3019 return CMD_SUCCESS;
3020}
3021
3022ALIAS (no_rip_default_metric,
3023 no_rip_default_metric_val_cmd,
3024 "no default-metric <1-16>",
3025 NO_STR
3026 "Set a metric of redistribute routes\n"
3027 "Default metric\n")
3028
3029DEFUN (rip_timers,
3030 rip_timers_cmd,
3031 "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
3032 "Adjust routing timers\n"
3033 "Basic routing protocol update timers\n"
3034 "Routing table update timer value in second. Default is 30.\n"
3035 "Routing information timeout timer. Default is 180.\n"
3036 "Garbage collection timer. Default is 120.\n")
3037{
3038 unsigned long update;
3039 unsigned long timeout;
3040 unsigned long garbage;
3041 char *endptr = NULL;
3042 unsigned long RIP_TIMER_MAX = 2147483647;
3043 unsigned long RIP_TIMER_MIN = 5;
3044
3045 update = strtoul (argv[0], &endptr, 10);
3046 if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
3047 {
3048 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
3049 return CMD_WARNING;
3050 }
3051
3052 timeout = strtoul (argv[1], &endptr, 10);
3053 if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
3054 {
3055 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
3056 return CMD_WARNING;
3057 }
3058
3059 garbage = strtoul (argv[2], &endptr, 10);
3060 if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
3061 {
3062 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
3063 return CMD_WARNING;
3064 }
3065
3066 /* Set each timer value. */
3067 rip->update_time = update;
3068 rip->timeout_time = timeout;
3069 rip->garbage_time = garbage;
3070
3071 /* Reset update timer thread. */
3072 rip_event (RIP_UPDATE_EVENT, 0);
3073
3074 return CMD_SUCCESS;
3075}
3076
3077DEFUN (no_rip_timers,
3078 no_rip_timers_cmd,
3079 "no timers basic",
3080 NO_STR
3081 "Adjust routing timers\n"
3082 "Basic routing protocol update timers\n")
3083{
3084 /* Set each timer value to the default. */
3085 rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
3086 rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
3087 rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
3088
3089 /* Reset update timer thread. */
3090 rip_event (RIP_UPDATE_EVENT, 0);
3091
3092 return CMD_SUCCESS;
3093}
hasso16705132003-05-25 14:49:19 +00003094
3095ALIAS (no_rip_timers,
3096 no_rip_timers_val_cmd,
3097 "no timers basic <0-65535> <0-65535> <0-65535>",
3098 NO_STR
3099 "Adjust routing timers\n"
3100 "Basic routing protocol update timers\n"
3101 "Routing table update timer value in second. Default is 30.\n"
3102 "Routing information timeout timer. Default is 180.\n"
3103 "Garbage collection timer. Default is 120.\n")
3104
paul718e3742002-12-13 20:15:29 +00003105
3106struct route_table *rip_distance_table;
3107
3108struct rip_distance
3109{
3110 /* Distance value for the IP source prefix. */
3111 u_char distance;
3112
3113 /* Name of the access-list to be matched. */
3114 char *access_list;
3115};
3116
pauldc63bfd2005-10-25 23:31:05 +00003117static struct rip_distance *
paul216565a2005-10-25 23:35:28 +00003118rip_distance_new (void)
paul718e3742002-12-13 20:15:29 +00003119{
3120 struct rip_distance *new;
3121 new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
3122 memset (new, 0, sizeof (struct rip_distance));
3123 return new;
3124}
3125
pauldc63bfd2005-10-25 23:31:05 +00003126static void
paul718e3742002-12-13 20:15:29 +00003127rip_distance_free (struct rip_distance *rdistance)
3128{
3129 XFREE (MTYPE_RIP_DISTANCE, rdistance);
3130}
3131
pauldc63bfd2005-10-25 23:31:05 +00003132static int
hasso98b718a2004-10-11 12:57:57 +00003133rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
3134 const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003135{
3136 int ret;
3137 struct prefix_ipv4 p;
3138 u_char distance;
3139 struct route_node *rn;
3140 struct rip_distance *rdistance;
3141
3142 ret = str2prefix_ipv4 (ip_str, &p);
3143 if (ret == 0)
3144 {
3145 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3146 return CMD_WARNING;
3147 }
3148
3149 distance = atoi (distance_str);
3150
3151 /* Get RIP distance node. */
3152 rn = route_node_get (rip_distance_table, (struct prefix *) &p);
3153 if (rn->info)
3154 {
3155 rdistance = rn->info;
3156 route_unlock_node (rn);
3157 }
3158 else
3159 {
3160 rdistance = rip_distance_new ();
3161 rn->info = rdistance;
3162 }
3163
3164 /* Set distance value. */
3165 rdistance->distance = distance;
3166
3167 /* Reset access-list configuration. */
3168 if (rdistance->access_list)
3169 {
3170 free (rdistance->access_list);
3171 rdistance->access_list = NULL;
3172 }
3173 if (access_list_str)
3174 rdistance->access_list = strdup (access_list_str);
3175
3176 return CMD_SUCCESS;
3177}
3178
pauldc63bfd2005-10-25 23:31:05 +00003179static int
hasso98b718a2004-10-11 12:57:57 +00003180rip_distance_unset (struct vty *vty, const char *distance_str,
3181 const char *ip_str, const char *access_list_str)
paul718e3742002-12-13 20:15:29 +00003182{
3183 int ret;
3184 struct prefix_ipv4 p;
3185 u_char distance;
3186 struct route_node *rn;
3187 struct rip_distance *rdistance;
3188
3189 ret = str2prefix_ipv4 (ip_str, &p);
3190 if (ret == 0)
3191 {
3192 vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
3193 return CMD_WARNING;
3194 }
3195
3196 distance = atoi (distance_str);
3197
3198 rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
3199 if (! rn)
3200 {
3201 vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
3202 return CMD_WARNING;
3203 }
3204
3205 rdistance = rn->info;
3206
3207 if (rdistance->access_list)
3208 free (rdistance->access_list);
3209 rip_distance_free (rdistance);
3210
3211 rn->info = NULL;
3212 route_unlock_node (rn);
3213 route_unlock_node (rn);
3214
3215 return CMD_SUCCESS;
3216}
3217
pauldc63bfd2005-10-25 23:31:05 +00003218static void
paul216565a2005-10-25 23:35:28 +00003219rip_distance_reset (void)
paul718e3742002-12-13 20:15:29 +00003220{
3221 struct route_node *rn;
3222 struct rip_distance *rdistance;
3223
3224 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3225 if ((rdistance = rn->info) != NULL)
3226 {
3227 if (rdistance->access_list)
3228 free (rdistance->access_list);
3229 rip_distance_free (rdistance);
3230 rn->info = NULL;
3231 route_unlock_node (rn);
3232 }
3233}
3234
3235/* Apply RIP information to distance method. */
3236u_char
3237rip_distance_apply (struct rip_info *rinfo)
3238{
3239 struct route_node *rn;
3240 struct prefix_ipv4 p;
3241 struct rip_distance *rdistance;
3242 struct access_list *alist;
3243
3244 if (! rip)
3245 return 0;
3246
3247 memset (&p, 0, sizeof (struct prefix_ipv4));
3248 p.family = AF_INET;
3249 p.prefix = rinfo->from;
3250 p.prefixlen = IPV4_MAX_BITLEN;
3251
3252 /* Check source address. */
3253 rn = route_node_match (rip_distance_table, (struct prefix *) &p);
3254 if (rn)
3255 {
3256 rdistance = rn->info;
3257 route_unlock_node (rn);
3258
3259 if (rdistance->access_list)
3260 {
3261 alist = access_list_lookup (AFI_IP, rdistance->access_list);
3262 if (alist == NULL)
3263 return 0;
3264 if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
3265 return 0;
3266
3267 return rdistance->distance;
3268 }
3269 else
3270 return rdistance->distance;
3271 }
3272
3273 if (rip->distance)
3274 return rip->distance;
3275
3276 return 0;
3277}
3278
pauldc63bfd2005-10-25 23:31:05 +00003279static void
paul718e3742002-12-13 20:15:29 +00003280rip_distance_show (struct vty *vty)
3281{
3282 struct route_node *rn;
3283 struct rip_distance *rdistance;
3284 int header = 1;
3285 char buf[BUFSIZ];
3286
3287 vty_out (vty, " Distance: (default is %d)%s",
3288 rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
3289 VTY_NEWLINE);
3290
3291 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3292 if ((rdistance = rn->info) != NULL)
3293 {
3294 if (header)
3295 {
3296 vty_out (vty, " Address Distance List%s",
3297 VTY_NEWLINE);
3298 header = 0;
3299 }
3300 sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
3301 vty_out (vty, " %-20s %4d %s%s",
3302 buf, rdistance->distance,
3303 rdistance->access_list ? rdistance->access_list : "",
3304 VTY_NEWLINE);
3305 }
3306}
3307
3308DEFUN (rip_distance,
3309 rip_distance_cmd,
3310 "distance <1-255>",
3311 "Administrative distance\n"
3312 "Distance value\n")
3313{
3314 rip->distance = atoi (argv[0]);
3315 return CMD_SUCCESS;
3316}
3317
3318DEFUN (no_rip_distance,
3319 no_rip_distance_cmd,
3320 "no distance <1-255>",
3321 NO_STR
3322 "Administrative distance\n"
3323 "Distance value\n")
3324{
3325 rip->distance = 0;
3326 return CMD_SUCCESS;
3327}
3328
3329DEFUN (rip_distance_source,
3330 rip_distance_source_cmd,
3331 "distance <1-255> A.B.C.D/M",
3332 "Administrative distance\n"
3333 "Distance value\n"
3334 "IP source prefix\n")
3335{
3336 rip_distance_set (vty, argv[0], argv[1], NULL);
3337 return CMD_SUCCESS;
3338}
3339
3340DEFUN (no_rip_distance_source,
3341 no_rip_distance_source_cmd,
3342 "no distance <1-255> A.B.C.D/M",
3343 NO_STR
3344 "Administrative distance\n"
3345 "Distance value\n"
3346 "IP source prefix\n")
3347{
3348 rip_distance_unset (vty, argv[0], argv[1], NULL);
3349 return CMD_SUCCESS;
3350}
3351
3352DEFUN (rip_distance_source_access_list,
3353 rip_distance_source_access_list_cmd,
3354 "distance <1-255> A.B.C.D/M WORD",
3355 "Administrative distance\n"
3356 "Distance value\n"
3357 "IP source prefix\n"
3358 "Access list name\n")
3359{
3360 rip_distance_set (vty, argv[0], argv[1], argv[2]);
3361 return CMD_SUCCESS;
3362}
3363
3364DEFUN (no_rip_distance_source_access_list,
3365 no_rip_distance_source_access_list_cmd,
3366 "no distance <1-255> A.B.C.D/M WORD",
3367 NO_STR
3368 "Administrative distance\n"
3369 "Distance value\n"
3370 "IP source prefix\n"
3371 "Access list name\n")
3372{
3373 rip_distance_unset (vty, argv[0], argv[1], argv[2]);
3374 return CMD_SUCCESS;
3375}
3376
3377/* Print out routes update time. */
pauldc63bfd2005-10-25 23:31:05 +00003378static void
paul718e3742002-12-13 20:15:29 +00003379rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
3380{
paul718e3742002-12-13 20:15:29 +00003381 time_t clock;
3382 struct tm *tm;
3383#define TIME_BUF 25
3384 char timebuf [TIME_BUF];
3385 struct thread *thread;
3386
paul718e3742002-12-13 20:15:29 +00003387 if ((thread = rinfo->t_timeout) != NULL)
3388 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003389 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003390 tm = gmtime (&clock);
3391 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3392 vty_out (vty, "%5s", timebuf);
3393 }
3394 else if ((thread = rinfo->t_garbage_collect) != NULL)
3395 {
Vincent Jardina1fdf942007-04-11 15:12:05 +00003396 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00003397 tm = gmtime (&clock);
3398 strftime (timebuf, TIME_BUF, "%M:%S", tm);
3399 vty_out (vty, "%5s", timebuf);
3400 }
3401}
3402
pauldc63bfd2005-10-25 23:31:05 +00003403static const char *
paul718e3742002-12-13 20:15:29 +00003404rip_route_type_print (int sub_type)
3405{
3406 switch (sub_type)
3407 {
3408 case RIP_ROUTE_RTE:
3409 return "n";
3410 case RIP_ROUTE_STATIC:
3411 return "s";
3412 case RIP_ROUTE_DEFAULT:
3413 return "d";
3414 case RIP_ROUTE_REDISTRIBUTE:
3415 return "r";
3416 case RIP_ROUTE_INTERFACE:
3417 return "i";
3418 default:
3419 return "?";
3420 }
3421}
3422
3423DEFUN (show_ip_rip,
3424 show_ip_rip_cmd,
3425 "show ip rip",
3426 SHOW_STR
3427 IP_STR
3428 "Show RIP routes\n")
3429{
3430 struct route_node *np;
3431 struct rip_info *rinfo;
3432
3433 if (! rip)
3434 return CMD_SUCCESS;
3435
hasso16705132003-05-25 14:49:19 +00003436 vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
3437 "Sub-codes:%s"
3438 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
paul718e3742002-12-13 20:15:29 +00003439 " (i) - interface%s%s"
hassoa1455d82004-03-03 19:36:24 +00003440 " Network Next Hop Metric From Tag Time%s",
hasso16705132003-05-25 14:49:19 +00003441 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003442
3443 for (np = route_top (rip->table); np; np = route_next (np))
3444 if ((rinfo = np->info) != NULL)
3445 {
3446 int len;
3447
ajsf52d13c2005-10-01 17:38:06 +00003448 len = vty_out (vty, "%c(%s) %s/%d",
paul718e3742002-12-13 20:15:29 +00003449 /* np->lock, For debugging. */
ajsf52d13c2005-10-01 17:38:06 +00003450 zebra_route_char(rinfo->type),
paul718e3742002-12-13 20:15:29 +00003451 rip_route_type_print (rinfo->sub_type),
3452 inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
3453
hassoa1455d82004-03-03 19:36:24 +00003454 len = 24 - len;
paul718e3742002-12-13 20:15:29 +00003455
3456 if (len > 0)
3457 vty_out (vty, "%*s", len, " ");
3458
3459 if (rinfo->nexthop.s_addr)
3460 vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
3461 rinfo->metric);
3462 else
3463 vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
3464
3465 /* Route which exist in kernel routing table. */
3466 if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
3467 (rinfo->sub_type == RIP_ROUTE_RTE))
3468 {
3469 vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
hasso16705132003-05-25 14:49:19 +00003470 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003471 rip_vty_out_uptime (vty, rinfo);
3472 }
3473 else if (rinfo->metric == RIP_METRIC_INFINITY)
3474 {
3475 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003476 vty_out (vty, "%3d ", rinfo->tag);
paul718e3742002-12-13 20:15:29 +00003477 rip_vty_out_uptime (vty, rinfo);
3478 }
3479 else
hasso16705132003-05-25 14:49:19 +00003480 {
vincentfbf5d032005-09-29 11:25:50 +00003481 if (rinfo->external_metric)
3482 {
3483 len = vty_out (vty, "self (%s:%d)",
ajsf52d13c2005-10-01 17:38:06 +00003484 zebra_route_string(rinfo->type),
vincentfbf5d032005-09-29 11:25:50 +00003485 rinfo->external_metric);
3486 len = 16 - len;
3487 if (len > 0)
3488 vty_out (vty, "%*s", len, " ");
3489 }
3490 else
3491 vty_out (vty, "self ");
hasso16705132003-05-25 14:49:19 +00003492 vty_out (vty, "%3d", rinfo->tag);
3493 }
paul718e3742002-12-13 20:15:29 +00003494
3495 vty_out (vty, "%s", VTY_NEWLINE);
3496 }
3497 return CMD_SUCCESS;
3498}
3499
hasso16705132003-05-25 14:49:19 +00003500/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
3501DEFUN (show_ip_rip_status,
3502 show_ip_rip_status_cmd,
3503 "show ip rip status",
paul718e3742002-12-13 20:15:29 +00003504 SHOW_STR
3505 IP_STR
hasso16705132003-05-25 14:49:19 +00003506 "Show RIP routes\n"
paul718e3742002-12-13 20:15:29 +00003507 "IP routing protocol process parameters and statistics\n")
3508{
hasso52dc7ee2004-09-23 19:18:23 +00003509 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00003510 struct interface *ifp;
3511 struct rip_interface *ri;
Stephen Hemminger1423c802008-08-14 17:59:25 +01003512 extern const struct message ri_version_msg[];
hasso8a676be2004-10-08 06:36:38 +00003513 const char *send_version;
3514 const char *receive_version;
paul718e3742002-12-13 20:15:29 +00003515
3516 if (! rip)
3517 return CMD_SUCCESS;
3518
3519 vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
3520 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
3521 rip->update_time);
Andrew J. Schorra4c64822007-03-21 18:57:38 +00003522 vty_out (vty, " next due in %lu seconds%s",
3523 thread_timer_remain_second(rip->t_update),
paul718e3742002-12-13 20:15:29 +00003524 VTY_NEWLINE);
3525 vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
3526 vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
3527 VTY_NEWLINE);
3528
3529 /* Filtering status show. */
3530 config_show_distribute (vty);
3531
3532 /* Default metric information. */
3533 vty_out (vty, " Default redistribution metric is %d%s",
3534 rip->default_metric, VTY_NEWLINE);
3535
3536 /* Redistribute information. */
3537 vty_out (vty, " Redistributing:");
3538 config_write_rip_redistribute (vty, 0);
3539 vty_out (vty, "%s", VTY_NEWLINE);
3540
paulf38a4712003-06-07 01:10:00 +00003541 vty_out (vty, " Default version control: send version %s,",
3542 lookup(ri_version_msg,rip->version_send));
3543 if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
3544 vty_out (vty, " receive any version %s", VTY_NEWLINE);
3545 else
3546 vty_out (vty, " receive version %s %s",
3547 lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00003548
3549 vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
3550
paul1eb8ef22005-04-07 07:30:20 +00003551 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00003552 {
paul718e3742002-12-13 20:15:29 +00003553 ri = ifp->info;
3554
3555 if (ri->enable_network || ri->enable_interface)
3556 {
3557 if (ri->ri_send == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003558 send_version = lookup (ri_version_msg, rip->version_send);
paul718e3742002-12-13 20:15:29 +00003559 else
3560 send_version = lookup (ri_version_msg, ri->ri_send);
3561
3562 if (ri->ri_receive == RI_RIP_UNSPEC)
paulf38a4712003-06-07 01:10:00 +00003563 receive_version = lookup (ri_version_msg, rip->version_recv);
paul718e3742002-12-13 20:15:29 +00003564 else
3565 receive_version = lookup (ri_version_msg, ri->ri_receive);
3566
3567 vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
3568 send_version,
3569 receive_version,
3570 ri->key_chain ? ri->key_chain : "",
3571 VTY_NEWLINE);
3572 }
3573 }
3574
3575 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
3576 config_write_rip_network (vty, 0);
3577
paul4aaff3f2003-06-07 01:04:45 +00003578 {
3579 int found_passive = 0;
paul1eb8ef22005-04-07 07:30:20 +00003580 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul4aaff3f2003-06-07 01:04:45 +00003581 {
paul4aaff3f2003-06-07 01:04:45 +00003582 ri = ifp->info;
3583
3584 if ((ri->enable_network || ri->enable_interface) && ri->passive)
3585 {
3586 if (!found_passive)
3587 {
3588 vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
3589 found_passive = 1;
3590 }
3591 vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
3592 }
3593 }
3594 }
3595
paul718e3742002-12-13 20:15:29 +00003596 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
3597 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
3598 rip_peer_display (vty);
3599
3600 rip_distance_show (vty);
3601
3602 return CMD_SUCCESS;
3603}
3604
3605/* RIP configuration write function. */
pauldc63bfd2005-10-25 23:31:05 +00003606static int
paul718e3742002-12-13 20:15:29 +00003607config_write_rip (struct vty *vty)
3608{
3609 int write = 0;
3610 struct route_node *rn;
3611 struct rip_distance *rdistance;
3612
3613 if (rip)
3614 {
3615 /* Router RIP statement. */
3616 vty_out (vty, "router rip%s", VTY_NEWLINE);
3617 write++;
3618
3619 /* RIP version statement. Default is RIP version 2. */
paulf38a4712003-06-07 01:10:00 +00003620 if (rip->version_send != RI_RIP_VERSION_2
3621 || rip->version_recv != RI_RIP_VERSION_1_AND_2)
3622 vty_out (vty, " version %d%s", rip->version_send,
paul718e3742002-12-13 20:15:29 +00003623 VTY_NEWLINE);
3624
3625 /* RIP timer configuration. */
3626 if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
3627 || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
3628 || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
3629 vty_out (vty, " timers basic %lu %lu %lu%s",
3630 rip->update_time,
3631 rip->timeout_time,
3632 rip->garbage_time,
3633 VTY_NEWLINE);
3634
3635 /* Default information configuration. */
3636 if (rip->default_information)
3637 {
3638 if (rip->default_information_route_map)
3639 vty_out (vty, " default-information originate route-map %s%s",
3640 rip->default_information_route_map, VTY_NEWLINE);
3641 else
3642 vty_out (vty, " default-information originate%s",
3643 VTY_NEWLINE);
3644 }
3645
3646 /* Redistribute configuration. */
3647 config_write_rip_redistribute (vty, 1);
3648
3649 /* RIP offset-list configuration. */
3650 config_write_rip_offset_list (vty);
3651
3652 /* RIP enabled network and interface configuration. */
3653 config_write_rip_network (vty, 1);
3654
3655 /* RIP default metric configuration */
3656 if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
3657 vty_out (vty, " default-metric %d%s",
3658 rip->default_metric, VTY_NEWLINE);
3659
3660 /* Distribute configuration. */
3661 write += config_write_distribute (vty);
3662
hasso16705132003-05-25 14:49:19 +00003663 /* Interface routemap configuration */
3664 write += config_write_if_rmap (vty);
3665
paul718e3742002-12-13 20:15:29 +00003666 /* Distance configuration. */
3667 if (rip->distance)
3668 vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
3669
3670 /* RIP source IP prefix distance configuration. */
3671 for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
3672 if ((rdistance = rn->info) != NULL)
3673 vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
3674 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
3675 rdistance->access_list ? rdistance->access_list : "",
3676 VTY_NEWLINE);
3677
3678 /* RIP static route configuration. */
3679 for (rn = route_top (rip->route); rn; rn = route_next (rn))
3680 if (rn->info)
3681 vty_out (vty, " route %s/%d%s",
3682 inet_ntoa (rn->p.u.prefix4),
3683 rn->p.prefixlen,
3684 VTY_NEWLINE);
3685
3686 }
3687 return write;
3688}
3689
3690/* RIP node structure. */
3691struct cmd_node rip_node =
3692{
3693 RIP_NODE,
3694 "%s(config-router)# ",
3695 1
3696};
3697
3698/* Distribute-list update functions. */
pauldc63bfd2005-10-25 23:31:05 +00003699static void
paul718e3742002-12-13 20:15:29 +00003700rip_distribute_update (struct distribute *dist)
3701{
3702 struct interface *ifp;
3703 struct rip_interface *ri;
3704 struct access_list *alist;
3705 struct prefix_list *plist;
3706
3707 if (! dist->ifname)
3708 return;
3709
3710 ifp = if_lookup_by_name (dist->ifname);
3711 if (ifp == NULL)
3712 return;
3713
3714 ri = ifp->info;
3715
3716 if (dist->list[DISTRIBUTE_IN])
3717 {
3718 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
3719 if (alist)
3720 ri->list[RIP_FILTER_IN] = alist;
3721 else
3722 ri->list[RIP_FILTER_IN] = NULL;
3723 }
3724 else
3725 ri->list[RIP_FILTER_IN] = NULL;
3726
3727 if (dist->list[DISTRIBUTE_OUT])
3728 {
3729 alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
3730 if (alist)
3731 ri->list[RIP_FILTER_OUT] = alist;
3732 else
3733 ri->list[RIP_FILTER_OUT] = NULL;
3734 }
3735 else
3736 ri->list[RIP_FILTER_OUT] = NULL;
3737
3738 if (dist->prefix[DISTRIBUTE_IN])
3739 {
3740 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
3741 if (plist)
3742 ri->prefix[RIP_FILTER_IN] = plist;
3743 else
3744 ri->prefix[RIP_FILTER_IN] = NULL;
3745 }
3746 else
3747 ri->prefix[RIP_FILTER_IN] = NULL;
3748
3749 if (dist->prefix[DISTRIBUTE_OUT])
3750 {
3751 plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
3752 if (plist)
3753 ri->prefix[RIP_FILTER_OUT] = plist;
3754 else
3755 ri->prefix[RIP_FILTER_OUT] = NULL;
3756 }
3757 else
3758 ri->prefix[RIP_FILTER_OUT] = NULL;
3759}
3760
3761void
3762rip_distribute_update_interface (struct interface *ifp)
3763{
3764 struct distribute *dist;
3765
3766 dist = distribute_lookup (ifp->name);
3767 if (dist)
3768 rip_distribute_update (dist);
3769}
3770
3771/* Update all interface's distribute list. */
paul02ff83c2004-06-11 11:27:03 +00003772/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003773static void
paul02ff83c2004-06-11 11:27:03 +00003774rip_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00003775{
3776 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003777 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00003778
paul1eb8ef22005-04-07 07:30:20 +00003779 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3780 rip_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00003781}
paul11dde9c2004-05-31 14:00:00 +00003782/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003783static void
paul11dde9c2004-05-31 14:00:00 +00003784rip_distribute_update_all_wrapper(struct access_list *notused)
3785{
paul02ff83c2004-06-11 11:27:03 +00003786 rip_distribute_update_all(NULL);
paul11dde9c2004-05-31 14:00:00 +00003787}
paul718e3742002-12-13 20:15:29 +00003788
3789/* Delete all added rip route. */
3790void
paul216565a2005-10-25 23:35:28 +00003791rip_clean (void)
paul718e3742002-12-13 20:15:29 +00003792{
3793 int i;
3794 struct route_node *rp;
3795 struct rip_info *rinfo;
3796
3797 if (rip)
3798 {
3799 /* Clear RIP routes */
3800 for (rp = route_top (rip->table); rp; rp = route_next (rp))
3801 if ((rinfo = rp->info) != NULL)
3802 {
3803 if (rinfo->type == ZEBRA_ROUTE_RIP &&
3804 rinfo->sub_type == RIP_ROUTE_RTE)
3805 rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
3806 &rinfo->nexthop, rinfo->metric);
3807
3808 RIP_TIMER_OFF (rinfo->t_timeout);
3809 RIP_TIMER_OFF (rinfo->t_garbage_collect);
3810
3811 rp->info = NULL;
3812 route_unlock_node (rp);
3813
3814 rip_info_free (rinfo);
3815 }
3816
3817 /* Cancel RIP related timers. */
3818 RIP_TIMER_OFF (rip->t_update);
3819 RIP_TIMER_OFF (rip->t_triggered_update);
3820 RIP_TIMER_OFF (rip->t_triggered_interval);
3821
3822 /* Cancel read thread. */
3823 if (rip->t_read)
3824 {
3825 thread_cancel (rip->t_read);
3826 rip->t_read = NULL;
3827 }
3828
3829 /* Close RIP socket. */
3830 if (rip->sock >= 0)
3831 {
3832 close (rip->sock);
3833 rip->sock = -1;
3834 }
3835
3836 /* Static RIP route configuration. */
3837 for (rp = route_top (rip->route); rp; rp = route_next (rp))
3838 if (rp->info)
3839 {
3840 rp->info = NULL;
3841 route_unlock_node (rp);
3842 }
3843
3844 /* RIP neighbor configuration. */
3845 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
3846 if (rp->info)
3847 {
3848 rp->info = NULL;
3849 route_unlock_node (rp);
3850 }
3851
3852 /* Redistribute related clear. */
3853 if (rip->default_information_route_map)
3854 free (rip->default_information_route_map);
3855
3856 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3857 if (rip->route_map[i].name)
3858 free (rip->route_map[i].name);
3859
3860 XFREE (MTYPE_ROUTE_TABLE, rip->table);
3861 XFREE (MTYPE_ROUTE_TABLE, rip->route);
3862 XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
3863
3864 XFREE (MTYPE_RIP, rip);
3865 rip = NULL;
3866 }
3867
3868 rip_clean_network ();
paul4aaff3f2003-06-07 01:04:45 +00003869 rip_passive_nondefault_clean ();
paul718e3742002-12-13 20:15:29 +00003870 rip_offset_clean ();
3871 rip_interface_clean ();
3872 rip_distance_reset ();
3873 rip_redistribute_clean ();
3874}
3875
3876/* Reset all values to the default settings. */
3877void
paul216565a2005-10-25 23:35:28 +00003878rip_reset (void)
paul718e3742002-12-13 20:15:29 +00003879{
3880 /* Reset global counters. */
3881 rip_global_route_changes = 0;
3882 rip_global_queries = 0;
3883
3884 /* Call ripd related reset functions. */
3885 rip_debug_reset ();
3886 rip_route_map_reset ();
3887
3888 /* Call library reset functions. */
3889 vty_reset ();
3890 access_list_reset ();
3891 prefix_list_reset ();
3892
3893 distribute_list_reset ();
3894
3895 rip_interface_reset ();
3896 rip_distance_reset ();
3897
3898 rip_zclient_reset ();
3899}
3900
pauldc63bfd2005-10-25 23:31:05 +00003901static void
hasso16705132003-05-25 14:49:19 +00003902rip_if_rmap_update (struct if_rmap *if_rmap)
3903{
3904 struct interface *ifp;
3905 struct rip_interface *ri;
3906 struct route_map *rmap;
3907
3908 ifp = if_lookup_by_name (if_rmap->ifname);
3909 if (ifp == NULL)
3910 return;
3911
3912 ri = ifp->info;
3913
3914 if (if_rmap->routemap[IF_RMAP_IN])
3915 {
3916 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
3917 if (rmap)
3918 ri->routemap[IF_RMAP_IN] = rmap;
3919 else
3920 ri->routemap[IF_RMAP_IN] = NULL;
3921 }
3922 else
3923 ri->routemap[RIP_FILTER_IN] = NULL;
3924
3925 if (if_rmap->routemap[IF_RMAP_OUT])
3926 {
3927 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
3928 if (rmap)
3929 ri->routemap[IF_RMAP_OUT] = rmap;
3930 else
3931 ri->routemap[IF_RMAP_OUT] = NULL;
3932 }
3933 else
3934 ri->routemap[RIP_FILTER_OUT] = NULL;
3935}
3936
3937void
3938rip_if_rmap_update_interface (struct interface *ifp)
3939{
3940 struct if_rmap *if_rmap;
3941
3942 if_rmap = if_rmap_lookup (ifp->name);
3943 if (if_rmap)
3944 rip_if_rmap_update (if_rmap);
3945}
3946
pauldc63bfd2005-10-25 23:31:05 +00003947static void
hasso16705132003-05-25 14:49:19 +00003948rip_routemap_update_redistribute (void)
3949{
3950 int i;
3951
3952 if (rip)
3953 {
3954 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
3955 {
3956 if (rip->route_map[i].name)
3957 rip->route_map[i].map =
3958 route_map_lookup_by_name (rip->route_map[i].name);
3959 }
3960 }
3961}
3962
paul11dde9c2004-05-31 14:00:00 +00003963/* ARGSUSED */
pauldc63bfd2005-10-25 23:31:05 +00003964static void
hasso98b718a2004-10-11 12:57:57 +00003965rip_routemap_update (const char *notused)
hasso16705132003-05-25 14:49:19 +00003966{
3967 struct interface *ifp;
paul1eb8ef22005-04-07 07:30:20 +00003968 struct listnode *node, *nnode;
hasso16705132003-05-25 14:49:19 +00003969
paul1eb8ef22005-04-07 07:30:20 +00003970 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
3971 rip_if_rmap_update_interface (ifp);
hasso16705132003-05-25 14:49:19 +00003972
3973 rip_routemap_update_redistribute ();
3974}
3975
paul718e3742002-12-13 20:15:29 +00003976/* Allocate new rip structure and set default value. */
3977void
pauldc63bfd2005-10-25 23:31:05 +00003978rip_init (void)
paul718e3742002-12-13 20:15:29 +00003979{
3980 /* Randomize for triggered update random(). */
3981 srand (time (NULL));
3982
3983 /* Install top nodes. */
3984 install_node (&rip_node, config_write_rip);
3985
3986 /* Install rip commands. */
3987 install_element (VIEW_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003988 install_element (VIEW_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003989 install_element (ENABLE_NODE, &show_ip_rip_cmd);
hasso16705132003-05-25 14:49:19 +00003990 install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
paul718e3742002-12-13 20:15:29 +00003991 install_element (CONFIG_NODE, &router_rip_cmd);
3992 install_element (CONFIG_NODE, &no_router_rip_cmd);
3993
3994 install_default (RIP_NODE);
3995 install_element (RIP_NODE, &rip_version_cmd);
3996 install_element (RIP_NODE, &no_rip_version_cmd);
3997 install_element (RIP_NODE, &no_rip_version_val_cmd);
3998 install_element (RIP_NODE, &rip_default_metric_cmd);
3999 install_element (RIP_NODE, &no_rip_default_metric_cmd);
4000 install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
4001 install_element (RIP_NODE, &rip_timers_cmd);
4002 install_element (RIP_NODE, &no_rip_timers_cmd);
hasso16705132003-05-25 14:49:19 +00004003 install_element (RIP_NODE, &no_rip_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00004004 install_element (RIP_NODE, &rip_route_cmd);
4005 install_element (RIP_NODE, &no_rip_route_cmd);
4006 install_element (RIP_NODE, &rip_distance_cmd);
4007 install_element (RIP_NODE, &no_rip_distance_cmd);
4008 install_element (RIP_NODE, &rip_distance_source_cmd);
4009 install_element (RIP_NODE, &no_rip_distance_source_cmd);
4010 install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
4011 install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
4012
4013 /* Debug related init. */
4014 rip_debug_init ();
4015
paul718e3742002-12-13 20:15:29 +00004016 /* SNMP init. */
4017#ifdef HAVE_SNMP
4018 rip_snmp_init ();
4019#endif /* HAVE_SNMP */
4020
4021 /* Access list install. */
4022 access_list_init ();
paul11dde9c2004-05-31 14:00:00 +00004023 access_list_add_hook (rip_distribute_update_all_wrapper);
4024 access_list_delete_hook (rip_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00004025
4026 /* Prefix list initialize.*/
4027 prefix_list_init ();
4028 prefix_list_add_hook (rip_distribute_update_all);
4029 prefix_list_delete_hook (rip_distribute_update_all);
4030
4031 /* Distribute list install. */
4032 distribute_list_init (RIP_NODE);
4033 distribute_list_add_hook (rip_distribute_update);
4034 distribute_list_delete_hook (rip_distribute_update);
4035
hasso16705132003-05-25 14:49:19 +00004036 /* Route-map */
4037 rip_route_map_init ();
4038 rip_offset_init ();
4039
4040 route_map_add_hook (rip_routemap_update);
4041 route_map_delete_hook (rip_routemap_update);
4042
4043 if_rmap_init (RIP_NODE);
4044 if_rmap_hook_add (rip_if_rmap_update);
4045 if_rmap_hook_delete (rip_if_rmap_update);
4046
paul718e3742002-12-13 20:15:29 +00004047 /* Distance control. */
4048 rip_distance_table = route_table_init ();
4049}