1*3bba10cfSclaudio /* $OpenBSD: packet.c,v 1.77 2024/11/21 13:29:28 claudio Exp $ */ 2ab0c2486Smichele 3ab0c2486Smichele /* 45dc9330aSrenato * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> 5ab0c2486Smichele * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 6ab0c2486Smichele * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 7ab0c2486Smichele * 8ab0c2486Smichele * Permission to use, copy, modify, and distribute this software for any 9ab0c2486Smichele * purpose with or without fee is hereby granted, provided that the above 10ab0c2486Smichele * copyright notice and this permission notice appear in all copies. 11ab0c2486Smichele * 12ab0c2486Smichele * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13ab0c2486Smichele * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14ab0c2486Smichele * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15ab0c2486Smichele * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16ab0c2486Smichele * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17ab0c2486Smichele * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18ab0c2486Smichele * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19ab0c2486Smichele */ 20ab0c2486Smichele 21ab0c2486Smichele #include <sys/types.h> 22ab0c2486Smichele #include <netinet/in.h> 23627846caSrenato #include <netinet/tcp.h> 24ab0c2486Smichele #include <arpa/inet.h> 25ab0c2486Smichele #include <net/if_dl.h> 26ab0c2486Smichele #include <unistd.h> 27ab0c2486Smichele #include <errno.h> 28ab0c2486Smichele #include <stdlib.h> 29ab0c2486Smichele #include <string.h> 30ab0c2486Smichele 31ab0c2486Smichele #include "ldpd.h" 32ab0c2486Smichele #include "ldpe.h" 335411bbb6Srenato #include "log.h" 34ab0c2486Smichele 35c28a25a1Srenato static struct iface *disc_find_iface(unsigned int, int, 36c28a25a1Srenato union ldpd_addr *, int); 37c28a25a1Srenato static void session_read(int, short, void *); 38c28a25a1Srenato static void session_write(int, short, void *); 3926889e1dSclaudio static ssize_t session_get_pdu(struct buf_read *, char **); 40c28a25a1Srenato static void tcp_close(struct tcp_conn *); 41c28a25a1Srenato static struct pending_conn *pending_conn_new(int, int, union ldpd_addr *); 42c28a25a1Srenato static void pending_conn_timeout(int, short, void *); 43ab0c2486Smichele 444ff910d1Sclaudio static u_int8_t *recv_buf; 454ff910d1Sclaudio 46ab0c2486Smichele int 473de94509Srenato gen_ldp_hdr(struct ibuf *buf, uint16_t size) 48ab0c2486Smichele { 49ab0c2486Smichele struct ldp_hdr ldp_hdr; 50ab0c2486Smichele 513de94509Srenato memset(&ldp_hdr, 0, sizeof(ldp_hdr)); 52ab0c2486Smichele ldp_hdr.version = htons(LDP_VERSION); 539277622bSrenato /* exclude the 'Version' and 'PDU Length' fields from the total */ 549277622bSrenato ldp_hdr.length = htons(size - LDP_HDR_DEAD_LEN); 5586408800Srenato ldp_hdr.lsr_id = leconf->rtr_id.s_addr; 56122f143eSclaudio ldp_hdr.lspace_id = 0; 57ab0c2486Smichele 58e39620e5Snicm return (ibuf_add(buf, &ldp_hdr, LDP_HDR_SIZE)); 59ab0c2486Smichele } 60ab0c2486Smichele 61ab0c2486Smichele int 62c31aa80eSrenato gen_msg_hdr(struct ibuf *buf, uint16_t type, uint16_t size) 63ab0c2486Smichele { 64c28a25a1Srenato static int msgcnt = 0; 65ab0c2486Smichele struct ldp_msg msg; 66ab0c2486Smichele 673de94509Srenato memset(&msg, 0, sizeof(msg)); 68ab0c2486Smichele msg.type = htons(type); 693de94509Srenato /* exclude the 'Type' and 'Length' fields from the total */ 703de94509Srenato msg.length = htons(size - LDP_MSG_DEAD_LEN); 7160e1e0e7Srenato msg.id = htonl(++msgcnt); 72ab0c2486Smichele 73e39620e5Snicm return (ibuf_add(buf, &msg, sizeof(msg))); 74ab0c2486Smichele } 75ab0c2486Smichele 7683dcf737Sclaudio /* send packets */ 77ab0c2486Smichele int 78a8c39dc0Srenato send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia, 79a8c39dc0Srenato void *pkt, size_t len) 80ab0c2486Smichele { 81a8c39dc0Srenato struct sockaddr *sa; 82a8c39dc0Srenato 83a8c39dc0Srenato switch (af) { 84a8c39dc0Srenato case AF_INET: 85a8c39dc0Srenato if (ia && IN_MULTICAST(ntohl(dst->v4.s_addr))) { 86ab0c2486Smichele /* set outgoing interface for multicast traffic */ 87a8c39dc0Srenato if (sock_set_ipv4_mcast(ia->iface) == -1) { 88a8c39dc0Srenato log_debug("%s: error setting multicast " 89a8c39dc0Srenato "interface, %s", __func__, ia->iface->name); 90ab0c2486Smichele return (-1); 91ab0c2486Smichele } 92a8c39dc0Srenato } 93a8c39dc0Srenato break; 94a8c39dc0Srenato case AF_INET6: 95a8c39dc0Srenato if (ia && IN6_IS_ADDR_MULTICAST(&dst->v6)) { 96a8c39dc0Srenato /* set outgoing interface for multicast traffic */ 97a8c39dc0Srenato if (sock_set_ipv6_mcast(ia->iface) == -1) { 98a8c39dc0Srenato log_debug("%s: error setting multicast " 99a8c39dc0Srenato "interface, %s", __func__, ia->iface->name); 100a8c39dc0Srenato return (-1); 101a8c39dc0Srenato } 102a8c39dc0Srenato } 103a8c39dc0Srenato break; 104a8c39dc0Srenato default: 105a8c39dc0Srenato fatalx("send_packet: unknown af"); 106a8c39dc0Srenato } 107ab0c2486Smichele 108a8c39dc0Srenato sa = addr2sa(af, dst, LDP_PORT); 109a8c39dc0Srenato if (sendto(fd, pkt, len, 0, sa, sa->sa_len) == -1) { 110b7b4db73Srenato log_warn("%s: error sending packet to %s", __func__, 111a8c39dc0Srenato log_sockaddr(sa)); 112ab0c2486Smichele return (-1); 113ab0c2486Smichele } 114ab0c2486Smichele 115ab0c2486Smichele return (0); 116ab0c2486Smichele } 117ab0c2486Smichele 118ab0c2486Smichele /* Discovery functions */ 119a8c39dc0Srenato #define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo)) 120ab0c2486Smichele void 121ab0c2486Smichele disc_recv_packet(int fd, short event, void *bula) 122ab0c2486Smichele { 123ab0c2486Smichele union { 124ab0c2486Smichele struct cmsghdr hdr; 125a8c39dc0Srenato char buf[CMSG_SPACE(CMSG_MAXLEN)]; 126ab0c2486Smichele } cmsgbuf; 12760e1e0e7Srenato struct msghdr m; 128a8c39dc0Srenato struct sockaddr_storage from; 129ab0c2486Smichele struct iovec iov; 130ab0c2486Smichele char *buf; 131ab0c2486Smichele struct cmsghdr *cmsg; 132ab0c2486Smichele ssize_t r; 1333de94509Srenato int multicast; 134a8c39dc0Srenato int af; 135a8c39dc0Srenato union ldpd_addr src; 136ab0c2486Smichele unsigned int ifindex = 0; 1373de94509Srenato struct iface *iface; 1383de94509Srenato uint16_t len; 1393de94509Srenato struct ldp_hdr ldp_hdr; 1403de94509Srenato uint16_t pdu_len; 14160e1e0e7Srenato struct ldp_msg msg; 1423de94509Srenato uint16_t msg_len; 1433de94509Srenato struct in_addr lsr_id; 144ab0c2486Smichele 145ab0c2486Smichele if (event != EV_READ) 146ab0c2486Smichele return; 147ab0c2486Smichele 1484ff910d1Sclaudio if (recv_buf == NULL) 1494ff910d1Sclaudio if ((recv_buf = malloc(READ_BUF_SIZE)) == NULL) 1504ff910d1Sclaudio fatal(__func__); 1514ff910d1Sclaudio 152ab0c2486Smichele /* setup buffer */ 15360e1e0e7Srenato memset(&m, 0, sizeof(m)); 1544ff910d1Sclaudio iov.iov_base = buf = recv_buf; 1554ff910d1Sclaudio iov.iov_len = READ_BUF_SIZE; 15660e1e0e7Srenato m.msg_name = &from; 15760e1e0e7Srenato m.msg_namelen = sizeof(from); 15860e1e0e7Srenato m.msg_iov = &iov; 15960e1e0e7Srenato m.msg_iovlen = 1; 16060e1e0e7Srenato m.msg_control = &cmsgbuf.buf; 16160e1e0e7Srenato m.msg_controllen = sizeof(cmsgbuf.buf); 162ab0c2486Smichele 16360e1e0e7Srenato if ((r = recvmsg(fd, &m, 0)) == -1) { 164ab0c2486Smichele if (errno != EAGAIN && errno != EINTR) 165b7b4db73Srenato log_debug("%s: read error: %s", __func__, 166ab0c2486Smichele strerror(errno)); 167ab0c2486Smichele return; 168ab0c2486Smichele } 169ac5a809bSrenato 17060e1e0e7Srenato multicast = (m.msg_flags & MSG_MCAST) ? 1 : 0; 171a8c39dc0Srenato sa2addr((struct sockaddr *)&from, &af, &src); 172a8c39dc0Srenato if (bad_addr(af, &src)) { 173ac5a809bSrenato log_debug("%s: invalid source address: %s", __func__, 174a8c39dc0Srenato log_addr(af, &src)); 175ac5a809bSrenato return; 176ac5a809bSrenato } 177ac5a809bSrenato 17860e1e0e7Srenato for (cmsg = CMSG_FIRSTHDR(&m); cmsg != NULL; 17960e1e0e7Srenato cmsg = CMSG_NXTHDR(&m, cmsg)) { 180a8c39dc0Srenato if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP && 181ab0c2486Smichele cmsg->cmsg_type == IP_RECVIF) { 182ab0c2486Smichele ifindex = ((struct sockaddr_dl *) 183ab0c2486Smichele CMSG_DATA(cmsg))->sdl_index; 184ab0c2486Smichele break; 185ab0c2486Smichele } 186a8c39dc0Srenato if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 && 187a8c39dc0Srenato cmsg->cmsg_type == IPV6_PKTINFO) { 188a8c39dc0Srenato ifindex = ((struct in6_pktinfo *) 189a8c39dc0Srenato CMSG_DATA(cmsg))->ipi6_ifindex; 190a8c39dc0Srenato break; 191a8c39dc0Srenato } 192ab0c2486Smichele } 193ab0c2486Smichele 194ab0c2486Smichele /* find a matching interface */ 195a8c39dc0Srenato iface = disc_find_iface(ifindex, af, &src, multicast); 1963de94509Srenato if (iface == NULL) 1973de94509Srenato return; 1983de94509Srenato 1993de94509Srenato /* check packet size */ 2003de94509Srenato len = (uint16_t)r; 2013de94509Srenato if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) { 2023de94509Srenato log_debug("%s: bad packet size, source %s", __func__, 203a8c39dc0Srenato log_addr(af, &src)); 204ab0c2486Smichele return; 205ab0c2486Smichele } 206ab0c2486Smichele 207ab0c2486Smichele /* LDP header sanity checks */ 2083de94509Srenato memcpy(&ldp_hdr, buf, sizeof(ldp_hdr)); 20989f23408Sclaudio if (ntohs(ldp_hdr.version) != LDP_VERSION) { 2103de94509Srenato log_debug("%s: invalid LDP version %d, source %s", __func__, 211a8c39dc0Srenato ntohs(ldp_hdr.version), log_addr(af, &src)); 212ab0c2486Smichele return; 213ab0c2486Smichele } 2143de94509Srenato if (ntohs(ldp_hdr.lspace_id) != 0) { 2153de94509Srenato log_debug("%s: invalid label space %u, source %s", __func__, 216a8c39dc0Srenato ntohs(ldp_hdr.lspace_id), log_addr(af, &src)); 217ab0c2486Smichele return; 218ab0c2486Smichele } 2193de94509Srenato /* check "PDU Length" field */ 2203de94509Srenato pdu_len = ntohs(ldp_hdr.length); 2213de94509Srenato if ((pdu_len < (LDP_HDR_PDU_LEN + LDP_MSG_SIZE)) || 2223de94509Srenato (pdu_len > (len - LDP_HDR_DEAD_LEN))) { 2233de94509Srenato log_debug("%s: invalid LDP packet length %u, source %s", 224a8c39dc0Srenato __func__, ntohs(ldp_hdr.length), log_addr(af, &src)); 225ab0c2486Smichele return; 226ab0c2486Smichele } 2273de94509Srenato buf += LDP_HDR_SIZE; 2283de94509Srenato len -= LDP_HDR_SIZE; 229ab0c2486Smichele 2303de94509Srenato lsr_id.s_addr = ldp_hdr.lsr_id; 2313de94509Srenato 2323de94509Srenato /* 2333de94509Srenato * For UDP, we process only the first message of each packet. This does 2343de94509Srenato * not impose any restrictions since LDP uses UDP only for sending Hello 2353de94509Srenato * packets. 2363de94509Srenato */ 23760e1e0e7Srenato memcpy(&msg, buf, sizeof(msg)); 2383de94509Srenato 2393de94509Srenato /* check "Message Length" field */ 24060e1e0e7Srenato msg_len = ntohs(msg.length); 2413de94509Srenato if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) { 2423de94509Srenato log_debug("%s: invalid LDP message length %u, source %s", 24360e1e0e7Srenato __func__, ntohs(msg.length), log_addr(af, &src)); 2443de94509Srenato return; 2453de94509Srenato } 2463de94509Srenato buf += LDP_MSG_SIZE; 2473de94509Srenato len -= LDP_MSG_SIZE; 24889f23408Sclaudio 249ab0c2486Smichele /* switch LDP packet type */ 25060e1e0e7Srenato switch (ntohs(msg.type)) { 251ab0c2486Smichele case MSG_TYPE_HELLO: 25260e1e0e7Srenato recv_hello(lsr_id, &msg, af, &src, iface, multicast, buf, len); 253ab0c2486Smichele break; 254ab0c2486Smichele default: 255b7b4db73Srenato log_debug("%s: unknown LDP packet type, source %s", __func__, 256a8c39dc0Srenato log_addr(af, &src)); 257ab0c2486Smichele } 258ab0c2486Smichele } 259ab0c2486Smichele 260c28a25a1Srenato static struct iface * 261a8c39dc0Srenato disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src, 262ac5a809bSrenato int multicast) 263ab0c2486Smichele { 264814e607dSclaudio struct iface *iface; 265a8c39dc0Srenato struct iface_af *ia; 266814e607dSclaudio struct if_addr *if_addr; 267a8c39dc0Srenato in_addr_t mask; 268ab0c2486Smichele 269ac5a809bSrenato iface = if_lookup(leconf, ifindex); 270ac5a809bSrenato if (iface == NULL) 271ac5a809bSrenato return (NULL); 272ac5a809bSrenato 273a8c39dc0Srenato /* 274a8c39dc0Srenato * For unicast packets, we just need to make sure that the interface 275a8c39dc0Srenato * is enabled for the given address-family. 276a8c39dc0Srenato */ 277a8c39dc0Srenato if (!multicast) { 278a8c39dc0Srenato ia = iface_af_get(iface, af); 279a8c39dc0Srenato if (ia->enabled) 280ac5a809bSrenato return (iface); 281a8c39dc0Srenato return (NULL); 282a8c39dc0Srenato } 283ac5a809bSrenato 284a8c39dc0Srenato switch (af) { 285a8c39dc0Srenato case AF_INET: 286ac5a809bSrenato LIST_FOREACH(if_addr, &iface->addr_list, entry) { 287a8c39dc0Srenato if (if_addr->af != AF_INET) 288a8c39dc0Srenato continue; 289a8c39dc0Srenato 290ab0c2486Smichele switch (iface->type) { 291ab0c2486Smichele case IF_TYPE_POINTOPOINT: 292a8c39dc0Srenato if (if_addr->dstbrd.v4.s_addr == src->v4.s_addr) 293ab0c2486Smichele return (iface); 294ab0c2486Smichele break; 295ab0c2486Smichele default: 296a8c39dc0Srenato mask = prefixlen2mask(if_addr->prefixlen); 297a8c39dc0Srenato if ((if_addr->addr.v4.s_addr & mask) == 298a8c39dc0Srenato (src->v4.s_addr & mask)) 299ab0c2486Smichele return (iface); 300ab0c2486Smichele break; 301ab0c2486Smichele } 302ac5a809bSrenato } 303a8c39dc0Srenato break; 304a8c39dc0Srenato case AF_INET6: 305a8c39dc0Srenato if (IN6_IS_ADDR_LINKLOCAL(&src->v6)) 306a8c39dc0Srenato return (iface); 307a8c39dc0Srenato break; 308a8c39dc0Srenato default: 309a8c39dc0Srenato fatalx("disc_find_iface: unknown af"); 310a8c39dc0Srenato } 311ab0c2486Smichele 312ab0c2486Smichele return (NULL); 313ab0c2486Smichele } 314ab0c2486Smichele 315ab0c2486Smichele void 3162196e980Sclaudio session_accept(int fd, short event, void *bula) 317ab0c2486Smichele { 318a8c39dc0Srenato struct sockaddr_storage src; 319dbadea95Smichele socklen_t len = sizeof(src); 32035ee709dSrenato int newfd; 321a8c39dc0Srenato int af; 322a8c39dc0Srenato union ldpd_addr addr; 32335ee709dSrenato struct nbr *nbr; 32435ee709dSrenato struct pending_conn *pconn; 325ab0c2486Smichele 3264dda87d0Sclaudio if (!(event & EV_READ)) 327ab0c2486Smichele return; 328ab0c2486Smichele 3295f3d6e22Sclaudio newfd = accept4(fd, (struct sockaddr *)&src, &len, 3305f3d6e22Sclaudio SOCK_NONBLOCK | SOCK_CLOEXEC); 331ab0c2486Smichele if (newfd == -1) { 3324dda87d0Sclaudio /* 3334dda87d0Sclaudio * Pause accept if we are out of file descriptors, or 3344dda87d0Sclaudio * libevent will haunt us here too. 3354dda87d0Sclaudio */ 3364dda87d0Sclaudio if (errno == ENFILE || errno == EMFILE) { 3374dda87d0Sclaudio accept_pause(); 33862e3c252Sderaadt } else if (errno != EWOULDBLOCK && errno != EINTR && 33962e3c252Sderaadt errno != ECONNABORTED) 340b7b4db73Srenato log_debug("%s: accept error: %s", __func__, 341ab0c2486Smichele strerror(errno)); 342ab0c2486Smichele return; 343ab0c2486Smichele } 344ab0c2486Smichele 345a8c39dc0Srenato sa2addr((struct sockaddr *)&src, &af, &addr); 346a8c39dc0Srenato 34735ee709dSrenato /* 34835ee709dSrenato * Since we don't support label spaces, we can identify this neighbor 34935ee709dSrenato * just by its source address. This way we don't need to wait for its 35035ee709dSrenato * Initialization message to know who we are talking to. 35135ee709dSrenato */ 352a8c39dc0Srenato nbr = nbr_find_addr(af, &addr); 35335ee709dSrenato if (nbr == NULL) { 35435ee709dSrenato /* 35535ee709dSrenato * According to RFC 5036, we would need to send a No Hello 35635ee709dSrenato * Error Notification message and close this TCP connection 35735ee709dSrenato * right now. But doing so would trigger the backoff exponential 35835ee709dSrenato * timer in the remote peer, which would considerably slow down 35935ee709dSrenato * the session establishment process. The trick here is to wait 36035ee709dSrenato * five seconds before sending the Notification Message. There's 36135ee709dSrenato * a good chance that the remote peer will send us a Hello 36235ee709dSrenato * message within this interval, so it's worth waiting before 36335ee709dSrenato * taking a more drastic measure. 36435ee709dSrenato */ 365a8c39dc0Srenato pconn = pending_conn_find(af, &addr); 36635ee709dSrenato if (pconn) 36735ee709dSrenato close(newfd); 36835ee709dSrenato else 369a8c39dc0Srenato pending_conn_new(newfd, af, &addr); 37035ee709dSrenato return; 37135ee709dSrenato } 37235ee709dSrenato /* protection against buggy implementations */ 37335ee709dSrenato if (nbr_session_active_role(nbr)) { 37435ee709dSrenato close(newfd); 37535ee709dSrenato return; 37635ee709dSrenato } 37735ee709dSrenato if (nbr->state != NBR_STA_PRESENT) { 37835ee709dSrenato log_debug("%s: lsr-id %s: rejecting additional transport " 37935ee709dSrenato "connection", __func__, inet_ntoa(nbr->id)); 38035ee709dSrenato close(newfd); 38135ee709dSrenato return; 38235ee709dSrenato } 38335ee709dSrenato 38435ee709dSrenato session_accept_nbr(nbr, newfd); 38535ee709dSrenato } 38635ee709dSrenato 38735ee709dSrenato void 38835ee709dSrenato session_accept_nbr(struct nbr *nbr, int fd) 38935ee709dSrenato { 39035ee709dSrenato struct nbr_params *nbrp; 39135ee709dSrenato int opt; 39235ee709dSrenato socklen_t len; 39335ee709dSrenato 3941ce5acabSrenato nbrp = nbr_params_find(leconf, nbr->id); 3955ff72af8Srenato if (nbr_gtsm_check(fd, nbr, nbrp)) { 3965ff72af8Srenato close(fd); 3975ff72af8Srenato return; 3985ff72af8Srenato } 3995ff72af8Srenato 4007ee91690Sdlg if (!LIST_EMPTY(&leconf->auth_list)) { 401627846caSrenato if (sysdep.no_pfkey || sysdep.no_md5sig) { 402627846caSrenato log_warnx("md5sig configured but not available"); 40335ee709dSrenato close(fd); 404627846caSrenato return; 405627846caSrenato } 406627846caSrenato 407627846caSrenato len = sizeof(opt); 40835ee709dSrenato if (getsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt, &len) == -1) 409627846caSrenato fatal("getsockopt TCP_MD5SIG"); 410627846caSrenato if (!opt) { /* non-md5'd connection! */ 41135ee709dSrenato log_warnx("connection attempt without md5 signature"); 41235ee709dSrenato close(fd); 413627846caSrenato return; 414627846caSrenato } 415627846caSrenato } 416627846caSrenato 41735ee709dSrenato nbr->tcp = tcp_new(fd, nbr); 41835ee709dSrenato nbr_fsm(nbr, NBR_EVT_MATCH_ADJ); 419ab0c2486Smichele } 420ab0c2486Smichele 421c28a25a1Srenato static void 4222196e980Sclaudio session_read(int fd, short event, void *arg) 423ab0c2486Smichele { 42435ee709dSrenato struct nbr *nbr = arg; 42535ee709dSrenato struct tcp_conn *tcp = nbr->tcp; 426ab0c2486Smichele struct ldp_hdr *ldp_hdr; 42760e1e0e7Srenato struct ldp_msg *msg; 4282196e980Sclaudio char *buf, *pdu; 4292196e980Sclaudio ssize_t n, len; 4303de94509Srenato uint16_t pdu_len, msg_len, msg_size, max_pdu_len; 4313de94509Srenato int ret; 432ab0c2486Smichele 43335ee709dSrenato if (event != EV_READ) 4342196e980Sclaudio return; 435ab0c2486Smichele 436699b7d06Sclaudio if ((n = read(fd, tcp->rbuf->buf + tcp->rbuf->wpos, 437699b7d06Sclaudio sizeof(tcp->rbuf->buf) - tcp->rbuf->wpos)) == -1) { 4382196e980Sclaudio if (errno != EINTR && errno != EAGAIN) { 439b7b4db73Srenato log_warn("%s: read error", __func__); 44053e24948Sclaudio nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 4412196e980Sclaudio return; 4422196e980Sclaudio } 4432196e980Sclaudio /* retry read */ 4442196e980Sclaudio return; 4452196e980Sclaudio } 4462196e980Sclaudio if (n == 0) { 4472196e980Sclaudio /* connection closed */ 448b7b4db73Srenato log_debug("%s: connection closed by remote end", __func__); 44953e24948Sclaudio nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 4502196e980Sclaudio return; 4512196e980Sclaudio } 452699b7d06Sclaudio tcp->rbuf->wpos += n; 453ab0c2486Smichele 454699b7d06Sclaudio while ((len = session_get_pdu(tcp->rbuf, &buf)) > 0) { 455132e53f0Sjsg pdu = buf; 456132e53f0Sjsg ldp_hdr = (struct ldp_hdr *)pdu; 457ab0c2486Smichele if (ntohs(ldp_hdr->version) != LDP_VERSION) { 4587d508fe8Smichele session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0); 4592196e980Sclaudio free(buf); 460ab0c2486Smichele return; 461ab0c2486Smichele } 462ab0c2486Smichele 463ab0c2486Smichele pdu_len = ntohs(ldp_hdr->length); 464feeedd8aSrenato /* 465feeedd8aSrenato * RFC 5036 - Section 3.5.3: 466feeedd8aSrenato * "Prior to completion of the negotiation, the maximum 467feeedd8aSrenato * allowable length is 4096 bytes". 468feeedd8aSrenato */ 46935ee709dSrenato if (nbr->state == NBR_STA_OPER) 470feeedd8aSrenato max_pdu_len = nbr->max_pdu_len; 471feeedd8aSrenato else 472feeedd8aSrenato max_pdu_len = LDP_MAX_LEN; 4739277622bSrenato if (pdu_len < (LDP_HDR_PDU_LEN + LDP_MSG_SIZE) || 474feeedd8aSrenato pdu_len > max_pdu_len) { 47535791d36Srenato session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); 4762196e980Sclaudio free(buf); 477ab0c2486Smichele return; 478ab0c2486Smichele } 4799277622bSrenato pdu_len -= LDP_HDR_PDU_LEN; 48053e24948Sclaudio if (ldp_hdr->lsr_id != nbr->id.s_addr || 48153e24948Sclaudio ldp_hdr->lspace_id != 0) { 4822196e980Sclaudio session_shutdown(nbr, S_BAD_LDP_ID, 0, 0); 4832196e980Sclaudio free(buf); 484ab0c2486Smichele return; 4852196e980Sclaudio } 4862196e980Sclaudio pdu += LDP_HDR_SIZE; 487ab0c2486Smichele len -= LDP_HDR_SIZE; 488ab0c2486Smichele 48923695a60Srenato nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 49023695a60Srenato 4913de94509Srenato while (len >= LDP_MSG_SIZE) { 4923de94509Srenato uint16_t type; 493a9ad3d7dSmiod 49460e1e0e7Srenato msg = (struct ldp_msg *)pdu; 49560e1e0e7Srenato type = ntohs(msg->type); 49660e1e0e7Srenato msg_len = ntohs(msg->length); 497c31aa80eSrenato if (msg_len < LDP_MSG_LEN || 498c31aa80eSrenato (msg_len + LDP_MSG_DEAD_LEN) > pdu_len) { 49960e1e0e7Srenato session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 50060e1e0e7Srenato msg->type); 5012196e980Sclaudio free(buf); 5022196e980Sclaudio return; 5032196e980Sclaudio } 504c31aa80eSrenato msg_size = msg_len + LDP_MSG_DEAD_LEN; 5053de94509Srenato pdu_len -= msg_size; 506ab0c2486Smichele 50753e24948Sclaudio /* check for error conditions earlier */ 50853e24948Sclaudio switch (type) { 50953e24948Sclaudio case MSG_TYPE_INIT: 51053e24948Sclaudio if ((nbr->state != NBR_STA_INITIAL) && 51153e24948Sclaudio (nbr->state != NBR_STA_OPENSENT)) { 51253e24948Sclaudio session_shutdown(nbr, S_SHUTDOWN, 51360e1e0e7Srenato msg->id, msg->type); 51453e24948Sclaudio free(buf); 51553e24948Sclaudio return; 51653e24948Sclaudio } 51753e24948Sclaudio break; 51853e24948Sclaudio case MSG_TYPE_KEEPALIVE: 51953e24948Sclaudio if ((nbr->state == NBR_STA_INITIAL) || 52053e24948Sclaudio (nbr->state == NBR_STA_OPENSENT)) { 52153e24948Sclaudio session_shutdown(nbr, S_SHUTDOWN, 52260e1e0e7Srenato msg->id, msg->type); 52353e24948Sclaudio free(buf); 52453e24948Sclaudio return; 52553e24948Sclaudio } 52653e24948Sclaudio break; 5273b4c1866Srenato default: 52853e24948Sclaudio if (nbr->state != NBR_STA_OPER) { 52953e24948Sclaudio session_shutdown(nbr, S_SHUTDOWN, 53060e1e0e7Srenato msg->id, msg->type); 53153e24948Sclaudio free(buf); 53253e24948Sclaudio return; 53353e24948Sclaudio } 53453e24948Sclaudio break; 53553e24948Sclaudio } 53653e24948Sclaudio 537ab0c2486Smichele /* switch LDP packet type */ 53853e24948Sclaudio switch (type) { 539ab0c2486Smichele case MSG_TYPE_NOTIFICATION: 5409277622bSrenato ret = recv_notification(nbr, pdu, msg_size); 541ab0c2486Smichele break; 542ab0c2486Smichele case MSG_TYPE_INIT: 5439277622bSrenato ret = recv_init(nbr, pdu, msg_size); 544ab0c2486Smichele break; 545ab0c2486Smichele case MSG_TYPE_KEEPALIVE: 5469277622bSrenato ret = recv_keepalive(nbr, pdu, msg_size); 547ab0c2486Smichele break; 5483b4c1866Srenato case MSG_TYPE_CAPABILITY: 5493b4c1866Srenato ret = recv_capability(nbr, pdu, msg_size); 5503b4c1866Srenato break; 551ab0c2486Smichele case MSG_TYPE_ADDR: 552ab0c2486Smichele case MSG_TYPE_ADDRWITHDRAW: 5539277622bSrenato ret = recv_address(nbr, pdu, msg_size); 554ab0c2486Smichele break; 555ab0c2486Smichele case MSG_TYPE_LABELMAPPING: 556ab0c2486Smichele case MSG_TYPE_LABELREQUEST: 557ab0c2486Smichele case MSG_TYPE_LABELWITHDRAW: 558ab0c2486Smichele case MSG_TYPE_LABELRELEASE: 559ab0c2486Smichele case MSG_TYPE_LABELABORTREQ: 5609277622bSrenato ret = recv_labelmessage(nbr, pdu, msg_size, 5619277622bSrenato type); 562cf650e8bSrenato break; 563ab0c2486Smichele default: 56405822608Srenato log_debug("%s: unknown LDP message from nbr %s", 565b7b4db73Srenato __func__, inet_ntoa(nbr->id)); 56660e1e0e7Srenato if (!(ntohs(msg->type) & UNKNOWN_FLAG)) 5670101edf8Srenato send_notification(nbr->tcp, 56860e1e0e7Srenato S_UNKNOWN_MSG, msg->id, msg->type); 56905822608Srenato /* ignore the message */ 5709277622bSrenato ret = 0; 571da0a2a5cSrenato break; 572da0a2a5cSrenato } 573ab0c2486Smichele 5749277622bSrenato if (ret == -1) { 5752196e980Sclaudio /* parser failed, giving up */ 5762196e980Sclaudio free(buf); 577ab0c2486Smichele return; 5782196e980Sclaudio } 579ab0c2486Smichele 580ab0c2486Smichele /* Analyse the next message */ 5819277622bSrenato pdu += msg_size; 5829277622bSrenato len -= msg_size; 583ab0c2486Smichele } 5842196e980Sclaudio free(buf); 5852196e980Sclaudio if (len != 0) { 5862196e980Sclaudio session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); 5872196e980Sclaudio return; 5882196e980Sclaudio } 5892196e980Sclaudio } 590ab0c2486Smichele } 591ab0c2486Smichele 592c28a25a1Srenato static void 5932196e980Sclaudio session_write(int fd, short event, void *arg) 594ab0c2486Smichele { 595699b7d06Sclaudio struct tcp_conn *tcp = arg; 596699b7d06Sclaudio struct nbr *nbr = tcp->nbr; 597ab0c2486Smichele 59835ee709dSrenato if (!(event & EV_WRITE)) 59935ee709dSrenato return; 60035ee709dSrenato 601*3bba10cfSclaudio if (ibuf_write(fd, tcp->wbuf.wbuf) == -1) 602baf86509Sclaudio if (nbr) 603ab0c2486Smichele nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 60435ee709dSrenato 605*3bba10cfSclaudio if (nbr == NULL && msgbuf_queuelen(tcp->wbuf.wbuf) == 0) { 60635ee709dSrenato /* 60735ee709dSrenato * We are done sending the notification message, now we can 60835ee709dSrenato * close the socket. 60935ee709dSrenato */ 61035ee709dSrenato tcp_close(tcp); 61135ee709dSrenato return; 612699b7d06Sclaudio } 6132196e980Sclaudio 614699b7d06Sclaudio evbuf_event_add(&tcp->wbuf); 615ab0c2486Smichele } 616ab0c2486Smichele 617ab0c2486Smichele void 61860e1e0e7Srenato session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id, 61960e1e0e7Srenato uint32_t msg_type) 6207d508fe8Smichele { 62107f78510Srenato switch (nbr->state) { 62207f78510Srenato case NBR_STA_PRESENT: 62307f78510Srenato if (nbr_pending_connect(nbr)) 62407f78510Srenato event_del(&nbr->ev_connect); 62507f78510Srenato break; 62607f78510Srenato case NBR_STA_INITIAL: 62707f78510Srenato case NBR_STA_OPENREC: 62807f78510Srenato case NBR_STA_OPENSENT: 62907f78510Srenato case NBR_STA_OPER: 630d99a8fc3Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 63147c7016aSclaudio 6320101edf8Srenato send_notification(nbr->tcp, status, msg_id, msg_type); 633deb01a47Sclaudio 6347d508fe8Smichele nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 63507f78510Srenato break; 63607f78510Srenato default: 63707f78510Srenato fatalx("session_shutdown: unknown neighbor state"); 63807f78510Srenato } 6397d508fe8Smichele } 6407d508fe8Smichele 6417d508fe8Smichele void 642ab0c2486Smichele session_close(struct nbr *nbr) 643ab0c2486Smichele { 644d99a8fc3Srenato log_debug("%s: closing session with lsr-id %s", __func__, 645ab0c2486Smichele inet_ntoa(nbr->id)); 646ab0c2486Smichele 647699b7d06Sclaudio tcp_close(nbr->tcp); 648938c679bSclaudio nbr_stop_ktimer(nbr); 649938c679bSclaudio nbr_stop_ktimeout(nbr); 650c78471fcSrenato nbr_stop_itimeout(nbr); 651ab0c2486Smichele } 652ab0c2486Smichele 653c28a25a1Srenato static ssize_t 65426889e1dSclaudio session_get_pdu(struct buf_read *r, char **b) 6552196e980Sclaudio { 6562196e980Sclaudio struct ldp_hdr l; 6572196e980Sclaudio size_t av, dlen, left; 6582196e980Sclaudio 6592196e980Sclaudio av = r->wpos; 6602196e980Sclaudio if (av < sizeof(l)) 6612196e980Sclaudio return (0); 6622196e980Sclaudio 6632196e980Sclaudio memcpy(&l, r->buf, sizeof(l)); 6649277622bSrenato dlen = ntohs(l.length) + LDP_HDR_DEAD_LEN; 6652196e980Sclaudio if (dlen > av) 6662196e980Sclaudio return (0); 6672196e980Sclaudio 6682196e980Sclaudio if ((*b = malloc(dlen)) == NULL) 6692196e980Sclaudio return (-1); 6702196e980Sclaudio 6712196e980Sclaudio memcpy(*b, r->buf, dlen); 6722196e980Sclaudio if (dlen < av) { 6732196e980Sclaudio left = av - dlen; 6742196e980Sclaudio memmove(r->buf, r->buf + dlen, left); 6752196e980Sclaudio r->wpos = left; 6762196e980Sclaudio } else 6772196e980Sclaudio r->wpos = 0; 6782196e980Sclaudio 6792196e980Sclaudio return (dlen); 6802196e980Sclaudio } 68133f6ccfeSrenato 68233f6ccfeSrenato struct tcp_conn * 68333f6ccfeSrenato tcp_new(int fd, struct nbr *nbr) 68433f6ccfeSrenato { 68533f6ccfeSrenato struct tcp_conn *tcp; 68633f6ccfeSrenato 68733f6ccfeSrenato if ((tcp = calloc(1, sizeof(*tcp))) == NULL) 68833f6ccfeSrenato fatal(__func__); 68933f6ccfeSrenato 69033f6ccfeSrenato tcp->fd = fd; 69133f6ccfeSrenato evbuf_init(&tcp->wbuf, tcp->fd, session_write, tcp); 69235ee709dSrenato 69335ee709dSrenato if (nbr) { 69426889e1dSclaudio if ((tcp->rbuf = calloc(1, sizeof(struct buf_read))) == NULL) 69535ee709dSrenato fatal(__func__); 69635ee709dSrenato 69735ee709dSrenato event_set(&tcp->rev, tcp->fd, EV_READ | EV_PERSIST, 69835ee709dSrenato session_read, nbr); 69933f6ccfeSrenato event_add(&tcp->rev, NULL); 70035ee709dSrenato tcp->nbr = nbr; 70135ee709dSrenato } 70233f6ccfeSrenato 70333f6ccfeSrenato return (tcp); 70433f6ccfeSrenato } 70533f6ccfeSrenato 706c28a25a1Srenato static void 70733f6ccfeSrenato tcp_close(struct tcp_conn *tcp) 70833f6ccfeSrenato { 709e373a269Srenato /* try to flush write buffer */ 710*3bba10cfSclaudio ibuf_write(tcp->fd, tcp->wbuf.wbuf); 71133f6ccfeSrenato evbuf_clear(&tcp->wbuf); 71235ee709dSrenato 71335ee709dSrenato if (tcp->nbr) { 71433f6ccfeSrenato event_del(&tcp->rev); 71535ee709dSrenato free(tcp->rbuf); 71635ee709dSrenato tcp->nbr->tcp = NULL; 71735ee709dSrenato } 71835ee709dSrenato 71933f6ccfeSrenato close(tcp->fd); 72033f6ccfeSrenato accept_unpause(); 72133f6ccfeSrenato free(tcp); 72233f6ccfeSrenato } 72335ee709dSrenato 724c28a25a1Srenato static struct pending_conn * 725a8c39dc0Srenato pending_conn_new(int fd, int af, union ldpd_addr *addr) 72635ee709dSrenato { 72735ee709dSrenato struct pending_conn *pconn; 72835ee709dSrenato struct timeval tv; 72935ee709dSrenato 73035ee709dSrenato if ((pconn = calloc(1, sizeof(*pconn))) == NULL) 73135ee709dSrenato fatal(__func__); 73235ee709dSrenato 73335ee709dSrenato pconn->fd = fd; 734a8c39dc0Srenato pconn->af = af; 735a8c39dc0Srenato pconn->addr = *addr; 73635ee709dSrenato evtimer_set(&pconn->ev_timeout, pending_conn_timeout, pconn); 73735ee709dSrenato TAILQ_INSERT_TAIL(&global.pending_conns, pconn, entry); 73835ee709dSrenato 73935ee709dSrenato timerclear(&tv); 74035ee709dSrenato tv.tv_sec = PENDING_CONN_TIMEOUT; 74135ee709dSrenato if (evtimer_add(&pconn->ev_timeout, &tv) == -1) 74235ee709dSrenato fatal(__func__); 74335ee709dSrenato 74435ee709dSrenato return (pconn); 74535ee709dSrenato } 74635ee709dSrenato 74735ee709dSrenato void 74835ee709dSrenato pending_conn_del(struct pending_conn *pconn) 74935ee709dSrenato { 75035ee709dSrenato if (evtimer_pending(&pconn->ev_timeout, NULL) && 75135ee709dSrenato evtimer_del(&pconn->ev_timeout) == -1) 75235ee709dSrenato fatal(__func__); 75335ee709dSrenato 75435ee709dSrenato TAILQ_REMOVE(&global.pending_conns, pconn, entry); 75535ee709dSrenato free(pconn); 75635ee709dSrenato } 75735ee709dSrenato 75835ee709dSrenato struct pending_conn * 759a8c39dc0Srenato pending_conn_find(int af, union ldpd_addr *addr) 76035ee709dSrenato { 76135ee709dSrenato struct pending_conn *pconn; 76235ee709dSrenato 76335ee709dSrenato TAILQ_FOREACH(pconn, &global.pending_conns, entry) 764a8c39dc0Srenato if (af == pconn->af && 765a8c39dc0Srenato ldp_addrcmp(af, addr, &pconn->addr) == 0) 76635ee709dSrenato return (pconn); 76735ee709dSrenato 76835ee709dSrenato return (NULL); 76935ee709dSrenato } 77035ee709dSrenato 771c28a25a1Srenato static void 77235ee709dSrenato pending_conn_timeout(int fd, short event, void *arg) 77335ee709dSrenato { 77435ee709dSrenato struct pending_conn *pconn = arg; 77535ee709dSrenato struct tcp_conn *tcp; 77635ee709dSrenato 77735ee709dSrenato log_debug("%s: no adjacency with remote end: %s", __func__, 778a8c39dc0Srenato log_addr(pconn->af, &pconn->addr)); 77935ee709dSrenato 78035ee709dSrenato /* 78135ee709dSrenato * Create a write buffer detached from any neighbor to send a 78235ee709dSrenato * notification message reliably. 78335ee709dSrenato */ 78435ee709dSrenato tcp = tcp_new(pconn->fd, NULL); 7850101edf8Srenato send_notification(tcp, S_NO_HELLO, 0, 0); 786*3bba10cfSclaudio ibuf_write(fd, tcp->wbuf.wbuf); 78735ee709dSrenato 78835ee709dSrenato pending_conn_del(pconn); 78935ee709dSrenato } 790