xref: /openbsd-src/usr.sbin/ripd/message.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: message.c,v 1.15 2019/12/15 20:51:39 remi Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netinet/ip.h>
23 #include <arpa/inet.h>
24 #include <netinet/udp.h>
25 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "ripd.h"
30 #include "rip.h"
31 #include "ripe.h"
32 #include "log.h"
33 
34 extern struct ripd_conf	*oeconf;
35 
36 void	 delete_entry(struct rip_route *);
37 
38 /* timers */
39 /* ARGSUSED */
40 void
41 report_timer(int fd, short event, void *arg)
42 {
43 	struct timeval	 tv;
44 
45 	ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, 0, 0, NULL, 0);
46 
47 	/* restart report timer */
48 	timerclear(&tv);
49 	tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET);
50 	evtimer_add(&oeconf->report_timer, &tv);
51 }
52 
53 int
54 start_report_timer(void)
55 {
56 	struct timeval	 tv;
57 
58 	timerclear(&tv);
59 	tv.tv_sec = KEEPALIVE + arc4random_uniform(OFFSET);
60 	return (evtimer_add(&oeconf->report_timer, &tv));
61 }
62 
63 /* list handlers */
64 void
65 add_entry(struct packet_head *r_list, struct rip_route *rr)
66 {
67 	struct packet_entry	*re;
68 
69 	if (rr == NULL)
70 		fatalx("add_entry: no route report");
71 
72 	if ((re = calloc(1, sizeof(*re))) == NULL)
73 		fatal("add_entry");
74 
75 	TAILQ_INSERT_TAIL(r_list, re, entry);
76 	re->rr = rr;
77 	rr->refcount++;
78 }
79 
80 void
81 delete_entry(struct rip_route *rr)
82 {
83 	if (--rr->refcount == 0)
84 		free(rr);
85 }
86 
87 void
88 clear_list(struct packet_head *r_list)
89 {
90 	struct packet_entry	*re;
91 
92 	while ((re = TAILQ_FIRST(r_list)) != NULL) {
93 		TAILQ_REMOVE(r_list, re, entry);
94 		delete_entry(re->rr);
95 		free(re);
96 	}
97 }
98 
99 /* communications */
100 int
101 send_triggered_update(struct iface *iface, struct rip_route *rr)
102 {
103 	struct sockaddr_in	 dst;
104 	struct ibuf		*buf;
105 	u_int16_t		 afi, route_tag;
106 	u_int32_t		 address, netmask, nexthop, metric;
107 
108 	if (iface->passive)
109 		return (0);
110 
111 	inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
112 
113 	dst.sin_port = htons(RIP_PORT);
114 	dst.sin_family = AF_INET;
115 	dst.sin_len = sizeof(struct sockaddr_in);
116 
117 	if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
118 	    sizeof(struct udphdr))) == NULL)
119 		fatal("send_triggered_update");
120 
121 	gen_rip_hdr(buf, COMMAND_RESPONSE);
122 
123 	afi = htons(AF_INET);
124 	route_tag = 0;
125 
126 	address = rr->address.s_addr;
127 	netmask = rr->mask.s_addr;
128 	nexthop = rr->nexthop.s_addr;
129 	metric = htonl(rr->metric);
130 
131 	ibuf_add(buf, &afi, sizeof(afi));
132 	ibuf_add(buf, &route_tag, sizeof(route_tag));
133 	ibuf_add(buf, &address, sizeof(address));
134 	ibuf_add(buf, &netmask, sizeof(netmask));
135 	ibuf_add(buf, &nexthop, sizeof(nexthop));
136 	ibuf_add(buf, &metric, sizeof(metric));
137 
138 	send_packet(iface, buf->buf, buf->wpos, &dst);
139 	ibuf_free(buf);
140 
141 	return (0);
142 }
143 
144 int
145 send_request(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
146 {
147 	struct ibuf		*buf;
148 	struct iface		*iface;
149 	struct packet_entry	*entry;
150 	struct sockaddr_in	 dst;
151 	u_int8_t		 nentries;
152 	u_int8_t		 single_entry = 0;
153 	u_int32_t		 address, netmask, nexthop;
154 	u_int16_t		 port, afi, route_tag;
155 	u_int32_t		 metric;
156 
157 	if (i == NULL) {
158 		/* directly to a nbr */
159 		iface = nbr->iface;
160 		dst.sin_addr = nbr->addr;
161 		port = htons(nbr->port);
162 	} else {
163 		/* multicast on interface */
164 		iface = i;
165 		inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
166 		port = htons(RIP_PORT);
167 	}
168 
169 	if (iface->passive) {
170 		clear_list(r_list);
171 		return (0);
172 	}
173 
174 	dst.sin_port = port;
175 	dst.sin_family = AF_INET;
176 	dst.sin_len = sizeof(struct sockaddr_in);
177 
178 	while (!TAILQ_EMPTY(r_list)) {
179 		if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
180 		    sizeof(struct udphdr))) == NULL)
181 			fatal("send_request");
182 
183 		gen_rip_hdr(buf, COMMAND_REQUEST);
184 
185 		route_tag = 0;
186 		nentries = 0;
187 
188 		if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head))
189 			single_entry = 1;
190 		while (((entry = TAILQ_FIRST(r_list)) != NULL) &&
191 		    nentries < MAX_RIP_ENTRIES) {
192 			afi = htons(AF_INET);
193 
194 			address = entry->rr->address.s_addr;
195 			netmask = entry->rr->mask.s_addr;
196 			nexthop = entry->rr->nexthop.s_addr;
197 			metric = htonl(entry->rr->metric);
198 
199 			if (metric == htonl(INFINITY) && single_entry)
200 				afi = AF_UNSPEC;
201 
202 			ibuf_add(buf, &afi, sizeof(afi));
203 			ibuf_add(buf, &route_tag, sizeof(route_tag));
204 			ibuf_add(buf, &address, sizeof(address));
205 			ibuf_add(buf, &netmask, sizeof(netmask));
206 			ibuf_add(buf, &nexthop, sizeof(nexthop));
207 			ibuf_add(buf, &metric, sizeof(metric));
208 			nentries++;
209 
210 			TAILQ_REMOVE(r_list, entry, entry);
211 			delete_entry(entry->rr);
212 			free(entry);
213 		}
214 		send_packet(iface, buf->buf, buf->wpos, &dst);
215 		ibuf_free(buf);
216 	}
217 
218 	return (0);
219 }
220 
221 int
222 send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
223 {
224 	struct ibuf		*buf;
225 	struct iface		*iface;
226 	struct packet_entry	*entry;
227 	struct sockaddr_in	 dst;
228 	u_int8_t		 nentries;
229 	u_int16_t		 port, afi, route_tag;
230 	u_int32_t		 address, netmask, nexthop;
231 	u_int32_t		 metric;
232 
233 	if (i == NULL) {
234 		/* directly to a nbr */
235 		iface = nbr->iface;
236 		dst.sin_addr = nbr->addr;
237 		port = htons(nbr->port);
238 	} else {
239 		/* multicast on interface */
240 		iface = i;
241 		inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
242 		port = htons(RIP_PORT);
243 	}
244 
245 	if (iface->passive) {
246 		clear_list(r_list);
247 		return (0);
248 	}
249 
250 	dst.sin_port = port;
251 	dst.sin_family = AF_INET;
252 	dst.sin_len = sizeof(struct sockaddr_in);
253 
254 	while (!TAILQ_EMPTY(r_list)) {
255 		if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
256 		    sizeof(struct udphdr))) == NULL)
257 			fatal("send_response");
258 
259 		gen_rip_hdr(buf, COMMAND_RESPONSE);
260 
261 		afi = htons(AF_INET);
262 		route_tag = 0;
263 		nentries = 0;
264 
265 		if (iface->auth_type != AUTH_NONE) {
266 			if (auth_gen(buf, iface) == -1) {
267 				ibuf_free(buf);
268 				return (-1);
269 			}
270 			nentries++;
271 		}
272 
273 		while ((entry = TAILQ_FIRST(r_list)) != NULL &&
274 		    nentries < MAX_RIP_ENTRIES) {
275 			address = entry->rr->address.s_addr;
276 			netmask = entry->rr->mask.s_addr;
277 			nexthop = entry->rr->nexthop.s_addr;
278 			metric = htonl(entry->rr->metric);
279 
280 			if (entry->rr->ifindex == iface->ifindex) {
281 				if (oeconf->options & OPT_SPLIT_HORIZON)
282 					goto free;
283 				else if (oeconf->options & OPT_SPLIT_POISONED)
284 					metric = htonl(INFINITY);
285 			}
286 
287 			/* If the nexthop is not reachable through the
288 			 * outgoing interface set it to INADDR_ANY */
289 			if ((nexthop & iface->mask.s_addr) !=
290 			    (iface->addr.s_addr & iface->mask.s_addr))
291 				nexthop = INADDR_ANY;
292 
293 			ibuf_add(buf, &afi, sizeof(afi));
294 			ibuf_add(buf, &route_tag, sizeof(route_tag));
295 			ibuf_add(buf, &address, sizeof(address));
296 			ibuf_add(buf, &netmask, sizeof(netmask));
297 			ibuf_add(buf, &nexthop, sizeof(nexthop));
298 			ibuf_add(buf, &metric, sizeof(metric));
299 			nentries++;
300 free:
301 			TAILQ_REMOVE(r_list, entry, entry);
302 			delete_entry(entry->rr);
303 			free(entry);
304 		}
305 
306 		if (iface->auth_type == AUTH_CRYPT)
307 			auth_add_trailer(buf, iface);
308 
309 		send_packet(iface, buf->buf, buf->wpos, &dst);
310 		ibuf_free(buf);
311 	}
312 
313 	return (0);
314 }
315 
316 void
317 recv_request(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
318 {
319 	struct rip_entry	*e;
320 	struct rip_route	 rr;
321 	int			 l = len;
322 
323 	bzero(&rr, sizeof(rr));
324 
325 	if (len < RIP_ENTRY_LEN) {
326 		log_debug("recv_request: bad packet size, interface %s",
327 		    i->name);
328 		return;
329 	}
330 
331 	/*
332 	 * XXX is it guaranteed that bus is properly aligned.
333 	 * If not this will bomb on strict alignment archs.
334 	 * */
335 	e = (struct rip_entry *)buf;
336 
337 	if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
338 		log_debug("recv_request: packet too long\n");
339 		return;
340 	}
341 
342 	l -= RIP_ENTRY_LEN;
343 
344 	/*
345 	 * If there is exactly one entry in the request, and it has
346 	 * an address family identifier of zero and a metric of
347 	 * infinity (i.e., 16), then this is a request to send the
348 	 * entire routing table.
349 	 */
350 	if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) {
351 		ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid,
352 		    0, NULL, 0);
353 		return;
354 	}
355 
356 	for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
357 		if (e->AFI != AF_INET) {
358 			log_debug("recv_request: AFI %d not supported\n",
359 			    e->AFI);
360 			return;
361 		}
362 		rr.address.s_addr = e->address;
363 		rr.mask.s_addr = e->mask;
364 		rr.nexthop.s_addr = e->nexthop;
365 		rr.metric = e->metric;
366 		rr.ifindex = i->ifindex;
367 
368 		ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid,
369 		    0, &rr, sizeof(rr));
370 
371 		e++;
372 	}
373 
374 	ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid,
375 	    0, NULL, 0);
376 }
377 
378 void
379 recv_response(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
380 {
381 	struct rip_route	 r;
382 	struct rip_entry	*e;
383 	int			 l;
384 
385 	if (len < RIP_ENTRY_LEN) {
386 		log_debug("recv_response: bad packet size, interface %s",
387 		    i->name);
388 		return;
389 	}
390 
391 	/* We must double check the length, because the only entry
392 	 * can be stripped off by authentication code
393 	 */
394 	if (len < RIP_ENTRY_LEN) {
395 		/* If there are no entries, our work is finished here */
396 		return;
397 	}
398 
399 	/* XXX again */
400 	e = (struct rip_entry *)buf;
401 
402 	if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
403 		log_debug("recv_response: packet too long\n");
404 		return;
405 	}
406 
407 	l = len - sizeof(*e);
408 
409 	for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
410 		if (ntohs(e->AFI) != AF_INET) {
411 			log_debug("recv_response: AFI %d not supported\n",
412 			    e->AFI);
413 			return;
414 		}
415 
416 		r.address.s_addr = e->address;
417 		r.mask.s_addr = e->mask;
418 
419 		if (e->nexthop == INADDR_ANY ||
420 		    ((i->addr.s_addr & i->mask.s_addr) !=
421 		    (e->nexthop & i->mask.s_addr)))
422 			r.nexthop.s_addr = nbr->addr.s_addr;
423 		else
424 			r.nexthop.s_addr = e->nexthop;
425 
426 		r.metric = ntohl(e->metric);
427 		r.ifindex = i->ifindex;
428 
429 		ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, &r, sizeof(r));
430 
431 		e++;
432 	}
433 }
434