struct lns *get_lns (struct tunnel *t) { /* * Look through our list of LNS's and * find a reasonable LNS for this call * if one is available */ struct lns *lns; struct iprange *ipr; int allow, checkdefault = 0; /* If access control is disabled, we give the default otherwise, we give nothing */ allow = 0; lns = lnslist; if (!lns) { lns = deflns; checkdefault = -1; } while (lns) { ipr = lns->lacs; while (ipr) { if ((ntohl (t->peer.sin_addr.s_addr) >= ntohl (ipr->start)) && (ntohl (t->peer.sin_addr.s_addr) <= ntohl (ipr->end))) { #ifdef DEBUG_AAA l2tp_log (LOG_DEBUG, "$s: Rule %s to %s, sense %s matched %s\n", __FUNCTION__, IPADDY (ipr->start), IPADDY (ipr->end), (ipr->sense ? "allow" : "deny"), IPADDY (t->peer.sin_addr.s_addr)); #endif allow = ipr->sense; } ipr = ipr->next; } if (allow) return lns; lns = lns->next; if (!lns && !checkdefault) { lns = deflns; checkdefault = -1; } } if (gconfig.accesscontrol) return NULL; else return deflns; }
void udp_xmit (struct buffer *buf, struct tunnel *t) { struct cmsghdr *cmsg; char cbuf[CMSG_SPACE(sizeof (unsigned int))]; unsigned int *refp; struct msghdr msgh; int err; struct iovec iov; /* * OKAY, now send a packet with the right SAref values. */ memset(&msgh, 0, sizeof(struct msghdr)); msgh.msg_control = cbuf; msgh.msg_controllen = 0; if(gconfig.ipsecsaref && t->refhim != IPSEC_SAREF_NULL) { msgh.msg_controllen = sizeof(cbuf); 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; msgh.msg_controllen = cmsg->cmsg_len; } 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)); } }
void lac_disconnect (int tid) { struct tunnel *t = tunnels.head; while (t) { if (t->ourtid == tid) { log (LOG_LOG, "Disconnecting from %s, Local: %d, Remote: %d\n", IPADDY (t->peer.sin_addr), t->ourtid, t->tid); t->self->needclose = -1; strcpy (t->self->errormsg, "Goodbye!"); call_close (t->self); return; } t = t->next; }; log (LOG_DEBUG, "No such tunnel %d to hang up.\n", tid); return; }
/* Now sends to syslog instead - MvO */ void show_status (void) { struct schedule_entry *se; struct tunnel *t; struct call *c; struct lns *tlns; struct lac *tlac; struct host *h; unsigned long cnt = 0; int s = 0; log (LOG_WARN, "====== l2tpd statistics ========\n"); log (LOG_WARN, " Scheduler entries:\n"); se = events; while (se) { s++; t = (struct tunnel *) se->data; tlac = (struct lac *) se->data; c = (struct call *) se->data; if (se->func == &hello) { log (LOG_WARN, "%d: HELLO to %d\n", s, t->tid); } else if (se->func == &magic_lac_dial) { log (LOG_WARN, "%d: Magic dial on %s\n", s, tlac->entname); } else if (se->func == &send_zlb) { log (LOG_WARN, "%d: Send payload ZLB on call %d:%d\n", s, c->container->tid, c->cid); } else if (se->func == &dethrottle) { log (LOG_WARN, "%d: Dethrottle call %d:%d\n", s, c->container->tid, c->cid); } else log (LOG_WARN, "%d: Unknown event\n", s); se = se->next; }; log (LOG_WARN, "Total Events scheduled: %d\n", s); log (LOG_WARN, "Number of tunnels open: %d\n", tunnels.count); t = tunnels.head; while (t) { log (LOG_WARN, "Tunnel %s, ID = %d (local), %d (remote) to %s:%d," " control_seq_num = %d, control_rec_seq_num = %d," " cLr = %d, call count = %d", (t->lac ? t->lac->entname : (t->lns ? t->lns->entname : "")), t->ourtid, t->tid, IPADDY (t->peer.sin_addr), ntohs (t->peer.sin_port), t->control_seq_num, t->control_rec_seq_num, t->cLr, t->count); c = t->call_head; while (c) { cnt++; log (LOG_WARN, "Call %s # %lu, ID = %d (local), %d (remote), serno = %u," " data_seq_num = %d, data_rec_seq_num = %d," " pLr = %d, tx = %u bytes (%u), rx= %u bytes (%u)", (c->lac ? c->lac-> entname : (c->lns ? c->lns->entname : "")), cnt, c->ourcid, c->cid, c->serno, c->data_seq_num, c->data_rec_seq_num, c->pLr, c->tx_bytes, c->tx_pkts, c->rx_bytes, c->rx_pkts); c = c->next; } t = t->next; } log (LOG_WARN, "==========Config File===========\n"); tlns = lnslist; while (tlns) { log (LOG_WARN, "LNS entry %s\n", tlns->entname[0] ? tlns->entname : "(unnamed)"); tlns = tlns->next; }; tlac = laclist; while (tlac) { log (LOG_WARN, "LAC entry %s, LNS is/are:", tlac->entname[0] ? tlac->entname : "(unnamed)"); h = tlac->lns; if (h) { while (h) { log (LOG_WARN, " %s", h->hostname); h = h->next; } } else log (LOG_WARN, " [none]"); tlac = tlac->next; }; log (LOG_WARN, "================================\n"); }
struct call *get_call (int tunnel, int call, unsigned int addr, int port) { /* * Figure out which call struct should handle this. * If we have tunnel and call ID's then they are unique. * Otherwise, if the tunnel is 0, look for an existing connection * or create a new tunnel. */ struct tunnel *st; struct call *sc; if (tunnel) { st = tunnels.head; while (st) { if (st->ourtid == tunnel) { if (call) { sc = st->call_head; while (sc) { if (sc->ourcid == call) return sc; sc = sc->next; } l2tp_log (LOG_DEBUG, "%s: can't find call %d in tunnel %d\n", __FUNCTION__, call, tunnel); return NULL; } else { return st->self; } } st = st->next; } l2tp_log (LOG_DEBUG, "%s:can't find tunnel %d\n", __FUNCTION__, tunnel); return NULL; } else { #ifdef USE_KERNEL struct l2tp_tunnel_opts to; #endif /* You can't specify a call number if you haven't specified a tunnel silly! */ if (call) { l2tp_log (LOG_WARN, "%s: call ID specified, but no tunnel ID specified. tossing.\n", __FUNCTION__); return NULL; } /* * Well, nothing appropriate... Let's add a new tunnel, if * we are not at capacity. */ if (debug_tunnel) { l2tp_log (LOG_DEBUG, "%s: allocating new tunnel for host %s, port %d.\n", __FUNCTION__, IPADDY (addr), ntohs (port)); } if (!(st = new_tunnel ())) { l2tp_log (LOG_WARN, "%s: unable to allocate new tunnel for host %s, port %d.\n", __FUNCTION__, IPADDY (addr), ntohs (port)); return NULL; }; st->peer.sin_family = AF_INET; st->peer.sin_port = port; bcopy (&addr, &st->peer.sin_addr, sizeof (addr)); #ifdef USE_KERNEL if (kernel_support) { /* Update kernel as to peer's location */ to.ourtid = st->ourtid; ioctl (server_socket, L2TPIOCGETTUNOPTS, &to); bcopy (&st->peer, &to.peer, sizeof (st->peer)); to.addrlen = sizeof (st->peer); ioctl (server_socket, L2TPIOCSETTUNOPTS, &to); } #endif st->next = tunnels.head; tunnels.head = st; tunnels.count++; return st->self; } }
void call_close (struct call *c) { struct buffer *buf; struct schedule_entry *se, *ose; struct call *tmp, *tmp2; if (!c || !c->container) { l2tp_log (LOG_DEBUG, "%s: called on null call or containerless call\n", __FUNCTION__); return; } if (c == c->container->self) { /* * We're actually closing the * entire tunnel */ /* First deschedule any remaining packet transmissions for this tunnel. That means Hello's and any reminaing packets scheduled for transmission. This is a very nasty little piece of code here. */ se = events; ose = NULL; while (se) { if ((((struct buffer *) se->data)->tunnel == c->container) || ((struct tunnel *) se->data == c->container)) { #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Descheduling event\n", __FUNCTION__); #endif if (ose) { ose->next = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = ose->next; } else { events = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = events; } } else { ose = se; se = se->next; } } if (c->closing) { /* Really close this tunnel, as our StopCCN has been ack'd */ #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Actually closing tunnel %d\n", __FUNCTION__, c->container->ourtid); #endif #ifdef USE_KERNEL if (kernel_support) ioctl (server_socket, L2TPIOCDELTUNNEL, c->container->ourtid); #endif destroy_tunnel (c->container); return; } /* * We need to close, but need to provide reliable delivery * of the final StopCCN. We record our state to know when * we have actually received an ACK on our StopCCN */ c->closeSs = c->container->control_seq_num; buf = new_outgoing (c->container); add_message_type_avp (buf, StopCCN); if (c->container->hbit) { mk_challenge (c->container->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, c->container->chal_them.vector, VECTOR_SIZE); } add_tunnelid_avp (buf, c->container->ourtid); if (c->result < 0) c->result = RESULT_CLEAR; if (c->error < 0) c->error = 0; add_result_code_avp (buf, c->result, c->error, c->errormsg, strlen (c->errormsg)); add_control_hdr (c->container, c, buf); if (packet_dump) do_packet_dump (buf); #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: enqueing close message for tunnel\n", __FUNCTION__); #endif control_xmit (buf); /* * We also need to stop all traffic on any calls contained * within us. */ tmp = c->container->call_head; while (tmp) { tmp2 = tmp->next; tmp->needclose = 0; tmp->closing = -1; call_close (tmp); tmp = tmp2; } /* mf, 16.04.2003: change log message to show tunneltag */ // l2tp_log (LOG_LOG, // "%s : Connection %d closed to %s, port %d (%s)\n", __FUNCTION__, // c->container->tid, // IPADDY (c->container->peer.sin_addr), // ntohs (c->container->peer.sin_port), c->errormsg); l2tp_log (LOG_LOG, "%s : Connection closed with peer %s, reason: %s\n", __FUNCTION__, c->container->tunneltag, c->errormsg); } else { /* * Just close a call */ #ifdef USE_KERNEL struct l2tp_call_opts co; #endif if (c->zlb_xmit) deschedule (c->zlb_xmit); /* if (c->dethrottle) deschedule(c->dethrottle); */ if (c->closing) { #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Actually closing call %d\n", __FUNCTION__, c->ourcid); #endif destroy_call (c); return; } #ifdef USE_KERNEL if (kernel_support) { co.ourtid = c->container->ourtid; co.ourcid = c->ourcid; ioctl (server_socket, L2TPIOCGETCALLOPTS, &co); co.flags = co.flags & ~L2TP_FLAG_CALL_UP; ioctl (server_socket, L2TPIOCSETCALLOPTS, &co); } #endif c->closeSs = c->container->control_seq_num; buf = new_outgoing (c->container); add_message_type_avp (buf, CDN); if (c->container->hbit) { mk_challenge (c->container->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, c->container->chal_them.vector, VECTOR_SIZE); } if (c->result < 0) c->result = RESULT_CLEAR; if (c->error < 0) c->error = 0; add_result_code_avp (buf, c->result, c->error, c->errormsg, strlen (c->errormsg)); #ifdef TEST_HIDDEN add_callid_avp (buf, c->ourcid, c->container); #else add_callid_avp (buf, c->ourcid); #endif add_control_hdr (c->container, c, buf); if (packet_dump) do_packet_dump (buf); #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: enqueuing close message for call %d\n", __FUNCTION__, c->ourcid); #endif control_xmit (buf); l2tp_log (LOG_LOG, "%s: Call %d to %s disconnected\n", __FUNCTION__, c->ourcid, IPADDY (c->container->peer.sin_addr)); } /* * Note that we're in the process of closing now */ c->closing = -1; }
struct call *get_call (int tunnel, int call, unsigned int addr, int port, IPsecSAref_t refme, IPsecSAref_t refhim) { /* * Figure out which call struct should handle this. * If we have tunnel and call ID's then they are unique. * Otherwise, if the tunnel is 0, look for an existing connection * or create a new tunnel. */ struct tunnel *st; struct call *sc; if (tunnel) { st = tunnels.head; while (st) { if (st->ourtid == tunnel && (gconfig.ipsecsaref==0 || (st->refhim == refhim || refhim==IPSEC_SAREF_NULL || st->refhim==IPSEC_SAREF_NULL))) { if (call) { sc = st->call_head; while (sc) { /* confirm that this is in fact a call with the right SA! */ if (sc->ourcid == call) return sc; sc = sc->next; } l2tp_log (LOG_DEBUG, "%s: can't find call %d in tunnel %d\n (ref=%d/%d)", __FUNCTION__, call, tunnel, refme, refhim); return NULL; } else { return st->self; } } st = st->next; } l2tp_log (LOG_DEBUG, "Can not find tunnel %u (refhim=%u)\n", tunnel, refhim); return NULL; } else { /* You can't specify a call number if you haven't specified a tunnel silly! */ if (call) { l2tp_log (LOG_WARNING, "%s: call ID specified, but no tunnel ID specified. tossing.\n", __FUNCTION__); return NULL; } /* * Well, nothing appropriate... Let's add a new tunnel, if * we are not at capacity. */ if (gconfig.debug_tunnel) { l2tp_log (LOG_DEBUG, "%s: allocating new tunnel for host %s, port %d.\n", __FUNCTION__, IPADDY (addr), ntohs (port)); } if (!(st = new_tunnel ())) { l2tp_log (LOG_WARNING, "%s: unable to allocate new tunnel for host %s, port %d.\n", __FUNCTION__, IPADDY (addr), ntohs (port)); return NULL; }; st->peer.sin_family = AF_INET; st->peer.sin_port = port; st->refme = refme; st->refhim = refhim; // <------- add for fix unable to connect to l2tp socket. By Jacky.Chen 2012.06.06 st->u_fd = -1; st->m_fd = -1; // ------> bcopy (&addr, &st->peer.sin_addr, sizeof (addr)); st->next = tunnels.head; tunnels.head = st; tunnels.count++; return st->self; } }
void call_close (struct call *c) { struct buffer *buf; struct schedule_entry *se, *ose; struct call *tmp, *tmp2; if (!c || !c->container) { l2tp_log (LOG_DEBUG, "%s: called on null call or containerless call\n", __FUNCTION__); return; } if (c == c->container->self) { /* * We're actually closing the * entire tunnel */ /* First deschedule any remaining packet transmissions for this tunnel. That means Hello's and any reminaing packets scheduled for transmission. This is a very nasty little piece of code here. */ se = events; ose = NULL; while (se) { if ((((struct buffer *) se->data)->tunnel == c->container) || ((struct tunnel *) se->data == c->container)) { #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Descheduling event\n", __FUNCTION__); #endif if (ose) { ose->next = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = ose->next; } else { events = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = events; } } else { ose = se; se = se->next; } } if (c->closing) { /* Really close this tunnel, as our StopCCN has been ack'd */ #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Actually closing tunnel %d\n", __FUNCTION__, c->container->ourtid); #endif destroy_tunnel (c->container); return; } /* * We need to close, but need to provide reliable delivery * of the final StopCCN. We record our state to know when * we have actually received an ACK on our StopCCN */ c->closeSs = c->container->control_seq_num; buf = new_outgoing (c->container); add_message_type_avp (buf, StopCCN); if (c->container->hbit) { mk_challenge (c->container->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, c->container->chal_them.vector, VECTOR_SIZE); } add_tunnelid_avp (buf, c->container->ourtid); if (c->result < 0) c->result = RESULT_CLEAR; if (c->error < 0) c->error = 0; add_result_code_avp (buf, c->result, c->error, c->errormsg, strlen (c->errormsg)); add_control_hdr (c->container, c, buf); if (gconfig.packet_dump) do_packet_dump (buf); #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: enqueing close message for tunnel\n", __FUNCTION__); #endif control_xmit (buf); /* * We also need to stop all traffic on any calls contained * within us. */ tmp = c->container->call_head; while (tmp) { tmp2 = tmp->next; tmp->needclose = 0; tmp->closing = -1; call_close (tmp); tmp = tmp2; } l2tp_log (LOG_DEBUG, "Connection %d closed to %s, port %d (%s)\n", c->container->tid, IPADDY (c->container->peer.sin_addr), ntohs (c->container->peer.sin_port), c->errormsg); if(strcmp(c->errormsg,"Server closing") ) { if(!strcmp(c->errormsg,"goodbye!") ) l2tp_log (LOG_INFO, "Terminated by router connect %s, cause manual disconnect.\n", IPADDY (c->container->peer.sin_addr) ); else if( c->msgtype <= 0 || c->msgtype > 16 ) l2tp_log (LOG_INFO, "Detect %s from %s, port %d \n", c->errormsg, IPADDY (c->container->peer.sin_addr), ntohs (c->container->peer.sin_port)); else l2tp_log (LOG_INFO, "Detect %s %s from %s, port %d \n", msgtypes[c->msgtype],c->errormsg, IPADDY (c->container->peer.sin_addr), ntohs (c->container->peer.sin_port)); } //if( (!strcmp(c->errormsg, "Timeout")) && (c->container->tid != 0) ) // l2tp_log(LOG_INFO, "Terminated by router, cause no response to echo-requests."); } else { /* * Just close a call */ if (c->zlb_xmit) deschedule (c->zlb_xmit); /* if (c->dethrottle) deschedule(c->dethrottle); */ if (c->closing) { #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Actually closing call %d\n", __FUNCTION__, c->ourcid); #endif destroy_call (c); return; } c->closeSs = c->container->control_seq_num; buf = new_outgoing (c->container); add_message_type_avp (buf, CDN); if (c->container->hbit) { mk_challenge (c->container->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, c->container->chal_them.vector, VECTOR_SIZE); } if (c->result < 0) c->result = RESULT_CLEAR; if (c->error < 0) c->error = 0; add_result_code_avp (buf, c->result, c->error, c->errormsg, strlen (c->errormsg)); #ifdef TEST_HIDDEN add_callid_avp (buf, c->ourcid, c->container); #else add_callid_avp (buf, c->ourcid); #endif add_control_hdr (c->container, c, buf); if (gconfig.packet_dump) do_packet_dump (buf); #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: enqueuing close message for call %d\n", __FUNCTION__, c->ourcid); #endif control_xmit (buf); l2tp_log (LOG_DEBUG, "%s: Call %d to %s disconnected\n", __FUNCTION__, c->ourcid, IPADDY (c->container->peer.sin_addr)); } /* * Note that we're in the process of closing now */ c->closing = -1; }