1 /* $OpenBSD: packet.c,v 1.16 2012/04/12 17:33:43 claudio 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/in_systm.h> 26 #include <netinet/ip.h> 27 #include <arpa/inet.h> 28 #include <net/if_dl.h> 29 #include <fcntl.h> 30 #include <unistd.h> 31 32 #include <errno.h> 33 #include <event.h> 34 #include <stdlib.h> 35 #include <string.h> 36 37 #include "ldpd.h" 38 #include "ldp.h" 39 #include "log.h" 40 #include "ldpe.h" 41 42 int ldp_hdr_sanity_check(struct ldp_hdr *, u_int16_t, 43 const struct iface *); 44 struct iface *find_iface(struct ldpd_conf *, unsigned int, struct in_addr); 45 ssize_t session_get_pdu(struct ibuf_read *, char **); 46 47 static int msgcnt = 0; 48 49 int 50 gen_ldp_hdr(struct ibuf *buf, struct iface *iface, u_int16_t size) 51 { 52 struct ldp_hdr ldp_hdr; 53 54 bzero(&ldp_hdr, sizeof(ldp_hdr)); 55 ldp_hdr.version = htons(LDP_VERSION); 56 57 /* We want just the size of the value */ 58 size -= TLV_HDR_LEN; 59 60 ldp_hdr.length = htons(size); 61 ldp_hdr.lsr_id = ldpe_router_id(); 62 if (iface) 63 ldp_hdr.lspace_id = iface->lspace_id; 64 65 return (ibuf_add(buf, &ldp_hdr, LDP_HDR_SIZE)); 66 } 67 68 int 69 gen_msg_tlv(struct ibuf *buf, u_int32_t type, u_int16_t size) 70 { 71 struct ldp_msg msg; 72 73 /* We want just the size of the value */ 74 size -= TLV_HDR_LEN; 75 76 bzero(&msg, sizeof(msg)); 77 msg.type = htons(type); 78 msg.length = htons(size); 79 msg.msgid = htonl(++msgcnt); 80 81 return (ibuf_add(buf, &msg, sizeof(msg))); 82 } 83 84 /* send and receive packets */ 85 int 86 send_packet(struct iface *iface, void *pkt, size_t len, struct sockaddr_in *dst) 87 { 88 /* set outgoing interface for multicast traffic */ 89 if (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(iface->discovery_fd, pkt, len, 0, 97 (struct sockaddr *)dst, sizeof(*dst)) == -1) { 98 log_warn("send_packet: error sending packet on interface %s", 99 iface->name); 100 return (-1); 101 } 102 103 return (0); 104 } 105 106 /* Discovery functions */ 107 void 108 disc_recv_packet(int fd, short event, void *bula) 109 { 110 union { 111 struct cmsghdr hdr; 112 char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; 113 } cmsgbuf; 114 struct sockaddr_in src; 115 struct msghdr msg; 116 struct iovec iov; 117 struct ldpd_conf *xconf = bula; 118 struct ldp_hdr ldp_hdr; 119 struct ldp_msg ldp_msg; 120 struct iface *iface; 121 char *buf; 122 struct cmsghdr *cmsg; 123 ssize_t r; 124 u_int16_t len; 125 int l; 126 unsigned int ifindex = 0; 127 128 if (event != EV_READ) 129 return; 130 131 /* setup buffer */ 132 bzero(&msg, sizeof(msg)); 133 iov.iov_base = buf = pkt_ptr; 134 iov.iov_len = IBUF_READ_SIZE; 135 msg.msg_name = &src; 136 msg.msg_namelen = sizeof(src); 137 msg.msg_iov = &iov; 138 msg.msg_iovlen = 1; 139 msg.msg_control = &cmsgbuf.buf; 140 msg.msg_controllen = sizeof(cmsgbuf.buf); 141 142 if ((r = recvmsg(fd, &msg, 0)) == -1) { 143 if (errno != EAGAIN && errno != EINTR) 144 log_debug("disc_recv_packet: read error: %s", 145 strerror(errno)); 146 return; 147 } 148 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 149 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 150 if (cmsg->cmsg_level == IPPROTO_IP && 151 cmsg->cmsg_type == IP_RECVIF) { 152 ifindex = ((struct sockaddr_dl *) 153 CMSG_DATA(cmsg))->sdl_index; 154 break; 155 } 156 } 157 158 len = (u_int16_t)r; 159 160 /* find a matching interface */ 161 if ((iface = find_iface(xconf, ifindex, src.sin_addr)) == NULL) { 162 log_debug("disc_recv_packet: cannot find a matching interface"); 163 return; 164 } 165 166 /* LDP header sanity checks */ 167 if (len < LDP_HDR_SIZE || len > LDP_MAX_LEN) { 168 log_debug("disc_recv_packet: bad packet size"); 169 return; 170 } 171 bcopy(buf, &ldp_hdr, sizeof(ldp_hdr)); 172 173 if (ntohs(ldp_hdr.version) != LDP_VERSION) { 174 log_debug("dsc_recv_packet: invalid LDP version %d", 175 ldp_hdr.version); 176 return; 177 } 178 179 if ((l = ldp_hdr_sanity_check(&ldp_hdr, len, iface)) == -1) 180 return; 181 182 if (l > len) { 183 log_debug("disc_recv_packet: invalid LDP packet length %d", 184 ntohs(ldp_hdr.length)); 185 return; 186 } 187 188 if (len < LDP_HDR_SIZE + LDP_MSG_LEN) { 189 log_debug("disc_recv_packet: invalid LDP packet length %d", 190 ntohs(ldp_hdr.length)); 191 return; 192 } 193 194 bcopy(buf + LDP_HDR_SIZE, &ldp_msg, sizeof(ldp_msg)); 195 196 197 /* switch LDP packet type */ 198 switch (ntohs(ldp_msg.type)) { 199 case MSG_TYPE_HELLO: 200 recv_hello(iface, src.sin_addr, buf, len); 201 break; 202 default: 203 log_debug("recv_packet: unknown LDP packet type, interface %s", 204 iface->name); 205 } 206 } 207 208 int 209 ldp_hdr_sanity_check(struct ldp_hdr *ldp_hdr, u_int16_t len, 210 const struct iface *iface) 211 { 212 struct in_addr addr; 213 214 if (ldp_hdr->lspace_id != iface->lspace_id) { 215 addr.s_addr = ldp_hdr->lspace_id; 216 log_debug("ldp_hdr_sanity_check: invalid label space " 217 "ID %s, interface %s", inet_ntoa(addr), 218 iface->name); 219 return (-1); 220 } 221 222 return (ntohs(ldp_hdr->length)); 223 } 224 225 struct iface * 226 find_iface(struct ldpd_conf *xconf, unsigned int ifindex, struct in_addr src) 227 { 228 struct iface *iface = NULL; 229 230 /* returned interface needs to be active */ 231 LIST_FOREACH(iface, &xconf->iface_list, entry) { 232 switch (iface->type) { 233 case IF_TYPE_POINTOPOINT: 234 if (ifindex == iface->ifindex && 235 iface->dst.s_addr == src.s_addr && 236 !iface->passive) 237 return (iface); 238 break; 239 default: 240 if (ifindex == iface->ifindex && 241 (iface->addr.s_addr & iface->mask.s_addr) == 242 (src.s_addr & iface->mask.s_addr) && 243 !iface->passive) 244 return (iface); 245 break; 246 } 247 } 248 249 return (NULL); 250 } 251 252 void 253 session_accept(int fd, short event, void *bula) 254 { 255 struct sockaddr_in src; 256 struct nbr *nbr = NULL; 257 int newfd; 258 socklen_t len = sizeof(src); 259 260 if (!(event & EV_READ)) 261 return; 262 263 newfd = accept(fd, (struct sockaddr *)&src, &len); 264 if (newfd == -1) { 265 /* 266 * Pause accept if we are out of file descriptors, or 267 * libevent will haunt us here too. 268 */ 269 if (errno == ENFILE || errno == EMFILE) { 270 accept_pause(); 271 } else if (errno != EWOULDBLOCK && errno != EINTR) 272 log_debug("sess_recv_packet: accept error: %s", 273 strerror(errno)); 274 return; 275 } 276 277 session_socket_blockmode(newfd, BM_NONBLOCK); 278 279 nbr = nbr_find_ip(src.sin_addr.s_addr); 280 if (nbr == NULL) { 281 struct ibuf *buf; 282 /* If there is no neighbor matching there is no 283 Hello adjacency: try to send notification */ 284 log_warnx("Connection attempt from unknown neighbor %s: %s", 285 inet_ntoa(src.sin_addr), "NO HELLO"); 286 buf = send_notification(S_NO_HELLO, NULL, 0, 0); 287 write(newfd, buf->buf, buf->wpos); 288 ibuf_free(buf); 289 close(newfd); 290 return; 291 } 292 293 nbr->fd = newfd; 294 nbr_fsm(nbr, NBR_EVT_SESSION_UP); 295 } 296 297 void 298 session_read(int fd, short event, void *arg) 299 { 300 struct nbr *nbr = arg; 301 struct iface *iface = nbr->iface; 302 struct ldp_hdr *ldp_hdr; 303 struct ldp_msg *ldp_msg; 304 char *buf, *pdu; 305 ssize_t n, len; 306 int l, msg_size; 307 u_int16_t pdu_len; 308 309 if (event != EV_READ) { 310 log_debug("session_read: spurious event"); 311 return; 312 } 313 314 if ((n = read(fd, nbr->rbuf->buf + nbr->rbuf->wpos, 315 sizeof(nbr->rbuf->buf) - nbr->rbuf->wpos)) == -1) { 316 if (errno != EINTR && errno != EAGAIN) { 317 session_shutdown(nbr, S_SHUTDOWN, 0, 0); 318 return; 319 } 320 /* retry read */ 321 return; 322 } 323 if (n == 0) { 324 /* connection closed */ 325 session_shutdown(nbr, S_SHUTDOWN, 0, 0); 326 return; 327 } 328 nbr->rbuf->wpos += n; 329 330 while ((len = session_get_pdu(nbr->rbuf, &buf)) > 0) { 331 pdu = buf; 332 ldp_hdr = (struct ldp_hdr *)pdu; 333 if (ntohs(ldp_hdr->version) != LDP_VERSION) { 334 session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0); 335 free(buf); 336 return; 337 } 338 339 pdu_len = ntohs(ldp_hdr->length); 340 if (pdu_len < LDP_HDR_SIZE || pdu_len > LDP_MAX_LEN) { 341 session_shutdown(nbr, S_BAD_MSG_LEN, 0, 0); 342 free(buf); 343 return; 344 } 345 346 if ((l = ldp_hdr_sanity_check(ldp_hdr, len, iface)) == -1) { 347 session_shutdown(nbr, S_BAD_LDP_ID, 0, 0); 348 free(buf); 349 return; 350 } 351 352 pdu += LDP_HDR_SIZE; 353 len -= LDP_HDR_SIZE; 354 355 while (len >= LDP_MSG_LEN) { 356 ldp_msg = (struct ldp_msg *)pdu; 357 358 pdu_len = ntohs(ldp_msg->length) + TLV_HDR_LEN; 359 if (pdu_len > len || 360 pdu_len < LDP_MSG_LEN - TLV_HDR_LEN) { 361 session_shutdown(nbr, S_BAD_TLV_LEN, 0, 0); 362 free(buf); 363 return; 364 } 365 366 /* switch LDP packet type */ 367 switch (ntohs(ldp_msg->type)) { 368 case MSG_TYPE_NOTIFICATION: 369 msg_size = recv_notification(nbr, pdu, pdu_len); 370 break; 371 case MSG_TYPE_INIT: 372 msg_size = recv_init(nbr, pdu, pdu_len); 373 break; 374 case MSG_TYPE_KEEPALIVE: 375 msg_size = recv_keepalive(nbr, pdu, pdu_len); 376 break; 377 case MSG_TYPE_ADDR: 378 case MSG_TYPE_ADDRWITHDRAW: 379 msg_size = recv_address(nbr, pdu, pdu_len); 380 break; 381 case MSG_TYPE_LABELMAPPING: 382 msg_size = recv_labelmapping(nbr, pdu, pdu_len); 383 break; 384 case MSG_TYPE_LABELREQUEST: 385 msg_size = recv_labelrequest(nbr, pdu, pdu_len); 386 break; 387 case MSG_TYPE_LABELWITHDRAW: 388 msg_size = recv_labelwithdraw(nbr, pdu, pdu_len); 389 break; 390 case MSG_TYPE_LABELRELEASE: 391 msg_size = recv_labelrelease(nbr, pdu, pdu_len); 392 break; 393 case MSG_TYPE_LABELABORTREQ: 394 case MSG_TYPE_HELLO: 395 default: 396 log_debug("session_read: unknown LDP packet " 397 "type interface %s", iface->name); 398 free(buf); 399 return; 400 } 401 402 if (msg_size == -1) { 403 /* parser failed, giving up */ 404 free(buf); 405 return; 406 } 407 408 /* Analyse the next message */ 409 pdu += msg_size + TLV_HDR_LEN; 410 len -= msg_size + TLV_HDR_LEN; 411 } 412 free(buf); 413 if (len != 0) { 414 session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); 415 return; 416 } 417 } 418 } 419 420 void 421 session_write(int fd, short event, void *arg) 422 { 423 struct nbr *nbr = arg; 424 425 if (event & EV_WRITE) { 426 if (msgbuf_write(&nbr->wbuf.wbuf) == -1) 427 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 428 } else 429 log_debug("session_write: spurious event"); 430 431 evbuf_event_add(&nbr->wbuf); 432 } 433 434 void 435 session_shutdown(struct nbr *nbr, u_int32_t status, u_int32_t msgid, 436 u_int32_t type) 437 { 438 log_debug("session_shutdown: nbr ID %s, status %x", 439 inet_ntoa(nbr->id), status); 440 441 send_notification_nbr(nbr, status, msgid, type); 442 443 /* try to flush write buffer, if it fails tough shit */ 444 msgbuf_write(&nbr->wbuf.wbuf); 445 446 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 447 } 448 449 void 450 session_close(struct nbr *nbr) 451 { 452 log_debug("session_close: closing session with nbr ID %s", 453 inet_ntoa(nbr->id)); 454 455 evbuf_clear(&nbr->wbuf); 456 event_del(&nbr->rev); 457 458 if (evtimer_pending(&nbr->keepalive_timer, NULL)) 459 evtimer_del(&nbr->keepalive_timer); 460 if (evtimer_pending(&nbr->keepalive_timeout, NULL)) 461 evtimer_del(&nbr->keepalive_timeout); 462 463 close(nbr->fd); 464 accept_unpause(); 465 } 466 467 ssize_t 468 session_get_pdu(struct ibuf_read *r, char **b) 469 { 470 struct ldp_hdr l; 471 size_t av, dlen, left; 472 473 av = r->wpos; 474 if (av < sizeof(l)) 475 return (0); 476 477 memcpy(&l, r->buf, sizeof(l)); 478 dlen = ntohs(l.length) + TLV_HDR_LEN; 479 if (dlen > av) 480 return (0); 481 482 if ((*b = malloc(dlen)) == NULL) 483 return (-1); 484 485 memcpy(*b, r->buf, dlen); 486 if (dlen < av) { 487 left = av - dlen; 488 memmove(r->buf, r->buf + dlen, left); 489 r->wpos = left; 490 } else 491 r->wpos = 0; 492 493 return (dlen); 494 } 495