xref: /openbsd/usr.sbin/ldpd/packet.c (revision a6445c1d)
1 /*	$OpenBSD: packet.c,v 1.36 2014/10/25 03:23:49 lteo Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
5  * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/uio.h>
23 
24 #include <netinet/in.h>
25 #include <netinet/ip.h>
26 #include <arpa/inet.h>
27 #include <net/if_dl.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 
31 #include <errno.h>
32 #include <event.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "ldpd.h"
37 #include "ldp.h"
38 #include "log.h"
39 #include "ldpe.h"
40 
41 extern struct ldpd_conf        *leconf;
42 
43 struct iface	*disc_find_iface(unsigned int, struct in_addr);
44 ssize_t		 session_get_pdu(struct ibuf_read *, char **);
45 
46 static int	 msgcnt = 0;
47 
48 int
49 gen_ldp_hdr(struct ibuf *buf, u_int16_t size)
50 {
51 	struct ldp_hdr	ldp_hdr;
52 
53 	bzero(&ldp_hdr, sizeof(ldp_hdr));
54 	ldp_hdr.version = htons(LDP_VERSION);
55 
56 	/* We want just the size of the value */
57 	size -= TLV_HDR_LEN;
58 
59 	ldp_hdr.length = htons(size);
60 	ldp_hdr.lsr_id = ldpe_router_id();
61 	ldp_hdr.lspace_id = 0;
62 
63 	return (ibuf_add(buf, &ldp_hdr, LDP_HDR_SIZE));
64 }
65 
66 int
67 gen_msg_tlv(struct ibuf *buf, u_int32_t type, u_int16_t size)
68 {
69 	struct ldp_msg	msg;
70 
71 	/* We want just the size of the value */
72 	size -= TLV_HDR_LEN;
73 
74 	bzero(&msg, sizeof(msg));
75 	msg.type = htons(type);
76 	msg.length = htons(size);
77 	if (type != MSG_TYPE_HELLO)
78 		msg.msgid = htonl(++msgcnt);
79 
80 	return (ibuf_add(buf, &msg, sizeof(msg)));
81 }
82 
83 /* send packets */
84 int
85 send_packet(int fd, struct iface *iface, void *pkt, size_t len,
86     struct sockaddr_in *dst)
87 {
88 	/* set outgoing interface for multicast traffic */
89 	if (iface && IN_MULTICAST(ntohl(dst->sin_addr.s_addr)))
90 		if (if_set_mcast(iface) == -1) {
91 			log_warn("send_packet: error setting multicast "
92 			    "interface, %s", iface->name);
93 			return (-1);
94 		}
95 
96 	if (sendto(fd, pkt, len, 0, (struct sockaddr *)dst,
97 	    sizeof(*dst)) == -1) {
98 		log_warn("send_packet: error sending packet");
99 		return (-1);
100 	}
101 
102 	return (0);
103 }
104 
105 /* Discovery functions */
106 void
107 disc_recv_packet(int fd, short event, void *bula)
108 {
109 	union {
110 		struct cmsghdr hdr;
111 		char	buf[CMSG_SPACE(sizeof(struct sockaddr_dl))];
112 	} cmsgbuf;
113 	struct sockaddr_in	 src;
114 	struct msghdr		 msg;
115 	struct iovec		 iov;
116 	struct ldp_hdr		 ldp_hdr;
117 	struct ldp_msg		 ldp_msg;
118 	struct iface		*iface = NULL;
119 	char			*buf;
120 	struct cmsghdr		*cmsg;
121 	ssize_t			 r;
122 	u_int16_t		 len;
123 	unsigned int		 ifindex = 0;
124 
125 	if (event != EV_READ)
126 		return;
127 
128 	/* setup buffer */
129 	bzero(&msg, sizeof(msg));
130 	iov.iov_base = buf = pkt_ptr;
131 	iov.iov_len = IBUF_READ_SIZE;
132 	msg.msg_name = &src;
133 	msg.msg_namelen = sizeof(src);
134 	msg.msg_iov = &iov;
135 	msg.msg_iovlen = 1;
136 	msg.msg_control = &cmsgbuf.buf;
137 	msg.msg_controllen = sizeof(cmsgbuf.buf);
138 
139 	if ((r = recvmsg(fd, &msg, 0)) == -1) {
140 		if (errno != EAGAIN && errno != EINTR)
141 			log_debug("disc_recv_packet: read error: %s",
142 			    strerror(errno));
143 		return;
144 	}
145 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
146 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
147 		if (cmsg->cmsg_level == IPPROTO_IP &&
148 		    cmsg->cmsg_type == IP_RECVIF) {
149 			ifindex = ((struct sockaddr_dl *)
150 			    CMSG_DATA(cmsg))->sdl_index;
151 			break;
152 		}
153 	}
154 
155 	len = (u_int16_t)r;
156 
157 	/* find a matching interface */
158 	if ((fd == leconf->ldp_discovery_socket) &&
159 	    (iface = disc_find_iface(ifindex, src.sin_addr)) == NULL) {
160 		log_debug("disc_recv_packet: cannot find a matching interface");
161 		return;
162 	}
163 
164 	/* LDP header sanity checks */
165 	if (len < LDP_HDR_SIZE || len > LDP_MAX_LEN) {
166 		log_debug("disc_recv_packet: bad packet size");
167 		return;
168 	}
169 	bcopy(buf, &ldp_hdr, sizeof(ldp_hdr));
170 
171 	if (ntohs(ldp_hdr.version) != LDP_VERSION) {
172 		log_debug("dsc_recv_packet: invalid LDP version %d",
173 		    ldp_hdr.version);
174 		return;
175 	}
176 
177 	if (ntohs(ldp_hdr.length) >
178 	    len - sizeof(ldp_hdr.version) - sizeof(ldp_hdr.length)) {
179 		log_debug("disc_recv_packet: invalid LDP packet length %u",
180 		    ntohs(ldp_hdr.length));
181 		return;
182 	}
183 
184 	if (len < LDP_HDR_SIZE + LDP_MSG_LEN) {
185 		log_debug("disc_recv_packet: invalid LDP packet length %d",
186 		    ntohs(ldp_hdr.length));
187 		return;
188 	}
189 
190 	bcopy(buf + LDP_HDR_SIZE, &ldp_msg, sizeof(ldp_msg));
191 
192 	/* switch LDP packet type */
193 	switch (ntohs(ldp_msg.type)) {
194 	case MSG_TYPE_HELLO:
195 		recv_hello(iface, src.sin_addr, buf, len);
196 		break;
197 	default:
198 		log_debug("recv_packet: unknown LDP packet type, source %s",
199 		    inet_ntoa(src.sin_addr));
200 	}
201 }
202 
203 struct iface *
204 disc_find_iface(unsigned int ifindex, struct in_addr src)
205 {
206 	struct iface	*iface;
207 	struct if_addr	*if_addr;
208 
209 	LIST_FOREACH(iface, &leconf->iface_list, entry)
210 		LIST_FOREACH(if_addr, &iface->addr_list, iface_entry)
211 			switch (iface->type) {
212 			case IF_TYPE_POINTOPOINT:
213 				if (ifindex == iface->ifindex &&
214 				    if_addr->dstbrd.s_addr == src.s_addr)
215 					return (iface);
216 				break;
217 			default:
218 				if (ifindex == iface->ifindex &&
219 				    (if_addr->addr.s_addr &
220 					if_addr->mask.s_addr) ==
221 				    (src.s_addr & if_addr->mask.s_addr))
222 					return (iface);
223 				break;
224 			}
225 
226 	return (NULL);
227 }
228 
229 struct tcp_conn *
230 tcp_new(int fd, struct nbr *nbr)
231 {
232 	struct tcp_conn *tcp;
233 
234 	if ((tcp = calloc(1, sizeof(*tcp))) == NULL)
235 		fatal("tcp_new");
236 	if ((tcp->rbuf = calloc(1, sizeof(struct ibuf_read))) == NULL)
237 		fatal("tcp_new");
238 
239 	if (nbr)
240 		tcp->nbr = nbr;
241 
242 	tcp->fd = fd;
243 	evbuf_init(&tcp->wbuf, tcp->fd, session_write, tcp);
244 	event_set(&tcp->rev, tcp->fd, EV_READ | EV_PERSIST, session_read, tcp);
245 	event_add(&tcp->rev, NULL);
246 
247 	return (tcp);
248 }
249 
250 void
251 tcp_close(struct tcp_conn *tcp)
252 {
253 	evbuf_clear(&tcp->wbuf);
254 	event_del(&tcp->rev);
255 	close(tcp->fd);
256 	free(tcp->rbuf);
257 	free(tcp);
258 }
259 
260 void
261 session_accept(int fd, short event, void *bula)
262 {
263 	struct sockaddr_in	 src;
264 	int			 newfd;
265 	socklen_t		 len = sizeof(src);
266 
267 	if (!(event & EV_READ))
268 		return;
269 
270 	newfd = accept(fd, (struct sockaddr *)&src, &len);
271 	if (newfd == -1) {
272 		/*
273 		 * Pause accept if we are out of file descriptors, or
274 		 * libevent will haunt us here too.
275 		 */
276 		if (errno == ENFILE || errno == EMFILE) {
277 			accept_pause();
278 		} else if (errno != EWOULDBLOCK && errno != EINTR &&
279 		    errno != ECONNABORTED)
280 			log_debug("sess_recv_packet: accept error: %s",
281 			    strerror(errno));
282 		return;
283 	}
284 
285 	session_socket_blockmode(newfd, BM_NONBLOCK);
286 
287 	tcp_new(newfd, NULL);
288 }
289 
290 void
291 session_read(int fd, short event, void *arg)
292 {
293 	struct tcp_conn	*tcp = arg;
294 	struct nbr	*nbr = tcp->nbr;
295 	struct ldp_hdr	*ldp_hdr;
296 	struct ldp_msg	*ldp_msg;
297 	char		*buf, *pdu;
298 	ssize_t		 n, len;
299 	int		 msg_size;
300 	u_int16_t	 pdu_len;
301 
302 	if (event != EV_READ) {
303 		log_debug("session_read: spurious event");
304 		return;
305 	}
306 
307 	if ((n = read(fd, tcp->rbuf->buf + tcp->rbuf->wpos,
308 	    sizeof(tcp->rbuf->buf) - tcp->rbuf->wpos)) == -1) {
309 		if (errno != EINTR && errno != EAGAIN) {
310 			log_warn("session_read: read error");
311 			if (nbr)
312 				nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
313 			else
314 				tcp_close(tcp);
315 			return;
316 		}
317 		/* retry read */
318 		return;
319 	}
320 	if (n == 0) {
321 		/* connection closed */
322 		log_debug("session_read: connection closed by remote end");
323 		if (nbr)
324 			nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
325 		else
326 			tcp_close(tcp);
327 		return;
328 	}
329 	tcp->rbuf->wpos += n;
330 
331 	while ((len = session_get_pdu(tcp->rbuf, &buf)) > 0) {
332 		pdu = buf;
333 		ldp_hdr = (struct ldp_hdr *)pdu;
334 		if (ntohs(ldp_hdr->version) != LDP_VERSION) {
335 			if (nbr)
336 				session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0);
337 			else {
338 				send_notification(S_BAD_PROTO_VER, tcp, 0, 0);
339 				msgbuf_write(&tcp->wbuf.wbuf);
340 				tcp_close(tcp);
341 			}
342 			free(buf);
343 			return;
344 		}
345 
346 		pdu_len = ntohs(ldp_hdr->length);
347 		if (pdu_len < (LDP_HDR_PDU_LEN + LDP_MSG_LEN) ||
348 		    pdu_len > LDP_MAX_LEN) {
349 			if (nbr)
350 				session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0);
351 			else {
352 				send_notification(S_BAD_PDU_LEN, tcp, 0, 0);
353 				msgbuf_write(&tcp->wbuf.wbuf);
354 				tcp_close(tcp);
355 			}
356 			free(buf);
357 			return;
358 		}
359 
360 		if (nbr) {
361 			if (ldp_hdr->lsr_id != nbr->id.s_addr ||
362 			    ldp_hdr->lspace_id != 0) {
363 				session_shutdown(nbr, S_BAD_LDP_ID, 0, 0);
364 				free(buf);
365 				return;
366 			}
367 		} else {
368 			nbr = nbr_find_ldpid(ldp_hdr->lsr_id);
369 			if (!nbr) {
370 				send_notification(S_NO_HELLO, tcp, 0, 0);
371 				msgbuf_write(&tcp->wbuf.wbuf);
372 				tcp_close(tcp);
373 				free(buf);
374 				return;
375 			}
376 			/* handle duplicate SYNs */
377 			if (nbr->tcp) {
378 				tcp_close(tcp);
379 				free(buf);
380 				return;
381 			}
382 
383 			nbr->tcp = tcp;
384 			tcp->nbr = nbr;
385 			nbr_fsm(nbr, NBR_EVT_MATCH_ADJ);
386 		}
387 
388 		pdu += LDP_HDR_SIZE;
389 		len -= LDP_HDR_SIZE;
390 
391 		if (nbr->state == NBR_STA_OPER)
392 			nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
393 
394 		while (len >= LDP_MSG_LEN) {
395 			u_int16_t type;
396 
397 			ldp_msg = (struct ldp_msg *)pdu;
398 			type = ntohs(ldp_msg->type);
399 
400 			pdu_len = ntohs(ldp_msg->length) + TLV_HDR_LEN;
401 			if (pdu_len > len ||
402 			    pdu_len < LDP_MSG_LEN - TLV_HDR_LEN) {
403 				session_shutdown(nbr, S_BAD_TLV_LEN,
404 				    ldp_msg->msgid, ldp_msg->type);
405 				free(buf);
406 				return;
407 			}
408 
409 			/* check for error conditions earlier */
410 			switch (type) {
411 			case MSG_TYPE_INIT:
412 				if ((nbr->state != NBR_STA_INITIAL) &&
413 				    (nbr->state != NBR_STA_OPENSENT)) {
414 					session_shutdown(nbr, S_SHUTDOWN,
415 					    ldp_msg->msgid, ldp_msg->type);
416 					free(buf);
417 					return;
418 				}
419 				break;
420 			case MSG_TYPE_KEEPALIVE:
421 				if ((nbr->state == NBR_STA_INITIAL) ||
422 				    (nbr->state == NBR_STA_OPENSENT)) {
423 					session_shutdown(nbr, S_SHUTDOWN,
424 					    ldp_msg->msgid, ldp_msg->type);
425 					free(buf);
426 					return;
427 				}
428 				break;
429 			case MSG_TYPE_NOTIFICATION:
430 			case MSG_TYPE_ADDR:
431 			case MSG_TYPE_ADDRWITHDRAW:
432 			case MSG_TYPE_LABELMAPPING:
433 			case MSG_TYPE_LABELREQUEST:
434 			case MSG_TYPE_LABELWITHDRAW:
435 			case MSG_TYPE_LABELRELEASE:
436 			case MSG_TYPE_LABELABORTREQ:
437 			default:
438 				if (nbr->state != NBR_STA_OPER) {
439 					session_shutdown(nbr, S_SHUTDOWN,
440 					    ldp_msg->msgid, ldp_msg->type);
441 					free(buf);
442 					return;
443 				}
444 				break;
445 			}
446 
447 			/* switch LDP packet type */
448 			switch (type) {
449 			case MSG_TYPE_NOTIFICATION:
450 				msg_size = recv_notification(nbr, pdu, pdu_len);
451 				break;
452 			case MSG_TYPE_INIT:
453 				msg_size = recv_init(nbr, pdu, pdu_len);
454 				break;
455 			case MSG_TYPE_KEEPALIVE:
456 				msg_size = recv_keepalive(nbr, pdu, pdu_len);
457 				break;
458 			case MSG_TYPE_ADDR:
459 			case MSG_TYPE_ADDRWITHDRAW:
460 				msg_size = recv_address(nbr, pdu, pdu_len);
461 				break;
462 			case MSG_TYPE_LABELMAPPING:
463 			case MSG_TYPE_LABELREQUEST:
464 			case MSG_TYPE_LABELWITHDRAW:
465 			case MSG_TYPE_LABELRELEASE:
466 			case MSG_TYPE_LABELABORTREQ:
467 				msg_size = recv_labelmessage(nbr, pdu,
468 				    pdu_len, type);
469 				break;
470 			default:
471 				log_debug("session_read: unknown LDP packet "
472 				    "from nbr %s", inet_ntoa(nbr->id));
473 				if (!(ntohs(ldp_msg->type) & UNKNOWN_FLAG)) {
474 					session_shutdown(nbr, S_UNKNOWN_MSG,
475 					    ldp_msg->msgid, ldp_msg->type);
476 					free(buf);
477 					return;
478 				}
479 				/* unknown flag is set, ignore the message */
480 				msg_size = ntohs(ldp_msg->length);
481 				break;
482 			}
483 
484 			if (msg_size == -1) {
485 				/* parser failed, giving up */
486 				free(buf);
487 				return;
488 			}
489 
490 			/* Analyse the next message */
491 			pdu += msg_size + TLV_HDR_LEN;
492 			len -= msg_size + TLV_HDR_LEN;
493 		}
494 		free(buf);
495 		if (len != 0) {
496 			session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0);
497 			return;
498 		}
499 	}
500 }
501 
502 void
503 session_write(int fd, short event, void *arg)
504 {
505 	struct tcp_conn *tcp = arg;
506 	struct nbr *nbr = tcp->nbr;
507 
508 	if (event & EV_WRITE) {
509 		if (msgbuf_write(&tcp->wbuf.wbuf) <= 0 && errno != EAGAIN) {
510 			if (nbr)
511 				nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
512 		}
513 	} else
514 		log_debug("session_write: spurious event");
515 
516 	evbuf_event_add(&tcp->wbuf);
517 }
518 
519 void
520 session_shutdown(struct nbr *nbr, u_int32_t status, u_int32_t msgid,
521     u_int32_t type)
522 {
523 	log_debug("session_shutdown: nbr ID %s", inet_ntoa(nbr->id));
524 
525 	send_notification_nbr(nbr, status, msgid, type);
526 
527 	/* try to flush write buffer, if it fails tough shit */
528 	msgbuf_write(&nbr->tcp->wbuf.wbuf);
529 
530 	nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
531 }
532 
533 void
534 session_close(struct nbr *nbr)
535 {
536 	log_debug("session_close: closing session with nbr ID %s",
537 	    inet_ntoa(nbr->id));
538 
539 	tcp_close(nbr->tcp);
540 	nbr->tcp = NULL;
541 
542 	nbr_stop_ktimer(nbr);
543 	nbr_stop_ktimeout(nbr);
544 
545 	accept_unpause();
546 }
547 
548 ssize_t
549 session_get_pdu(struct ibuf_read *r, char **b)
550 {
551 	struct ldp_hdr	l;
552 	size_t		av, dlen, left;
553 
554 	av = r->wpos;
555 	if (av < sizeof(l))
556 		return (0);
557 
558 	memcpy(&l, r->buf, sizeof(l));
559 	dlen = ntohs(l.length) + TLV_HDR_LEN;
560 	if (dlen > av)
561 		return (0);
562 
563 	if ((*b = malloc(dlen)) == NULL)
564 		return (-1);
565 
566 	memcpy(*b, r->buf, dlen);
567 	if (dlen < av) {
568 		left = av - dlen;
569 		memmove(r->buf, r->buf + dlen, left);
570 		r->wpos = left;
571 	} else
572 		r->wpos = 0;
573 
574 	return (dlen);
575 }
576