blob: cf78a54e79e8f101f60032383af5e9f6f8515a64 [file] [log] [blame]
hassoca776982004-06-12 14:33:05 +00001/*
2 *
3 * Copyright (C) 2000 Robert Olsson.
4 * Swedish University of Agricultural Sciences
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24/*
25 * This work includes work with the following copywrite:
26 *
27 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
28 *
29 */
30
31/*
32 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
33 * for reviewing and tests.
34 */
35
36
37#include <zebra.h>
38
39#ifdef HAVE_IRDP
40
41#include "if.h"
42#include "vty.h"
43#include "sockunion.h"
hassoc9e52be2004-09-26 16:09:34 +000044#include "sockopt.h"
hassoca776982004-06-12 14:33:05 +000045#include "prefix.h"
46#include "command.h"
47#include "memory.h"
48#include "stream.h"
49#include "ioctl.h"
50#include "connected.h"
51#include "log.h"
52#include "zclient.h"
53#include "thread.h"
hasso25dac852004-07-13 03:06:51 +000054#include "privs.h"
hassoca776982004-06-12 14:33:05 +000055#include "zebra/interface.h"
56#include "zebra/rtadv.h"
57#include "zebra/rib.h"
58#include "zebra/zserv.h"
59#include "zebra/redistribute.h"
60#include "zebra/irdp.h"
61#include <netinet/ip_icmp.h>
62
Stephen Hemmingerab0f6152009-12-10 14:22:44 +030063#include "checksum.h"
hassoca776982004-06-12 14:33:05 +000064#include "if.h"
65#include "sockunion.h"
66#include "log.h"
67
68/* GLOBAL VARS */
69
hasso25dac852004-07-13 03:06:51 +000070extern struct zebra_privs_t zserv_privs;
71
hassoca776982004-06-12 14:33:05 +000072/* Master of threads. */
73extern struct zebra_t zebrad;
74struct thread *t_irdp_raw;
75
76/* Timer interval of irdp. */
77int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
78
hassoca776982004-06-12 14:33:05 +000079int
80irdp_sock_init (void)
81{
82 int ret, i;
ajs4460e7a2005-01-29 17:07:40 +000083 int save_errno;
ajs2da40f42005-03-30 16:33:13 +000084 int sock;
hassoca776982004-06-12 14:33:05 +000085
hasso25dac852004-07-13 03:06:51 +000086 if ( zserv_privs.change (ZPRIVS_RAISE) )
87 zlog_err ("irdp_sock_init: could not raise privs, %s",
ajs6099b3b2004-11-20 02:06:59 +000088 safe_strerror (errno) );
hasso25dac852004-07-13 03:06:51 +000089
ajs2da40f42005-03-30 16:33:13 +000090 sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
ajs4460e7a2005-01-29 17:07:40 +000091 save_errno = errno;
hasso25dac852004-07-13 03:06:51 +000092
93 if ( zserv_privs.change (ZPRIVS_LOWER) )
94 zlog_err ("irdp_sock_init: could not lower privs, %s",
ajs6099b3b2004-11-20 02:06:59 +000095 safe_strerror (errno) );
hasso25dac852004-07-13 03:06:51 +000096
ajs2da40f42005-03-30 16:33:13 +000097 if (sock < 0) {
ajs4460e7a2005-01-29 17:07:40 +000098 zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
ajs2da40f42005-03-30 16:33:13 +000099 return sock;
hassoca776982004-06-12 14:33:05 +0000100 };
101
102 i = 1;
ajs2da40f42005-03-30 16:33:13 +0000103 ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
hassoca776982004-06-12 14:33:05 +0000104 (void *) &i, sizeof (i));
105 if (ret < 0) {
ajs6099b3b2004-11-20 02:06:59 +0000106 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
ajs2da40f42005-03-30 16:33:13 +0000107 close(sock);
hassoca776982004-06-12 14:33:05 +0000108 return ret;
109 };
110
ajs2da40f42005-03-30 16:33:13 +0000111 ret = setsockopt_ifindex (AF_INET, sock, 1);
hassoca776982004-06-12 14:33:05 +0000112 if (ret < 0) {
ajs6099b3b2004-11-20 02:06:59 +0000113 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
ajs2da40f42005-03-30 16:33:13 +0000114 close(sock);
hassoca776982004-06-12 14:33:05 +0000115 return ret;
116 };
117
ajs2da40f42005-03-30 16:33:13 +0000118 t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock);
hassoca776982004-06-12 14:33:05 +0000119
ajs2da40f42005-03-30 16:33:13 +0000120 return sock;
hassoca776982004-06-12 14:33:05 +0000121}
122
123
ajs2da40f42005-03-30 16:33:13 +0000124static int
125get_pref(struct irdp_interface *irdp, struct prefix *p)
hassoca776982004-06-12 14:33:05 +0000126{
paul0c0f9112004-09-24 08:24:42 +0000127 struct listnode *node;
hassoca776982004-06-12 14:33:05 +0000128 struct Adv *adv;
129
130 /* Use default preference or use the override pref */
131
paul0c0f9112004-09-24 08:24:42 +0000132 if( irdp->AdvPrefList == NULL )
133 return irdp->Preference;
hassoca776982004-06-12 14:33:05 +0000134
paul1eb8ef22005-04-07 07:30:20 +0000135 for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
hassoca776982004-06-12 14:33:05 +0000136 if( p->u.prefix4.s_addr == adv->ip.s_addr )
137 return adv->pref;
paul0c0f9112004-09-24 08:24:42 +0000138
hassoca776982004-06-12 14:33:05 +0000139 return irdp->Preference;
140}
141
142/* Make ICMP Router Advertisement Message. */
ajs2da40f42005-03-30 16:33:13 +0000143static int
144make_advertisement_packet (struct interface *ifp,
145 struct prefix *p,
146 struct stream *s)
hassoca776982004-06-12 14:33:05 +0000147{
148 struct zebra_if *zi=ifp->info;
149 struct irdp_interface *irdp=&zi->irdp;
150 int size;
151 int pref;
152 u_int16_t checksum;
153
154 pref = get_pref(irdp, p);
155
156 stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
157 stream_putc (s, 0); /* Code. */
158 stream_putw (s, 0); /* Checksum. */
159 stream_putc (s, 1); /* Num address. */
160 stream_putc (s, 2); /* Address Entry Size. */
161
162 if(irdp->flags & IF_SHUTDOWN)
163 stream_putw (s, 0);
164 else
165 stream_putw (s, irdp->Lifetime);
166
167 stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
168 stream_putl (s, pref);
169
170 /* in_cksum return network byte order value */
171 size = 16;
172 checksum = in_cksum (s->data, size);
173 stream_putw_at (s, 2, htons(checksum));
174
175 return size;
176}
177
ajs2da40f42005-03-30 16:33:13 +0000178static void
179irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
hassoca776982004-06-12 14:33:05 +0000180{
181 struct zebra_if *zi=ifp->info;
182 struct irdp_interface *irdp=&zi->irdp;
Timo Teräsbe6335d2015-05-23 11:08:41 +0300183 char buf[PREFIX_STRLEN];
hassoca776982004-06-12 14:33:05 +0000184 u_int32_t dst;
185 u_int32_t ttl=1;
186
187 if (! (ifp->flags & IFF_UP)) return;
188
189 if (irdp->flags & IF_BROADCAST)
190 dst =INADDR_BROADCAST ;
191 else
192 dst = htonl(INADDR_ALLHOSTS_GROUP);
193
194 if(irdp->flags & IF_DEBUG_MESSAGES)
Timo Teräsbe6335d2015-05-23 11:08:41 +0300195 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
hassoca776982004-06-12 14:33:05 +0000196 ifp->name,
Timo Teräsbe6335d2015-05-23 11:08:41 +0300197 prefix2str(p, buf, sizeof buf),
hassoca776982004-06-12 14:33:05 +0000198 irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
199 get_pref(irdp, p));
200
201 send_packet (ifp, s, dst, p, ttl);
202}
203
ajs2da40f42005-03-30 16:33:13 +0000204static void irdp_advertisement (struct interface *ifp, struct prefix *p)
hassoca776982004-06-12 14:33:05 +0000205{
206 struct stream *s;
207 s = stream_new (128);
208 make_advertisement_packet (ifp, p, s);
Paul Jakma36943742006-08-04 06:18:04 +0000209 irdp_send(ifp, p, s);
210 stream_free (s);
hassoca776982004-06-12 14:33:05 +0000211}
212
213int irdp_send_thread(struct thread *t_advert)
214{
215 u_int32_t timer, tmp;
216 struct interface *ifp = THREAD_ARG (t_advert);
217 struct zebra_if *zi=ifp->info;
218 struct irdp_interface *irdp=&zi->irdp;
219 struct prefix *p;
paul1eb8ef22005-04-07 07:30:20 +0000220 struct listnode *node, *nnode;
hassoca776982004-06-12 14:33:05 +0000221 struct connected *ifc;
222
223 irdp->flags &= ~IF_SOLICIT;
224
225 if(ifp->connected)
paul1eb8ef22005-04-07 07:30:20 +0000226 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
paul0c0f9112004-09-24 08:24:42 +0000227 {
228 p = ifc->address;
Paul Jakmaff1dd552007-02-26 17:11:45 +0000229
230 if (p->family != AF_INET)
231 continue;
232
paul0c0f9112004-09-24 08:24:42 +0000233 irdp_advertisement(ifp, p);
234 irdp->irdp_sent++;
235 }
hassoca776982004-06-12 14:33:05 +0000236
237 tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
238 timer = (random () % tmp ) + 1;
239 timer = irdp->MinAdvertInterval + timer;
240
241 if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
242 timer > MAX_INITIAL_ADVERT_INTERVAL )
243 timer= MAX_INITIAL_ADVERT_INTERVAL;
244
245 if(irdp->flags & IF_DEBUG_MISC)
ajsb6178002004-12-07 21:12:56 +0000246 zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
hassoca776982004-06-12 14:33:05 +0000247
248 irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
249 return 0;
250}
251
252void irdp_advert_off(struct interface *ifp)
253{
254 struct zebra_if *zi=ifp->info;
255 struct irdp_interface *irdp=&zi->irdp;
paul1eb8ef22005-04-07 07:30:20 +0000256 struct listnode *node, *nnode;
hassoca776982004-06-12 14:33:05 +0000257 int i;
258 struct connected *ifc;
259 struct prefix *p;
260
261 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
262 irdp->t_advertise = NULL;
263
264 if(ifp->connected)
paul1eb8ef22005-04-07 07:30:20 +0000265 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
paul0c0f9112004-09-24 08:24:42 +0000266 {
267 p = ifc->address;
hassoca776982004-06-12 14:33:05 +0000268
paul0c0f9112004-09-24 08:24:42 +0000269 /* Output some packets with Lifetime 0
270 we should add a wait...
271 */
hassoca776982004-06-12 14:33:05 +0000272
paul0c0f9112004-09-24 08:24:42 +0000273 for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++)
274 {
275 irdp->irdp_sent++;
276 irdp_advertisement(ifp, p);
277 }
hassoca776982004-06-12 14:33:05 +0000278 }
hassoca776982004-06-12 14:33:05 +0000279}
280
281
282void process_solicit (struct interface *ifp)
283{
284 struct zebra_if *zi=ifp->info;
285 struct irdp_interface *irdp=&zi->irdp;
286 u_int32_t timer;
287
288 /* When SOLICIT is active we reject further incoming solicits
289 this keeps down the answering rate so we don't have think
290 about DoS attacks here. */
291
292 if( irdp->flags & IF_SOLICIT) return;
293
294 irdp->flags |= IF_SOLICIT;
295 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
296 irdp->t_advertise = NULL;
297
298 timer = (random () % MAX_RESPONSE_DELAY) + 1;
299
300 irdp->t_advertise = thread_add_timer(zebrad.master,
301 irdp_send_thread,
302 ifp,
303 timer);
304}
305
306void irdp_finish()
307{
308
paul1eb8ef22005-04-07 07:30:20 +0000309 struct listnode *node, *nnode;
hassoca776982004-06-12 14:33:05 +0000310 struct interface *ifp;
311 struct zebra_if *zi;
312 struct irdp_interface *irdp;
313
ajs274a4a42004-12-07 15:39:31 +0000314 zlog_info("IRDP: Received shutdown notification.");
hassoca776982004-06-12 14:33:05 +0000315
paul1eb8ef22005-04-07 07:30:20 +0000316 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
hassoca776982004-06-12 14:33:05 +0000317 {
paul0c0f9112004-09-24 08:24:42 +0000318 zi = ifp->info;
319
320 if (!zi)
321 continue;
hassoca776982004-06-12 14:33:05 +0000322 irdp = &zi->irdp;
paul0c0f9112004-09-24 08:24:42 +0000323 if (!irdp)
324 continue;
hassoca776982004-06-12 14:33:05 +0000325
paul0c0f9112004-09-24 08:24:42 +0000326 if (irdp->flags & IF_ACTIVE )
327 {
328 irdp->flags |= IF_SHUTDOWN;
329 irdp_advert_off(ifp);
330 }
hassoca776982004-06-12 14:33:05 +0000331 }
332}
333
hassoca776982004-06-12 14:33:05 +0000334#endif /* HAVE_IRDP */