1 /* $OpenBSD: packet.c,v 1.3 2009/11/01 11:09:58 michele 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 struct iface *session_find_iface(struct ldpd_conf *, struct in_addr); 46 47 static int msgcnt = 0; 48 49 int 50 gen_ldp_hdr(struct buf *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 ldp_hdr.lspace_id = iface->lspace_id; 63 64 return (buf_add(buf, &ldp_hdr, LDP_HDR_SIZE)); 65 } 66 67 int 68 gen_msg_tlv(struct buf *buf, u_int32_t type, u_int16_t size) 69 { 70 struct ldp_msg msg; 71 72 /* We want just the size of the value */ 73 size -= TLV_HDR_LEN; 74 75 bzero(&msg, sizeof(msg)); 76 msg.type = htons(type); 77 msg.length = htons(size); 78 msg.msgid = htonl(++msgcnt); 79 80 return (buf_add(buf, &msg, sizeof(msg))); 81 } 82 83 /* send and receive packets */ 84 int 85 send_packet(struct iface *iface, void *pkt, size_t len, struct sockaddr_in *dst) 86 { 87 /* set outgoing interface for multicast traffic */ 88 if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr))) 89 if (if_set_mcast(iface) == -1) { 90 log_warn("send_packet: error setting multicast " 91 "interface, %s", iface->name); 92 return (-1); 93 } 94 95 if (sendto(iface->discovery_fd, pkt, len, 0, 96 (struct sockaddr *)dst, sizeof(*dst)) == -1) { 97 log_warn("send_packet: error sending packet on interface %s", 98 iface->name); 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 ldpd_conf *xconf = bula; 117 struct ldp_hdr *ldp_hdr; 118 struct ldp_msg *ldp_msg; 119 struct iface *iface; 120 char *buf; 121 struct cmsghdr *cmsg; 122 ssize_t r; 123 u_int16_t len; 124 int l; 125 unsigned int ifindex = 0; 126 127 if (event != EV_READ) 128 return; 129 130 /* setup buffer */ 131 bzero(&msg, sizeof(msg)); 132 iov.iov_base = buf = pkt_ptr; 133 iov.iov_len = READ_BUF_SIZE; 134 msg.msg_name = &src; 135 msg.msg_namelen = sizeof(src); 136 msg.msg_iov = &iov; 137 msg.msg_iovlen = 1; 138 msg.msg_control = &cmsgbuf.buf; 139 msg.msg_controllen = sizeof(cmsgbuf.buf); 140 141 if ((r = recvmsg(fd, &msg, 0)) == -1) { 142 if (errno != EAGAIN && errno != EINTR) 143 log_debug("disc_recv_packet: read error: %s", 144 strerror(errno)); 145 return; 146 } 147 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 148 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 149 if (cmsg->cmsg_level == IPPROTO_IP && 150 cmsg->cmsg_type == IP_RECVIF) { 151 ifindex = ((struct sockaddr_dl *) 152 CMSG_DATA(cmsg))->sdl_index; 153 break; 154 } 155 } 156 157 len = (u_int16_t)r; 158 159 /* find a matching interface */ 160 if ((iface = find_iface(xconf, ifindex, src.sin_addr)) == NULL) { 161 log_debug("disc_recv_packet: cannot find a matching interface"); 162 return; 163 } 164 165 /* LDP header sanity checks */ 166 if (len < LDP_HDR_SIZE || len > LDP_MAX_LEN) { 167 log_debug("disc_recv_packet: bad packet size"); 168 return; 169 } 170 ldp_hdr = (struct ldp_hdr *)buf; 171 172 if (ntohs(ldp_hdr->version) != LDP_VERSION) { 173 log_debug("dsc_recv_packet: invalid LDP version %d", 174 ldp_hdr->version); 175 return; 176 } 177 178 if (ntohs(ldp_hdr->length) > len || 179 len <= sizeof(struct ldp_hdr)) { 180 log_debug("disc_recv_packet: invalid LDP packet length %d", 181 ntohs(ldp_hdr->length)); 182 return; 183 } 184 185 if ((l = ldp_hdr_sanity_check(ldp_hdr, len, iface)) == -1) 186 return; 187 188 ldp_msg = (struct ldp_msg *)(buf + LDP_HDR_SIZE); 189 190 if (len < LDP_MSG_LEN) { 191 log_debug("disc_recv_packet: invalid LDP packet length %d", 192 ntohs(ldp_hdr->length)); 193 return; 194 } 195 196 /* switch LDP packet type */ 197 switch (ntohs(ldp_msg->type)) { 198 case MSG_TYPE_HELLO: 199 recv_hello(iface, src.sin_addr, buf, len); 200 break; 201 default: 202 log_debug("recv_packet: unknown LDP packet type, interface %s", 203 iface->name); 204 } 205 } 206 207 int 208 ldp_hdr_sanity_check(struct ldp_hdr *ldp_hdr, u_int16_t len, 209 const struct iface *iface) 210 { 211 struct in_addr addr; 212 213 if (iface->type != IF_TYPE_VIRTUALLINK) { 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 } else { 222 if (ldp_hdr->lspace_id != 0) { 223 addr.s_addr = ldp_hdr->lspace_id; 224 log_debug("ldp_hdr_sanity_check: invalid label space " 225 "ID %s, interface %s", inet_ntoa(addr), 226 iface->name); 227 return (-1); 228 } 229 } 230 231 return (ntohs(ldp_hdr->length)); 232 } 233 234 struct iface * 235 find_iface(struct ldpd_conf *xconf, unsigned int ifindex, struct in_addr src) 236 { 237 struct iface *iface = NULL; 238 239 /* returned interface needs to be active */ 240 LIST_FOREACH(iface, &xconf->iface_list, entry) { 241 switch (iface->type) { 242 case IF_TYPE_VIRTUALLINK: 243 if ((src.s_addr == iface->dst.s_addr) && 244 !iface->passive) 245 return (iface); 246 break; 247 case IF_TYPE_POINTOPOINT: 248 if (ifindex == iface->ifindex && 249 iface->dst.s_addr == src.s_addr && 250 !iface->passive) 251 return (iface); 252 break; 253 default: 254 if (ifindex == iface->ifindex && 255 (iface->addr.s_addr & iface->mask.s_addr) == 256 (src.s_addr & iface->mask.s_addr) && 257 !iface->passive) 258 return (iface); 259 break; 260 } 261 } 262 263 return (NULL); 264 } 265 266 void 267 session_recv_packet(int fd, short event, void *bula) 268 { 269 struct sockaddr_in src; 270 struct ldpd_conf *xconf = bula; 271 struct iface *iface; 272 struct nbr *nbr = NULL; 273 int newfd; 274 socklen_t len = sizeof(src); 275 276 if (event != EV_READ) 277 return; 278 279 newfd = accept(fd, (struct sockaddr *)&src, &len); 280 if (newfd == -1) { 281 log_debug("sess_recv_packet: accept error: %s", 282 strerror(errno)); 283 return; 284 } 285 286 if (fcntl(newfd, F_SETFL, O_NONBLOCK) == -1) { 287 log_debug("sess_recv_packet: unable to set non blocking flag"); 288 return; 289 } 290 291 if ((iface = session_find_iface(xconf, src.sin_addr)) == NULL) { 292 log_debug("sess_recv_packet: cannot find a matching interface"); 293 return; 294 } 295 296 /* XXX */ 297 nbr = nbr_find_ip(iface, src.sin_addr.s_addr); 298 if (nbr == NULL) { 299 /* If there is no neighbor matching there is no 300 Hello adjacency: send notification */ 301 send_notification(S_NO_HELLO, iface, newfd, 0, 0); 302 close(newfd); 303 return; 304 } 305 306 nbr->fd = newfd; 307 nbr_fsm(nbr, NBR_EVT_SESSION_UP); 308 } 309 310 void 311 session_read(struct bufferevent *bev, void *arg) 312 { 313 struct nbr *nbr = (struct nbr *)arg; 314 struct iface *iface = nbr->iface; 315 struct ldp_hdr *ldp_hdr; 316 struct ldp_msg *ldp_msg; 317 u_int16_t len = EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)); 318 u_int16_t pdu_len; 319 char buffer[LDP_MAX_LEN]; 320 char *buf = buffer; 321 int l, msg_size = 0; 322 323 bufferevent_read(bev, buf, len); 324 325 another_packet: 326 ldp_hdr = (struct ldp_hdr *)buf; 327 328 if (ntohs(ldp_hdr->version) != LDP_VERSION) { 329 session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0); 330 return; 331 } 332 333 pdu_len = ntohs(ldp_hdr->length); 334 335 if (pdu_len < LDP_HDR_SIZE || pdu_len > LDP_MAX_LEN) { 336 session_shutdown(nbr, S_BAD_MSG_LEN, 0, 0); 337 return; 338 } 339 340 if ((l = ldp_hdr_sanity_check(ldp_hdr, len, iface)) == -1) 341 return; 342 343 buf += LDP_HDR_SIZE; 344 len -= LDP_HDR_SIZE; 345 346 pdu_len -= LDP_HDR_SIZE - PDU_HDR_SIZE; 347 348 while (pdu_len > LDP_MSG_LEN) { 349 ldp_msg = (struct ldp_msg *)buf; 350 351 /* switch LDP packet type */ 352 switch (ntohs(ldp_msg->type)) { 353 case MSG_TYPE_NOTIFICATION: 354 msg_size = recv_notification(nbr, buf, pdu_len); 355 break; 356 case MSG_TYPE_INIT: 357 msg_size = recv_init(nbr, buf, pdu_len); 358 break; 359 case MSG_TYPE_KEEPALIVE: 360 msg_size = recv_keepalive(nbr, buf, pdu_len); 361 break; 362 case MSG_TYPE_ADDR: 363 msg_size = recv_address(nbr, buf, pdu_len); 364 break; 365 case MSG_TYPE_ADDRWITHDRAW: 366 msg_size = recv_address_withdraw(nbr, buf, pdu_len); 367 break; 368 case MSG_TYPE_LABELMAPPING: 369 msg_size = recv_labelmapping(nbr, buf, pdu_len); 370 break; 371 case MSG_TYPE_LABELREQUEST: 372 msg_size = recv_labelrequest(nbr, buf, pdu_len); 373 break; 374 case MSG_TYPE_LABELWITHDRAW: 375 msg_size = recv_labelwithdraw(nbr, buf, pdu_len); 376 break; 377 case MSG_TYPE_LABELRELEASE: 378 msg_size = recv_labelrelease(nbr, buf, pdu_len); 379 break; 380 case MSG_TYPE_LABELABORTREQ: 381 case MSG_TYPE_HELLO: 382 default: 383 log_debug("session_read: unknown LDP packet type " 384 "interface %s", iface->name); 385 return; 386 } 387 388 if (msg_size < 0) 389 return; 390 391 /* Analyse the next message */ 392 buf += msg_size + TLV_HDR_LEN; 393 len -= msg_size + TLV_HDR_LEN; 394 pdu_len -= msg_size + TLV_HDR_LEN; 395 } 396 397 if (len > LDP_HDR_SIZE) 398 goto another_packet; 399 } 400 401 void 402 session_error(struct bufferevent *bev, short what, void *arg) 403 { 404 struct nbr *nbr = arg; 405 406 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 407 } 408 409 void 410 session_shutdown(struct nbr *nbr, u_int32_t status, u_int32_t msgid, 411 u_int32_t type) 412 { 413 send_notification_nbr(nbr, status, msgid, type); 414 send_notification_nbr(nbr, S_SHUTDOWN, msgid, type); 415 416 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 417 } 418 419 void 420 session_close(struct nbr *nbr) 421 { 422 log_debug("session_close: closing session with nbr ID %s", 423 inet_ntoa(nbr->id)); 424 425 if (evtimer_pending(&nbr->keepalive_timer, NULL)) 426 evtimer_del(&nbr->keepalive_timer); 427 if (evtimer_pending(&nbr->keepalive_timeout, NULL)) 428 evtimer_del(&nbr->keepalive_timeout); 429 430 bufferevent_free(nbr->bev); 431 close(nbr->fd); 432 } 433 434 struct iface * 435 session_find_iface(struct ldpd_conf *xconf, struct in_addr src) 436 { 437 struct iface *iface = NULL; 438 439 /* returned interface needs to be active */ 440 LIST_FOREACH(iface, &xconf->iface_list, entry) { 441 switch (iface->type) { 442 case IF_TYPE_VIRTUALLINK: 443 if ((src.s_addr == iface->dst.s_addr) && 444 !iface->passive) 445 return (iface); 446 break; 447 case IF_TYPE_POINTOPOINT: 448 if (iface->dst.s_addr == src.s_addr && 449 !iface->passive) 450 return (iface); 451 break; 452 default: 453 if ((iface->addr.s_addr & iface->mask.s_addr) == 454 (src.s_addr & iface->mask.s_addr) && 455 !iface->passive) 456 return (iface); 457 break; 458 } 459 } 460 461 return (NULL); 462 } 463