/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Network routines for UDP handling */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef LINUX # include #endif #include "l2tp.h" #include "ipsecmast.h" #include "misc.h" /* for IPADDY macro */ char hostname[256]; struct sockaddr_in server, from; /* Server and transmitter structs */ int server_socket; /* Server socket */ #ifdef USE_KERNEL int kernel_support; /* Kernel Support there or not? */ #endif int init_network (void) { long arg; unsigned int length = sizeof (server); gethostname (hostname, sizeof (hostname)); server.sin_family = AF_INET; server.sin_addr.s_addr = gconfig.listenaddr; server.sin_port = htons (gconfig.port); int flags; if ((server_socket = socket (PF_INET, SOCK_DGRAM, 0)) < 0) { l2tp_log (LOG_CRIT, "%s: Unable to allocate socket. Terminating.\n", __FUNCTION__); return -EINVAL; }; flags = 1; setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); #ifdef SO_NO_CHECK setsockopt(server_socket, SOL_SOCKET, SO_NO_CHECK, &flags, sizeof(flags)); #endif if (bind (server_socket, (struct sockaddr *) &server, sizeof (server))) { close (server_socket); l2tp_log (LOG_CRIT, "%s: Unable to bind socket: %s. Terminating.\n", __FUNCTION__, strerror(errno), errno); return -EINVAL; }; if (getsockname (server_socket, (struct sockaddr *) &server, &length)) { close (server_socket); l2tp_log (LOG_CRIT, "%s: Unable to read socket name.Terminating.\n", __FUNCTION__); return -EINVAL; } #ifdef LINUX /* * For L2TP/IPsec with KLIPSng, set the socket to receive IPsec REFINFO * values. */ if (!gconfig.ipsecsaref) { l2tp_log (LOG_INFO, "Not looking for kernel SAref support.\n"); } else { arg=1; if(setsockopt(server_socket, IPPROTO_IP, gconfig.sarefnum, &arg, sizeof(arg)) != 0 && !gconfig.forceuserspace) { l2tp_log(LOG_CRIT, "setsockopt recvref[%d]: %s\n", gconfig.sarefnum, strerror(errno)); gconfig.ipsecsaref=0; } arg=1; if(setsockopt(server_socket, IPPROTO_IP, IP_PKTINFO, (char*)&arg, sizeof(arg)) != 0) { l2tp_log(LOG_CRIT, "setsockopt IP_PKTINFO: %s\n", strerror(errno)); } } #else l2tp_log(LOG_INFO, "No attempt being made to use IPsec SAref's since we're not on a Linux machine.\n"); #endif #ifdef USE_KERNEL if (gconfig.forceuserspace) { l2tp_log (LOG_INFO, "Not looking for kernel support.\n"); kernel_support = 0; } else { int kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (kernel_fd < 0) { close(kernel_fd); l2tp_log (LOG_INFO, "L2TP kernel support not detected (try modprobing l2tp_ppp and pppol2tp)\n"); kernel_support = 0; } else { close(kernel_fd); l2tp_log (LOG_INFO, "Using l2tp kernel support.\n"); kernel_support = -1; } } #else l2tp_log (LOG_INFO, "This binary does not support kernel L2TP.\n"); #endif arg = fcntl (server_socket, F_GETFL); arg |= O_NONBLOCK; fcntl (server_socket, F_SETFL, arg); gconfig.port = ntohs (server.sin_port); return 0; } static inline void extract (void *buf, int *tunnel, int *call) { /* * Extract the tunnel and call #'s, and fix the order of the * version */ struct payload_hdr *p = (struct payload_hdr *) buf; if (PLBIT (p->ver)) { *tunnel = p->tid; *call = p->cid; } else { *tunnel = p->length; *call = p->tid; } } static inline void fix_hdr (void *buf) { /* * Fix the byte order of the header */ struct payload_hdr *p = (struct payload_hdr *) buf; _u16 ver = ntohs (p->ver); if (CTBIT (p->ver)) { /* * Control headers are always * exactly 12 bytes big. */ swaps (buf, 12); } else { int len = 6; if (PSBIT (ver)) len += 2; if (PLBIT (ver)) len += 2; if (PFBIT (ver)) len += 4; swaps (buf, len); } } void dethrottle (void *call) { UNUSED(call); /* struct call *c = (struct call *)call; */ /* if (c->throttle) { #ifdef DEBUG_FLOW log(LOG_DEBUG, "%s: dethrottling call %d, and setting R-bit\n",__FUNCTION__,c->ourcid); #endif c->rbit = RBIT; c->throttle = 0; } else { log(LOG_DEBUG, "%s: call %d already dethrottled?\n",__FUNCTION__,c->ourcid); } */ } void control_xmit (void *b) { struct buffer *buf = (struct buffer *) b; struct tunnel *t; struct timeval tv; int ns; if (!buf) { l2tp_log (LOG_WARNING, "%s: called on NULL buffer!\n", __FUNCTION__); return; } t = buf->tunnel; #ifdef DEBUG_CONTROL_XMIT if(t) { l2tp_log (LOG_DEBUG, "trying to send control packet to %d\n", t->ourtid); } #endif buf->retries++; ns = ntohs (((struct control_hdr *) (buf->start))->Ns); if (t) { if (ns < t->cLr) { #ifdef DEBUG_CONTROL_XMIT l2tp_log (LOG_DEBUG, "%s: Tossing packet %d\n", __FUNCTION__, ns); #endif /* Okay, it's been received. Let's toss it now */ toss (buf); return; } } if (buf->retries > gconfig.max_retries) { /* * Too many retries. Either kill the tunnel, or * if there is no tunnel, just stop retransmitting. */ if (t) { if (t->self->needclose) { l2tp_log (LOG_DEBUG, "Unable to deliver closing message for tunnel %d. Destroying anyway.\n", t->ourtid); t->self->needclose = 0; t->self->closing = -1; } else { l2tp_log (LOG_NOTICE, "Maximum retries exceeded for tunnel %d. Closing.\n", t->ourtid); strcpy (t->self->errormsg, "Timeout"); t->self->needclose = -1; } call_close(t->self); } toss (buf); } else { /* * Adaptive timeout with exponential backoff. The delay grows * exponentialy, unless it's capped by configuration. */ unsigned shift_by = (buf->retries-1); if (shift_by > 31) shift_by = 31; tv.tv_sec = 1LL << shift_by; tv.tv_usec = 0; schedule (tv, control_xmit, buf); #ifdef DEBUG_CONTROL_XMIT l2tp_log (LOG_DEBUG, "%s: Scheduling and transmitting packet %d\n", __FUNCTION__, ns); #endif udp_xmit (buf, t); } } unsigned char* get_inner_tos_byte (struct buffer *buf) { int tos_offset = 10; unsigned char *tos_byte = buf->start+tos_offset; return tos_byte; } unsigned char* get_inner_ppp_type (struct buffer *buf) { int ppp_type_offset = 8; unsigned char *ppp_type_byte = buf->start+ppp_type_offset; return ppp_type_byte; } void udp_xmit (struct buffer *buf, struct tunnel *t) { struct cmsghdr *cmsg = NULL; char cbuf[CMSG_SPACE(sizeof (unsigned int) + sizeof (struct in_pktinfo))]; unsigned int *refp; struct msghdr msgh; int err; struct iovec iov; int finallen = 0; /* * OKAY, now send a packet with the right SAref values. */ memset(&msgh, 0, sizeof(struct msghdr)); msgh.msg_control = cbuf; msgh.msg_controllen = sizeof(cbuf); if (gconfig.ipsecsaref && t->refhim != IPSEC_SAREF_NULL) { cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = gconfig.sarefnum; cmsg->cmsg_len = CMSG_LEN(sizeof(unsigned int)); if(gconfig.debug_network) { l2tp_log(LOG_DEBUG,"sending with saref=%d using sarefnum=%d\n", t->refhim, gconfig.sarefnum); } refp = (unsigned int *)CMSG_DATA(cmsg); *refp = t->refhim; finallen = cmsg->cmsg_len; } #ifdef LINUX if (t->my_addr.ipi_addr.s_addr){ struct in_pktinfo *pktinfo; if ( ! cmsg) { cmsg = CMSG_FIRSTHDR(&msgh); } else { cmsg = CMSG_NXTHDR(&msgh, cmsg); } cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg); *pktinfo = t->my_addr; finallen += cmsg->cmsg_len; } #endif /* * Some OS don't like assigned buffer with zero length (e.g. OpenBSD), * some OS don't like empty buffer with non-zero length (e.g. Linux). * So make them all happy by assigning control buffer only if we really * have something there and zero both fields otherwise. */ msgh.msg_controllen = finallen; if (!finallen) msgh.msg_control = NULL; iov.iov_base = buf->start; iov.iov_len = buf->len; /* return packet from whence it came */ msgh.msg_name = &buf->peer; msgh.msg_namelen = sizeof(buf->peer); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; /* Receive one packet. */ if ((err = sendmsg(server_socket, &msgh, 0)) < 0) { l2tp_log(LOG_ERR, "udp_xmit failed to %s:%d with err=%d:%s\n", IPADDY(t->peer.sin_addr), ntohs(t->peer.sin_port), err,strerror(errno)); } } int build_fdset (fd_set *readfds) { struct tunnel *tun; struct call *call; int max = 0; tun = tunnels.head; FD_ZERO (readfds); while (tun) { if (tun->udp_fd > -1) { if (tun->udp_fd > max) max = tun->udp_fd; FD_SET (tun->udp_fd, readfds); } call = tun->call_head; while (call) { if (call->needclose ^ call->closing) { call_close (call); call = tun->call_head; if (!call) break; continue; } if (call->fd > -1) { if (!call->needclose && !call->closing) { if (call->fd > max) max = call->fd; FD_SET (call->fd, readfds); } } call = call->next; } /* Now that call fds have been collected, and checked for * closing, check if the tunnel needs to be closed too */ if (tun->self->needclose ^ tun->self->closing) { if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: closing down tunnel %d\n", __FUNCTION__, tun->ourtid); call_close (tun->self); /* Reset the while loop * and check for NULL */ tun = tunnels.head; if (!tun) break; continue; } tun = tun->next; } FD_SET (server_socket, readfds); if (server_socket > max) max = server_socket; FD_SET (control_fd, readfds); if (control_fd > max) max = control_fd; return max; } void network_thread () { /* * We loop forever waiting on either data from the ppp drivers or from * our network socket. Control handling is no longer done here. */ struct sockaddr_in from; struct in_pktinfo to; unsigned int fromlen; int tunnel, call; /* Tunnel and call */ int recvsize; /* Length of data received */ struct buffer *buf; /* Payload buffer */ struct call *c, *sc; /* Call to send this off to */ struct tunnel *st; /* Tunnel */ fd_set readfds; /* Descriptors to watch for reading */ int max; /* Highest fd */ struct timeval tv, *ptv; /* Timeout for select */ struct msghdr msgh; struct iovec iov; char cbuf[256]; unsigned int refme, refhim; int * currentfd; int server_socket_processed; /* This one buffer can be recycled for everything except control packets */ buf = new_buf (MAX_RECV_SIZE); tunnel = 0; call = 0; for (;;) { int ret; process_signal(); max = build_fdset (&readfds); ptv = process_schedule(&tv); ret = select (max + 1, &readfds, NULL, NULL, ptv); if (ret <= 0) { if (ret == 0) { if (gconfig.debug_network) { l2tp_log (LOG_DEBUG, "%s: select timeout with max retries: %d for tunnel: %d\n", __FUNCTION__, gconfig.max_retries, tunnels.head->ourtid); } } else { if (gconfig.debug_network) { l2tp_log (LOG_DEBUG, "%s: select returned error %d (%s)\n", __FUNCTION__, errno, strerror (errno)); } } continue; } if (FD_ISSET (control_fd, &readfds)) { do_control (); } server_socket_processed = 0; currentfd = NULL; st = tunnels.head; while (st || !server_socket_processed) { if (st && (st->udp_fd == -1)) { st=st->next; continue; } if (st) { currentfd = &st->udp_fd; } else { currentfd = &server_socket; server_socket_processed = 1; } if (FD_ISSET (*currentfd, &readfds)) { /* * Okay, now we're ready for reading and processing new data. */ recycle_buf (buf); /* Reserve space for expanding payload packet headers */ buf->start += PAYLOAD_BUF; buf->len -= PAYLOAD_BUF; memset(&from, 0, sizeof(from)); memset(&to, 0, sizeof(to)); fromlen = sizeof(from); memset(&msgh, 0, sizeof(struct msghdr)); iov.iov_base = buf->start; iov.iov_len = buf->len; msgh.msg_control = cbuf; msgh.msg_controllen = sizeof(cbuf); msgh.msg_name = &from; msgh.msg_namelen = fromlen; msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; /* Receive one packet. */ recvsize = recvmsg(*currentfd, &msgh, 0); if (recvsize < MIN_PAYLOAD_HDR_LEN) { if (recvsize < 0) { if (errno == ECONNREFUSED) { close(*currentfd); } if ((errno == ECONNREFUSED) || (errno == EBADF)) { *currentfd = -1; } if (errno != EAGAIN) l2tp_log (LOG_WARNING, "%s: recvfrom returned error %d (%s)\n", __FUNCTION__, errno, strerror (errno)); } else { l2tp_log (LOG_WARNING, "%s: received too small a packet\n", __FUNCTION__); } if (st) st=st->next; continue; } refme=refhim=0; struct cmsghdr *cmsg; /* Process auxiliary received data in msgh */ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { #ifdef LINUX /* extract destination(our) addr */ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { struct in_pktinfo* pktInfo = ((struct in_pktinfo*)CMSG_DATA(cmsg)); to = *pktInfo; } else #endif /* extract IPsec info out */ if (gconfig.ipsecsaref && cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == gconfig.sarefnum) { unsigned int *refp; refp = (unsigned int *)CMSG_DATA(cmsg); refme =refp[0]; refhim=refp[1]; } } /* * some logic could be added here to verify that we only * get L2TP packets inside of IPsec, or to provide different * classes of service to packets not inside of IPsec. */ buf->len = recvsize; fix_hdr (buf->start); extract (buf->start, &tunnel, &call); if (gconfig.debug_network) { #ifdef LINUX char from_addr[128] = {0}; char to_addr[128] = {0}; inet_ntop(AF_INET, (void *)&from.sin_addr, from_addr, 128); inet_ntop(AF_INET, (void *)&to.ipi_addr, to_addr, 128); l2tp_log(LOG_DEBUG, "%s: recv packet from %s, to %s, size = %d, " "tunnel = %d, call = %d ref=%u refhim=%u\n", __FUNCTION__, from_addr, to_addr, recvsize, tunnel, call, refme, refhim); #else l2tp_log(LOG_DEBUG, "%s: recv packet from %s, size = %d, " "tunnel = %d, call = %d ref=%u refhim=%u\n", __FUNCTION__, inet_ntoa (from.sin_addr), recvsize, tunnel, call, refme, refhim); #endif } if (gconfig.packet_dump) { do_packet_dump (buf); } if (!(c = get_call (tunnel, call, from.sin_addr, from.sin_port, refme, refhim))) { if ((c = get_tunnel (tunnel, from.sin_addr.s_addr, from.sin_port))) { /* * It is theoretically possible that we could be sent * a control message (say a StopCCN) on a call that we * have already closed or some such nonsense. To * prevent this from closing the tunnel, if we get a * call on a valid tunnel, but not with a valid CID, * we'll just send a ZLB to ACK receiving the packet. */ if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: no such call %d on tunnel %d. Sending special ZLB\n", __FUNCTION__, call, tunnel); if(1==handle_special (buf, c, call)) { buf = new_buf (MAX_RECV_SIZE); } } else l2tp_log (LOG_DEBUG, "%s: unable to find call or tunnel to handle packet. call = %d, tunnel = %d Dumping.\n", __FUNCTION__, call, tunnel); } else { if (c->container) { c->container->my_addr = to; } buf->peer = from; /* Handle the packet */ c->container->chal_us.vector = NULL; if (handle_packet (buf, c->container, c)) { if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: bad packet\n", __FUNCTION__); } if (c->cnu) { /* Send Zero Byte Packet */ control_zlb (buf, c->container, c); c->cnu = 0; } } } if (st) st=st->next; } /* * finished obvious sources, look for data from PPP connections. */ for (st = tunnels.head; st; st = st->next) { for (sc = st->call_head; sc; sc = sc->next) { if ((sc->fd < 0) || !FD_ISSET (sc->fd, &readfds)) continue; /* Got some payload to send */ int result; while ((result = read_packet (sc)) > 0) { add_payload_hdr (sc->container, sc, sc->ppp_buf); if (gconfig.packet_dump) { do_packet_dump (sc->ppp_buf); } sc->prx = sc->data_rec_seq_num; if (sc->zlb_xmit) { deschedule (sc->zlb_xmit); sc->zlb_xmit = NULL; } sc->tx_bytes += sc->ppp_buf->len; sc->tx_pkts++; unsigned char* tosval = get_inner_tos_byte(sc->ppp_buf); unsigned char* typeval = get_inner_ppp_type(sc->ppp_buf); int tosval_dec = (int)*tosval; int typeval_dec = (int)*typeval; if (typeval_dec != 33 ) tosval_dec=atoi(gconfig.controltos); setsockopt(server_socket, IPPROTO_IP, IP_TOS, &tosval_dec, sizeof(tosval_dec)); udp_xmit (sc->ppp_buf, st); recycle_payload (sc->ppp_buf, sc->container->peer); } if (result != 0) { l2tp_log (LOG_WARNING, "%s: tossing read packet, error = %s (%d). Closing call.\n", __FUNCTION__, strerror (-result), -result); strcpy (sc->errormsg, strerror (-result)); sc->needclose = -1; } } // for (sc.. } // for (st.. } } #ifdef USE_KERNEL int connect_pppol2tp(struct tunnel *t) { if (!kernel_support) return 0; int ufd = -1, fd2 = -1; int flags; struct sockaddr_pppol2tp sax; struct sockaddr_in server; memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_addr.s_addr = gconfig.listenaddr; server.sin_port = htons (gconfig.port); if ((ufd = socket (PF_INET, SOCK_DGRAM, 0)) < 0) { l2tp_log (LOG_CRIT, "%s: Unable to allocate UDP socket. Terminating.\n", __FUNCTION__); return -EINVAL; }; flags=1; setsockopt(ufd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); #ifdef SO_NO_CHECK setsockopt(ufd, SOL_SOCKET, SO_NO_CHECK, &flags, sizeof(flags)); #endif if (bind (ufd, (struct sockaddr *) &server, sizeof (server))) { close (ufd); l2tp_log (LOG_CRIT, "%s: Unable to bind UDP socket: %s. Terminating.\n", __FUNCTION__, strerror(errno), errno); return -EINVAL; }; server = t->peer; flags = fcntl(ufd, F_GETFL); if (flags == -1 || fcntl(ufd, F_SETFL, flags | O_NONBLOCK) == -1) { l2tp_log (LOG_WARNING, "%s: Unable to set UDP socket nonblock.\n", __FUNCTION__); return -EINVAL; } if (connect (ufd, (struct sockaddr *) &server, sizeof(server)) < 0) { l2tp_log (LOG_CRIT, "%s: Unable to connect UDP peer. Terminating.\n", __FUNCTION__); close(ufd); return -EINVAL; } t->udp_fd=ufd; fd2 = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (fd2 < 0) { l2tp_log (LOG_WARNING, "%s: Unable to allocate PPPoL2TP socket.\n", __FUNCTION__); return -EINVAL; } flags = fcntl(fd2, F_GETFL); if (flags == -1 || fcntl(fd2, F_SETFL, flags | O_NONBLOCK) == -1) { l2tp_log (LOG_WARNING, "%s: Unable to set PPPoL2TP socket nonblock.\n", __FUNCTION__); close(fd2); return -EINVAL; } memset(&sax, 0, sizeof(sax)); sax.sa_family = AF_PPPOX; sax.sa_protocol = PX_PROTO_OL2TP; sax.pppol2tp.fd = t->udp_fd; sax.pppol2tp.addr.sin_addr.s_addr = t->peer.sin_addr.s_addr; sax.pppol2tp.addr.sin_port = t->peer.sin_port; sax.pppol2tp.addr.sin_family = AF_INET; sax.pppol2tp.s_tunnel = t->ourtid; sax.pppol2tp.d_tunnel = t->tid; if ((connect(fd2, (struct sockaddr *)&sax, sizeof(sax))) < 0) { l2tp_log (LOG_WARNING, "%s: Unable to connect PPPoL2TP socket. %d %s\n", __FUNCTION__, errno, strerror(errno)); close(fd2); return -EINVAL; } t->pppox_fd = fd2; return 0; } #endif