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