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