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)); } }
int set_rand_source (char *word, char *value, int context, void *item) { time_t seconds; /* * We're going to go ahead and seed the rand() function with srand() * because even if we set the randomness source to dev or egd, they * can fall back to sys if they fail, so we want to make sure we at * least have *some* semblance of randomness available from the * rand() function */ /* * This is a sucky random number seed...just the result from the * time() call...but...the user requested to use the rand() * function, which is a pretty sucky source of randomness * regardless...at least we can get a almost sorta decent seed. If * you have any better suggestions for creating a seed...lemme know * :/ */ seconds = time(NULL); srand(seconds); if (context != CONTEXT_GLOBAL) { l2tp_log(LOG_WARNING, "%s: %s not valid in context %d\n", __FUNCTION__, word, context); return -1; } /* WORKING HERE */ if (strlen(value) == 0) { snprintf(filerr, sizeof (filerr), "no randomness source specified\n"); return -1; } if (strncmp(value, "egd", 3) == 0) { return set_rand_egd(value); } else if (strncmp(value, "dev", 3) == 0) { return set_rand_dev(); } else if (strncmp(value, "sys", 3) == 0) { return set_rand_sys(); } else { l2tp_log(LOG_WARNING, "%s: %s is not a valid randomness source\n", __FUNCTION__, value); return -1; } }
struct tunnel *l2tp_call (char *host, int port, struct lac *lac, struct lns *lns) { /* * Establish a tunnel from us to host * on port port */ struct call *tmp = NULL; struct hostent *hp; struct in_addr addr; port = htons (port); hp = gethostbyname (host); if (!hp) { l2tp_log (LOG_WARNING, "Host name lookup failed for %s.\n", host); return NULL; } bcopy (hp->h_addr, &addr.s_addr, hp->h_length); /* Force creation of a new tunnel and set it's tid to 0 to cause negotiation to occur */ /* * to do IPsec properly here, we need to set a socket policy, * and/or communicate with pluto. */ tmp = get_call (0, 0, addr, port, IPSEC_SAREF_NULL, IPSEC_SAREF_NULL); if (!tmp) { l2tp_log (LOG_WARNING, "%s: Unable to create tunnel to %s.\n", __FUNCTION__, host); return NULL; } tmp->container->tid = 0; tmp->container->lac = lac; tmp->container->lns = lns; tmp->lac = lac; tmp->lns = lns; if (lac) lac->t = tmp->container; if (lns) lns->t = tmp->container; /* * Since our state is 0, we will establish a tunnel now */ l2tp_log (LOG_NOTICE, "Connecting to host %s, port %d\n", host, ntohs (port)); control_finish (tmp->container, tmp); return tmp->container; }
static void consider_pidfile() { int pid=0; int i,l; char buf[STRLEN]; /* Read previous pid file. */ i = open(gconfig.pidfile,O_RDONLY); if (i < 0) { /* l2tp_log(LOG_DEBUG, "%s: Unable to read pid file [%s]\n", __FUNCTION__, gconfig.pidfile); */ } else { l=read(i,buf,sizeof(buf)-1); close (i); if (l >= 0) { buf[l] = '\0'; pid = atoi(buf); } /* If the previous server process is still running, complain and exit immediately. */ if (pid && pid != getpid () && kill (pid, 0) == 0) { l2tp_log(LOG_INFO, "%s: There's already a xl2tpd server running.\n", __FUNCTION__); close(server_socket); exit(1); } } pid = setsid(); unlink(gconfig.pidfile); if ((i = open (gconfig.pidfile, O_WRONLY | O_CREAT, 0640)) >= 0) { snprintf (buf, sizeof(buf), "%d\n", (int)getpid()); if (-1 == write (i, buf, strlen(buf))) { l2tp_log (LOG_CRIT, "%s: Unable to write to %s.\n", __FUNCTION__, gconfig.pidfile); close (i); exit(1); } close (i); } }
int build_fdset_ipv6 (fd_set *readfds) { struct tunnel6 *tun; struct call6 *call; int max = 0; tun = tunnels6.head; FD_ZERO (readfds); while (tun) { call = tun->call_head; while (call) { if (call->needclose ^ call->closing) { call_close6 (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_close6 (tun->self); /* Reset the while loop * and check for NULL */ tun = tunnels6.head; if (!tun) break; continue; } tun = tun->next; } FD_SET (server_socket6, readfds); if (server_socket6 > max) max = server_socket6; FD_SET (control_fd, readfds); if (control_fd > max) max = control_fd; return max; }
void l2tp_pkt_free(struct l2tp_packet *pkt) { int buf; L2TP_DEBUG(L2TP_DATA, "%s: pkt=%p, msg=%d tid=%hu sid=%hu ns=%hu nr=%hu", __func__, pkt, pkt->msg_type, pkt->tunnel_id, pkt->session_id, pkt->nr, pkt->ns); if (pkt->num_bufs > 0) { for (buf = 0; buf < pkt->num_bufs; buf++) { if (pkt->iov[buf].iov_base != NULL) { #ifdef DEBUG if (pkt->iov[buf].iov_len == 0) { l2tp_log(LOG_ERR, "Freeing zero length buffer %p, index %d?", pkt->iov[buf].iov_base, buf); } USL_POISON_MEMORY(pkt->iov[buf].iov_base, 0xe8, pkt->iov[buf].iov_len); #endif free(pkt->iov[buf].iov_base); } else { break; } } } USL_POISON_MEMORY(pkt, 0xe7, sizeof(*pkt)); free(pkt); }
int getPtyMaster_pty (char *tty10, char *tty01) { char *p10; char *p01; static char dev[] = PTY00; int fd; for (p10 = PTY10; *p10; p10++) { dev[8] = *p10; for (p01 = PTY01; *p01; p01++) { dev[9] = *p01; fd = open (dev, O_RDWR | O_NONBLOCK); if (fd >= 0) { *tty10 = *p10; *tty01 = *p01; return fd; } } } l2tp_log (LOG_CRIT, "%s: No more free pseudo-tty's\n", __FUNCTION__); return -1; }
int set_localiprange (char *word, char *value, int context, void *item) { struct lns *lns = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } if (lns->localaddr) { snprintf (filerr, sizeof (filerr), "'local ip range' and 'local ip' are mutually exclusive\n"); return -1; } lns->localrange = set_range (word, value, lns->localrange); if (!lns->localrange) return -1; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "range start = %x, end = %x, sense=%ud\n", ntohl (lns->range->start), ntohl (lns->range->end), lns->range->sense); #endif return 0; }
int getPtyMaster(char *ttybuf, int ttybuflen) { int fd=-1; #ifndef OPENBSD fd = getPtyMaster_ptmx(ttybuf, ttybuflen); char a, b; if(fd >= 0) { return fd; } l2tp_log (LOG_WARNING, "%s: failed to use pts -- using legacy ptys\n", __FUNCTION__); fd = getPtyMaster_pty(&a,&b); if(fd >= 0) { snprintf(ttybuf, ttybuflen, "/dev/tty%c%c", a, b); return fd; } #endif #ifdef OPENBSD fd = getPtyMaster_ptm(ttybuf, ttybuflen); if(fd >= 0) { return fd; } #endif /* OPENBSD */ return -EINVAL; }
int set_rand_sys () { l2tp_log(LOG_WARNING, "The \"rand()\" function call is not a very good source" "of randomness\n"); rand_source = RAND_SYS; return 0; }
int set_authfile (char *word, char *value, int context, void *item) { if (!strlen (value)) { snprintf (filerr, sizeof (filerr), "no filename specified for authentication\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_authfile: Setting global auth file to '%s'\n", value); #endif /* ; */ strncpy (((struct global *) item)->authfile, value, sizeof (((struct global *)item)->authfile)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; }
static void l2tp_init(void) { l2tp_log(LOG_INFO, "started"); #ifdef L2TP_DMALLOC /* dmalloc debug options are set in the environment. However, * certain options cause problems to this application. We * therefore ensure that the troublesome options are disabled, * regardless of the user's settings. The disabled options * are: alloc-blank, free-blank, force-linear. If these * options are enabled, it causes strange problems in the * generated RPC code. */ dmalloc_debug(dmalloc_debug_current() & 0xff5dffff); l2tp_dmalloc_mark = dmalloc_mark(); if (getenv("DMALLOC_OPTIONS") != NULL) { l2tp_log(LOG_WARNING, "DMALLOC debugging enabled"); } #endif l2tp_my_pid = getpid(); atexit(l2tp_cleanup); L2TP_DEBUG(L2TP_FUNC, "%s (%s %s): trace flags = %08lx", __FUNCTION__, __DATE__, __TIME__, l2tp_opt_trace_flags); usl_set_debug(l2tp_opt_debug, l2tp_system_log); usl_signal_terminate_hook = l2tp_die; usl_signal_init(); usl_fd_init(); usl_timer_init(); usl_pid_init(); l2tp_net_init(); l2tp_rand_fd = open("/dev/random", O_RDONLY); if (l2tp_rand_fd < 0) { fprintf(stderr, "No /dev/random device found. Exiting.\n"); exit(1); } usl_signal_notifier_add(l2tp_signal_handler, NULL); l2tp_avp_init(); l2tp_peer_init(); l2tp_api_init(); l2tp_xprt_init(); l2tp_tunnel_init(); l2tp_session_init(); l2tp_ppp_init(); }
int set_string (char *word, char *value, char *ptr, int len) { #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value); #endif /* ; */ strncpy (ptr, value, len); return 0; }
static void open_controlfd() { control_fd = open (gconfig.controlfile, O_RDONLY | O_NONBLOCK, 0600); if (control_fd < 0) { l2tp_log (LOG_CRIT, "%s: Unable to open %s for reading.\n", __FUNCTION__, gconfig.controlfile); exit (1); } /* turn off O_NONBLOCK */ if(fcntl(control_fd, F_SETFL, O_RDONLY)==-1) { l2tp_log(LOG_CRIT, "Can not turn off nonblocking mode for controlfd: %s\n", strerror(errno)); exit(1); } }
int getPtyMaster_ptmx(char *ttybuf, int ttybuflen) { int fd; char *tty; fd = open("/dev/ptmx", O_RDWR); if (fd == -1) { l2tp_log (LOG_WARNING, "%s: unable to open /dev/ptmx to allocate pty\n", __FUNCTION__); return -EINVAL; } #if 0 /* not needed, triggers SElinux block */ /* change the onwership */ if (grantpt(fd)) { l2tp_log (LOG_WARNING, "%s: unable to grantpt() on pty\n", __FUNCTION__); close(fd); return -EINVAL; } #endif if (unlockpt(fd)) { l2tp_log (LOG_WARNING, "%s: unable to unlockpt() on pty\n", __FUNCTION__); close(fd); return -EINVAL; } tty = ptsname(fd); if (tty == NULL) { l2tp_log (LOG_WARNING, "%s: unable to obtain name of slave tty\n", __FUNCTION__); close(fd); return -EINVAL; } ttybuf[0]='\0'; strncat(ttybuf, tty, ttybuflen); return fd; }
int init_config6 () { FILE *f; int returnedValue; gconfig.port = UDP_LISTEN_PORT; //TODO: need to change to in6addr_any as it is INADDR_ANY in ipv4 // Default is to bind (listen) to all interfaces // Assigning zero to listenaddr6 (IN6ADDR_INIT_ANY) // memset((void*) &gconfig.ipaddr.listenaddr6, 0, 16); gconfig.ipaddr.listenaddr6 = in6addr_any; gconfig.debug_avp = 0; gconfig.debug_network = 0; gconfig.packet_dump = 0; gconfig.debug_tunnel = 0; gconfig.debug_state = 0; lnslist6 = NULL; laclist6 = NULL; deflac6 = (struct lac6 *) malloc (sizeof (struct lac6)); f = fopen (gconfig.configfile, "r"); if (!f) { f = fopen (gconfig.altconfigfile, "r"); if (f) { l2tp_log (LOG_WARNING, "%s: Using old style config files %s and %s\n", __FUNCTION__, gconfig.altconfigfile, gconfig.altauthfile); strncpy (gconfig.authfile, gconfig.altauthfile, sizeof (gconfig.authfile)); } else { l2tp_log (LOG_CRIT, "%s: Unable to open config file %s or %s\n", __FUNCTION__, gconfig.configfile, gconfig.altconfigfile); return -1; } } returnedValue = parse_config6 (f); fclose (f); return (returnedValue); filerr[0] = 0; }
int set_lns (char *word, char *value, int context, void *item) { #if 0 struct hostent *hp; #endif struct lac *l; struct host *ipr, *pos; char *d; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_lns: setting LNS to '%s'\n", value); #endif l = (struct lac *) item; d = strchr (value, ':'); if (d) { d[0] = 0; d++; } #if 0 // why would you want to lookup hostnames at this time? hp = gethostbyname (value); if (!hp) { snprintf (filerr, sizeof (filerr), "no such host '%s'\n", value); return -1; } #endif ipr = malloc (sizeof (struct host)); ipr->next = NULL; pos = l->lns; if (!pos) { l->lns = ipr; } else { while (pos->next) pos = pos->next; pos->next = ipr; } strncpy (ipr->hostname, value, sizeof (ipr->hostname)); if (d) ipr->port = atoi (d); else ipr->port = UDP_LISTEN_PORT; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; }
static int sra_sanity_failed(struct call *c, int datalen) { if (likely((datalen == 6) && (c->msgtype == ICCN))) return 0; if (datalen != 6) { l2tp_log(LOG_DEBUG, "%s: avp is incorrect size. %d != 6\n", __func__, datalen); wrong_length(c, "Sequencing Required", 6, datalen, 1); return -EINVAL; } l2tp_log(LOG_DEBUG, "%s: sequencing required not appropriate for %s!\n", __func__, msgtypes[c->msgtype]); return -EINVAL; }
void l2tp_make_random_vector(void *buf, int buf_len) { size_t count; count = usl_fd_read(l2tp_rand_fd, buf, buf_len); if ((count < 0) && (errno != EAGAIN)) { l2tp_log(LOG_ERR, "ERROR: problem reading /dev/random: %s", strerror(errno)); exit(1); } }
bool_t l2tp_test_log_1_svc(char *message, int *result, struct svc_req *req) { #ifdef L2TP_TEST l2tp_log(LOG_INFO, "APP: %s", message); *result = 0; return TRUE; #else /* L2TP_TEST */ return FALSE; #endif /* L2TP_TEST */ }
void schedule_redial(struct lac *lac) { struct timeval tv; if (lac->redial && (lac->rtimeout > 0) && !lac->rsched) { l2tp_log (LOG_INFO, "Network is broken now. Will redial in %d seconds\n", lac->rtimeout); tv.tv_sec = lac->rtimeout; tv.tv_usec = 0; lac->rsched = schedule (tv, magic_lac_dial, lac); } }
static inline int is_datalen_bad(struct call *c, int len, int cmp, const char *msg) { if (likely(len >= cmp)) return 0; l2tp_log(LOG_DEBUG, "%s: avp is incorrect size. %d < %d\n", __func__, len, cmp); wrong_length(c, msg, cmp, len, 1); return 1; }
void lac_disconnect6 (int tid) { struct tunnel6 *t = tunnels6.head; while (t) { if (t->ourtid == tid) { l2tp_log (LOG_INFO, "Disconnecting from %s, Local: %d, Remote: %d\n", IPADDY6 (t->peer.sin6_addr), t->ourtid, t->tid); t->self->needclose = -1; strcpy (t->self->errormsg, "Goodbye!"); call_close6 (t->self); return; } t = t->next; }; l2tp_log (LOG_DEBUG, "No such tunnel %d to hang up.\n", tid); return; }
int seq_reqd_avp(struct tunnel *t, struct call *c, const struct avp *data, int datalen) { if (sanity_enabled(t) && sra_sanity_failed(c, datalen)) return -EINVAL; if (gconfig.debug_avp) l2tp_log(LOG_DEBUG, "%s: peer requires sequencing.\n", __func__); c->seq_reqd = -1; return 0; }
int init_config () { FILE *f; int returnedValue; gconfig.port = UDP_LISTEN_PORT; gconfig.sarefnum = IP_IPSEC_REFINFO; /* default use the latest we know */ gconfig.listenaddr = htonl(INADDR_ANY); /* Default is to bind (listen) to all interfaces */ gconfig.debug_avp = 0; gconfig.debug_network = 0; gconfig.packet_dump = 0; gconfig.debug_tunnel = 0; gconfig.debug_state = 0; lnslist = NULL; laclist = NULL; deflac = (struct lac *) calloc (1, sizeof (struct lac)); f = fopen (gconfig.configfile, "r"); if (!f) { f = fopen (gconfig.altconfigfile, "r"); if (f) { l2tp_log (LOG_WARNING, "%s: Using old style config files %s and %s\n", __FUNCTION__, gconfig.altconfigfile, gconfig.altauthfile); strncpy (gconfig.authfile, gconfig.altauthfile, sizeof (gconfig.authfile)); } else { l2tp_log (LOG_CRIT, "%s: Unable to open config file %s or %s\n", __FUNCTION__, gconfig.configfile, gconfig.altconfigfile); return -1; } } returnedValue = parse_config (f); fclose (f); return (returnedValue); filerr[0] = 0; }
/* die - clean up state and exit with the specified status. */ static void l2tp_die(void) { static int exiting = 0; if (!exiting) { exiting = 1; l2tp_log(LOG_INFO, "Exiting"); exit(1); } else { _exit(1); } }
static int route_ctrl(int ctrl, struct rtentry *rt) { int s; /* Open a raw socket to the kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || ioctl(s, ctrl, rt) < 0) l2tp_log (LOG_ERR, "route_ctrl: %s", strerror(errno)); else errno = 0; close(s); return errno; }
static int rva_sanity_failed(struct call *c, int size, int datalen) { if (likely((size >= 0) && (size <= MAX_VECTOR_SIZE))) return 0; l2tp_log(LOG_DEBUG, "%s: Random vector too %s (%d)\n", __func__, (size < 0)?"small":"large", size); wrong_length (c, "Random Vector", 6, datalen, 1); return -EINVAL; }
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; }
int getPtyMaster_ptmx(char *ttybuf, int ttybuflen) { int fd; char *tty; fd = open("/dev/ptmx", O_RDWR); if (fd == -1) { l2tp_log (LOG_WARNING, "%s: unable to open /dev/ptmx to allocate pty\n", __FUNCTION__); return -EINVAL; } grantpt(fd); /* No need to call grantpt */ if (unlockpt(fd)) { l2tp_log (LOG_WARNING, "%s: unable to unlockpt() on pty\n", __FUNCTION__); close(fd); return -EINVAL; } tty = ptsname(fd); if (tty == NULL) { l2tp_log (LOG_WARNING, "%s: unable to obtain name of slave tty\n", __FUNCTION__); close(fd); return -EINVAL; } ttybuf[0]='\0'; strncat(ttybuf, tty, ttybuflen); l2tp_log (LOG_WARNING, "%s: name of slave tty is %s\n", __FUNCTION__, ttybuf); return fd; }