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