]> git.proxmox.com Git - mirror_frr.git/blame - zebra/irdp_main.c
*: use frr_elevate_privs() (1/2: coccinelle)
[mirror_frr.git] / zebra / irdp_main.c
CommitLineData
ca776988 1/*
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 *
896014f4
DL
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
ca776988 21 */
22
d62a17ae 23/*
ca776988 24 * This work includes work with the following copywrite:
25 *
26 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
27 *
28 */
29
d62a17ae 30/*
43e52561 31 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
ca776988 32 * for reviewing and tests.
33 */
34
35
36#include <zebra.h>
37
ca776988 38#include "if.h"
39#include "vty.h"
40#include "sockunion.h"
c9e52be3 41#include "sockopt.h"
ca776988 42#include "prefix.h"
43#include "command.h"
44#include "memory.h"
4a1ab8e4 45#include "zebra_memory.h"
ca776988 46#include "stream.h"
47#include "ioctl.h"
48#include "connected.h"
49#include "log.h"
50#include "zclient.h"
51#include "thread.h"
25dac855 52#include "privs.h"
ead4ee99 53#include "libfrr.h"
43e52561 54#include "lib_errors.h"
8dc1f7fc 55#include "version.h"
ca776988 56#include "zebra/interface.h"
57#include "zebra/rtadv.h"
58#include "zebra/rib.h"
59#include "zebra/zserv.h"
60#include "zebra/redistribute.h"
61#include "zebra/irdp.h"
62#include <netinet/ip_icmp.h>
63
ab0f6155 64#include "checksum.h"
ca776988 65#include "if.h"
66#include "sockunion.h"
67#include "log.h"
68
69/* GLOBAL VARS */
70
25dac855 71extern struct zebra_privs_t zserv_privs;
72
ca776988 73struct thread *t_irdp_raw;
74
75/* Timer interval of irdp. */
76int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
77
d62a17ae 78int irdp_sock_init(void)
ca776988 79{
d62a17ae 80 int ret, i;
81 int save_errno;
82 int sock;
83
01b9e3fd 84 frr_elevate_privs(&zserv_privs) {
d62a17ae 85
01b9e3fd
DL
86 sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
87 save_errno = errno;
d62a17ae 88
01b9e3fd 89 }
d62a17ae 90
91 if (sock < 0) {
92 zlog_warn("IRDP: can't create irdp socket %s",
93 safe_strerror(save_errno));
94 return sock;
95 };
96
97 i = 1;
98 ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (void *)&i, sizeof(i));
99 if (ret < 0) {
100 zlog_warn("IRDP: can't do irdp sockopt %s",
101 safe_strerror(errno));
102 close(sock);
103 return ret;
104 };
105
106 ret = setsockopt_ifindex(AF_INET, sock, 1);
107 if (ret < 0) {
108 zlog_warn("IRDP: can't do irdp sockopt %s",
109 safe_strerror(errno));
110 close(sock);
111 return ret;
112 };
113
114 t_irdp_raw = NULL;
115 thread_add_read(zebrad.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
116
117 return sock;
ca776988 118}
119
120
d62a17ae 121static int get_pref(struct irdp_interface *irdp, struct prefix *p)
ca776988 122{
d62a17ae 123 struct listnode *node;
124 struct Adv *adv;
125
126 /* Use default preference or use the override pref */
127
128 if (irdp->AdvPrefList == NULL)
129 return irdp->Preference;
130
131 for (ALL_LIST_ELEMENTS_RO(irdp->AdvPrefList, node, adv))
132 if (p->u.prefix4.s_addr == adv->ip.s_addr)
133 return adv->pref;
134
135 return irdp->Preference;
ca776988 136}
137
138/* Make ICMP Router Advertisement Message. */
d62a17ae 139static int make_advertisement_packet(struct interface *ifp, struct prefix *p,
140 struct stream *s)
ca776988 141{
d62a17ae 142 struct zebra_if *zi = ifp->info;
ead4ee99 143 struct irdp_interface *irdp = zi->irdp;
d62a17ae 144 int size;
145 int pref;
d7c0a89a 146 uint16_t checksum;
d62a17ae 147
148 pref = get_pref(irdp, p);
149
150 stream_putc(s, ICMP_ROUTERADVERT); /* Type. */
151 stream_putc(s, 0); /* Code. */
152 stream_putw(s, 0); /* Checksum. */
153 stream_putc(s, 1); /* Num address. */
154 stream_putc(s, 2); /* Address Entry Size. */
155
156 if (irdp->flags & IF_SHUTDOWN)
157 stream_putw(s, 0);
158 else
159 stream_putw(s, irdp->Lifetime);
160
161 stream_putl(s, htonl(p->u.prefix4.s_addr)); /* Router address. */
162 stream_putl(s, pref);
163
164 /* in_cksum return network byte order value */
165 size = 16;
166 checksum = in_cksum(s->data, size);
167 stream_putw_at(s, 2, htons(checksum));
168
169 return size;
ca776988 170}
171
d62a17ae 172static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
ca776988 173{
d62a17ae 174 struct zebra_if *zi = ifp->info;
ead4ee99 175 struct irdp_interface *irdp = zi->irdp;
d62a17ae 176 char buf[PREFIX_STRLEN];
d7c0a89a
QY
177 uint32_t dst;
178 uint32_t ttl = 1;
d62a17ae 179
ead4ee99
DL
180 if (!irdp)
181 return;
d62a17ae 182 if (!(ifp->flags & IFF_UP))
183 return;
184
185 if (irdp->flags & IF_BROADCAST)
186 dst = INADDR_BROADCAST;
187 else
188 dst = htonl(INADDR_ALLHOSTS_GROUP);
189
190 if (irdp->flags & IF_DEBUG_MESSAGES)
191 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
192 ifp->name, prefix2str(p, buf, sizeof buf),
193 irdp->flags & IF_SHUTDOWN ? 0 : irdp->Lifetime,
194 get_pref(irdp, p));
195
196 send_packet(ifp, s, dst, p, ttl);
ca776988 197}
198
d62a17ae 199static void irdp_advertisement(struct interface *ifp, struct prefix *p)
ca776988 200{
d62a17ae 201 struct stream *s;
202 s = stream_new(128);
203 make_advertisement_packet(ifp, p, s);
204 irdp_send(ifp, p, s);
205 stream_free(s);
ca776988 206}
207
208int irdp_send_thread(struct thread *t_advert)
209{
d7c0a89a 210 uint32_t timer, tmp;
d62a17ae 211 struct interface *ifp = THREAD_ARG(t_advert);
212 struct zebra_if *zi = ifp->info;
ead4ee99 213 struct irdp_interface *irdp = zi->irdp;
d62a17ae 214 struct prefix *p;
215 struct listnode *node, *nnode;
216 struct connected *ifc;
217
ead4ee99
DL
218 if (!irdp)
219 return 0;
220
d62a17ae 221 irdp->flags &= ~IF_SOLICIT;
222
223 if (ifp->connected)
224 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
225 p = ifc->address;
226
227 if (p->family != AF_INET)
228 continue;
229
230 irdp_advertisement(ifp, p);
231 irdp->irdp_sent++;
232 }
233
234 tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval;
235 timer = random() % (tmp + 1);
236 timer = irdp->MinAdvertInterval + timer;
237
238 if (irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS
239 && timer > MAX_INITIAL_ADVERT_INTERVAL)
240 timer = MAX_INITIAL_ADVERT_INTERVAL;
241
242 if (irdp->flags & IF_DEBUG_MISC)
243 zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name,
244 timer);
245
246 irdp->t_advertise = NULL;
247 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
248 &irdp->t_advertise);
249 return 0;
ca776988 250}
251
252void irdp_advert_off(struct interface *ifp)
253{
d62a17ae 254 struct zebra_if *zi = ifp->info;
ead4ee99 255 struct irdp_interface *irdp = zi->irdp;
d62a17ae 256 struct listnode *node, *nnode;
257 int i;
258 struct connected *ifc;
259 struct prefix *p;
260
ead4ee99
DL
261 if (!irdp)
262 return;
263
d62a17ae 264 if (irdp->t_advertise)
265 thread_cancel(irdp->t_advertise);
266 irdp->t_advertise = NULL;
267
268 if (ifp->connected)
269 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
270 p = ifc->address;
271
272 /* Output some packets with Lifetime 0
273 we should add a wait...
274 */
275
276 for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) {
277 irdp->irdp_sent++;
278 irdp_advertisement(ifp, p);
279 }
280 }
ca776988 281}
282
283
d62a17ae 284void process_solicit(struct interface *ifp)
ca776988 285{
d62a17ae 286 struct zebra_if *zi = ifp->info;
ead4ee99 287 struct irdp_interface *irdp = zi->irdp;
d7c0a89a 288 uint32_t timer;
ca776988 289
ead4ee99
DL
290 if (!irdp)
291 return;
292
d62a17ae 293 /* When SOLICIT is active we reject further incoming solicits
294 this keeps down the answering rate so we don't have think
295 about DoS attacks here. */
ca776988 296
d62a17ae 297 if (irdp->flags & IF_SOLICIT)
298 return;
ca776988 299
d62a17ae 300 irdp->flags |= IF_SOLICIT;
301 if (irdp->t_advertise)
302 thread_cancel(irdp->t_advertise);
303 irdp->t_advertise = NULL;
ca776988 304
d62a17ae 305 timer = (random() % MAX_RESPONSE_DELAY) + 1;
ca776988 306
d62a17ae 307 irdp->t_advertise = NULL;
308 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
309 &irdp->t_advertise);
ca776988 310}
311
2eb27eec 312static int irdp_finish(void)
ca776988 313{
d62a17ae 314 struct vrf *vrf;
d62a17ae 315 struct interface *ifp;
316 struct zebra_if *zi;
317 struct irdp_interface *irdp;
318
319 zlog_info("IRDP: Received shutdown notification.");
320
a2addae8 321 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
451fda4f 322 FOR_ALL_INTERFACES (vrf, ifp) {
a2addae8
RW
323 zi = ifp->info;
324
325 if (!zi)
326 continue;
327 irdp = zi->irdp;
328 if (!irdp)
329 continue;
330
331 if (irdp->flags & IF_ACTIVE) {
332 irdp->flags |= IF_SHUTDOWN;
333 irdp_advert_off(ifp);
334 }
d62a17ae 335 }
ead4ee99 336 return 0;
ca776988 337}
338
8dc1f7fc 339static int irdp_init(struct thread_master *master)
2eb27eec
DL
340{
341 irdp_if_init();
342
343 hook_register(frr_early_fini, irdp_finish);
8dc1f7fc
DL
344 return 0;
345}
346
347static int irdp_module_init(void)
348{
349 hook_register(frr_late_init, irdp_init);
350 return 0;
2eb27eec
DL
351}
352
996c9314
LB
353FRR_MODULE_SETUP(.name = "zebra_irdp", .version = FRR_VERSION,
354 .description = "zebra IRDP module", .init = irdp_module_init, )