xref: /openbsd-src/usr.sbin/ripd/message.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /*	$OpenBSD: message.c,v 1.12 2014/10/25 03:23:49 lteo 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_response");
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 	inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
109 
110 	dst.sin_port = htons(RIP_PORT);
111 	dst.sin_family = AF_INET;
112 	dst.sin_len = sizeof(struct sockaddr_in);
113 
114 	if (iface->passive)
115 		return (0);
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 	dst.sin_port = port;
170 	dst.sin_family = AF_INET;
171 	dst.sin_len = sizeof(struct sockaddr_in);
172 
173 	if (iface->passive)
174 		return (0);
175 
176 	while (!TAILQ_EMPTY(r_list)) {
177 		if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
178 		    sizeof(struct udphdr))) == NULL)
179 			fatal("send_request");
180 
181 		gen_rip_hdr(buf, COMMAND_REQUEST);
182 
183 		route_tag = 0;
184 		nentries = 0;
185 
186 		if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head))
187 			single_entry = 1;
188 		while (((entry = TAILQ_FIRST(r_list)) != NULL) &&
189 		    nentries < MAX_RIP_ENTRIES) {
190 			afi = htons(AF_INET);
191 
192 			address = entry->rr->address.s_addr;
193 			netmask = entry->rr->mask.s_addr;
194 			nexthop = entry->rr->nexthop.s_addr;
195 			metric = htonl(entry->rr->metric);
196 
197 			if (metric == htonl(INFINITY) && single_entry)
198 				afi = AF_UNSPEC;
199 
200 			ibuf_add(buf, &afi, sizeof(afi));
201 			ibuf_add(buf, &route_tag, sizeof(route_tag));
202 			ibuf_add(buf, &address, sizeof(address));
203 			ibuf_add(buf, &netmask, sizeof(netmask));
204 			ibuf_add(buf, &nexthop, sizeof(nexthop));
205 			ibuf_add(buf, &metric, sizeof(metric));
206 
207 			TAILQ_REMOVE(r_list, entry, entry);
208 			delete_entry(entry->rr);
209 			free(entry);
210 			nentries++;
211 		}
212 		send_packet(iface, buf->buf, buf->wpos, &dst);
213 		ibuf_free(buf);
214 	}
215 
216 	return (0);
217 }
218 
219 int
220 send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
221 {
222 	struct ibuf		*buf;
223 	struct iface		*iface;
224 	struct packet_entry	*entry;
225 	struct sockaddr_in	 dst;
226 	u_int8_t		 nentries;
227 	u_int16_t		 port, afi, route_tag;
228 	u_int32_t		 address, netmask, nexthop;
229 	u_int32_t		 metric;
230 
231 	if (i == NULL) {
232 		/* directly to a nbr */
233 		iface = nbr->iface;
234 		dst.sin_addr = nbr->addr;
235 		port = htons(nbr->port);
236 	} else {
237 		/* multicast on interface */
238 		iface = i;
239 		inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
240 		port = htons(RIP_PORT);
241 	}
242 
243 	dst.sin_port = port;
244 	dst.sin_family = AF_INET;
245 	dst.sin_len = sizeof(struct sockaddr_in);
246 
247 	if (iface->passive)
248 		return (0);
249 
250 	while (!TAILQ_EMPTY(r_list)) {
251 		if ((buf = ibuf_open(iface->mtu - sizeof(struct ip) -
252 		    sizeof(struct udphdr))) == NULL)
253 			fatal("send_response");
254 
255 		gen_rip_hdr(buf, COMMAND_RESPONSE);
256 
257 		afi = htons(AF_INET);
258 		route_tag = 0;
259 		nentries = 0;
260 
261 		if (iface->auth_type != AUTH_NONE) {
262 			if (auth_gen(buf, iface) == -1) {
263 				ibuf_free(buf);
264 				return (-1);
265 			}
266 			nentries++;
267 		}
268 
269 		while ((entry = TAILQ_FIRST(r_list)) != NULL &&
270 		    nentries < MAX_RIP_ENTRIES) {
271 			address = entry->rr->address.s_addr;
272 			netmask = entry->rr->mask.s_addr;
273 			nexthop = entry->rr->nexthop.s_addr;
274 			metric = htonl(entry->rr->metric);
275 
276 			if (entry->rr->ifindex == iface->ifindex) {
277 				if (oeconf->options & OPT_SPLIT_HORIZON)
278 					goto free;
279 				else if (oeconf->options & OPT_SPLIT_POISONED)
280 					metric = htonl(INFINITY);
281 			}
282 
283 			/* If the nexthop is not reachable through the
284 			 * outgoing interface set it to INADDR_ANY */
285 			if ((nexthop & iface->mask.s_addr) !=
286 			    (iface->addr.s_addr & iface->mask.s_addr))
287 				nexthop = INADDR_ANY;
288 
289 			ibuf_add(buf, &afi, sizeof(afi));
290 			ibuf_add(buf, &route_tag, sizeof(route_tag));
291 			ibuf_add(buf, &address, sizeof(address));
292 			ibuf_add(buf, &netmask, sizeof(netmask));
293 			ibuf_add(buf, &nexthop, sizeof(nexthop));
294 			ibuf_add(buf, &metric, sizeof(metric));
295 free:
296 			TAILQ_REMOVE(r_list, entry, entry);
297 			delete_entry(entry->rr);
298 			free(entry);
299 			nentries++;
300 		}
301 
302 		if (iface->auth_type == AUTH_CRYPT)
303 			auth_add_trailer(buf, iface);
304 
305 		send_packet(iface, buf->buf, buf->wpos, &dst);
306 		ibuf_free(buf);
307 	}
308 
309 	return (0);
310 }
311 
312 void
313 recv_request(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
314 {
315 	struct rip_entry	*e;
316 	struct rip_route	 rr;
317 	int			 l = len;
318 
319 	bzero(&rr, sizeof(rr));
320 
321 	if (len < RIP_ENTRY_LEN) {
322 		log_debug("recv_request: bad packet size, interface %s",
323 		    i->name);
324 		return;
325 	}
326 
327 	/*
328 	 * XXX is it guaranteed that bus is properly aligned.
329 	 * If not this will bomb on strict alignment archs.
330 	 * */
331 	e = (struct rip_entry *)buf;
332 
333 	if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
334 		log_debug("recv_request: packet too long\n");
335 		return;
336 	}
337 
338 	l -= RIP_ENTRY_LEN;
339 
340 	/*
341 	 * If there is exactly one entry in the request, and it has
342 	 * an address family identifier of zero and a metric of
343 	 * infinity (i.e., 16), then this is a request to send the
344 	 * entire routing table.
345 	 */
346 	if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) {
347 		ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid,
348 		    0, NULL, 0);
349 		return;
350 	}
351 
352 	for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
353 		if (e->AFI != AF_INET) {
354 			log_debug("recv_request: AFI %d not supported\n",
355 			    e->AFI);
356 			return;
357 		}
358 		rr.address.s_addr = e->address;
359 		rr.mask.s_addr = e->mask;
360 		rr.nexthop.s_addr = e->nexthop;
361 		rr.metric = e->metric;
362 		rr.ifindex = i->ifindex;
363 
364 		ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid,
365 		    0, &rr, sizeof(rr));
366 
367 		e++;
368 	}
369 
370 	ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid,
371 	    0, NULL, 0);
372 }
373 
374 void
375 recv_response(struct iface *i, struct nbr *nbr, u_int8_t *buf, u_int16_t len)
376 {
377 	struct rip_route	 r;
378 	struct rip_entry	*e;
379 	int			 l;
380 
381 	if (len < RIP_ENTRY_LEN) {
382 		log_debug("recv_response: bad packet size, interface %s",
383 		    i->name);
384 		return;
385 	}
386 
387 	/* We must double check the length, because the only entry
388 	 * can be stripped off by authentication code
389 	 */
390 	if (len < RIP_ENTRY_LEN) {
391 		/* If there are no entries, our work is finished here */
392 		return;
393 	}
394 
395 	/* XXX again */
396 	e = (struct rip_entry *)buf;
397 
398 	if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
399 		log_debug("recv_response: packet too long\n");
400 		return;
401 	}
402 
403 	l = len - sizeof(*e);
404 
405 	for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
406 		if (ntohs(e->AFI) != AF_INET) {
407 			log_debug("recv_response: AFI %d not supported\n",
408 			    e->AFI);
409 			return;
410 		}
411 
412 		r.address.s_addr = e->address;
413 		r.mask.s_addr = e->mask;
414 
415 		if (e->nexthop == INADDR_ANY ||
416 		    ((i->addr.s_addr & i->mask.s_addr) !=
417 		    (e->nexthop & i->mask.s_addr)))
418 			r.nexthop.s_addr = nbr->addr.s_addr;
419 		else
420 			r.nexthop.s_addr = e->nexthop;
421 
422 		r.metric = ntohl(e->metric);
423 		r.ifindex = i->ifindex;
424 
425 		ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, &r, sizeof(r));
426 
427 		e++;
428 	}
429 }
430