static int route_adddel(struct main_server_st* s, proc_st *proc, const char* pattern, const char* route, const char* dev) { int ret; char *cmd = NULL; if (pattern == 0) { mslog(s, NULL, LOG_WARNING, "route-add-cmd or route-del-cmd are not set."); return 0; } ret = replace_cmd(s, proc, &cmd, pattern, route, dev); if (ret < 0) return ret; ret = call_script(s, proc, cmd); if (ret < 0) { int e = errno; mslog(s, NULL, LOG_INFO, "failed to spawn cmd: %s: %s", cmd, strerror(e)); ret = ERR_EXEC; goto fail; } ret = 0; fail: talloc_free(cmd); return ret; }
int get_ip_leases(main_server_st* s, struct proc_st* proc) { int ret; char buf[128]; if (proc->ipv4 == NULL) { ret = get_ipv4_lease(s, proc); if (ret < 0) return ret; if (proc->ipv4) { if (htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4) == 0) { mslog(s, proc, LOG_ERR, "could not add IPv4 lease to hash table."); return -1; } } } if (proc->ipv6 == NULL) { ret = get_ipv6_lease(s, proc); if (ret < 0) return ret; if (proc->ipv6) { if (htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6) == 0) { mslog(s, proc, LOG_ERR, "could not add IPv6 lease to hash table."); return -1; } } } if (proc->ipv4 == 0 && proc->ipv6 == 0) { mslog(s, proc, LOG_ERR, "no IPv4 or IPv6 addresses are configured. Cannot obtain lease."); return -1; } if (proc->ipv4) mslog(s, proc, LOG_INFO, "assigned IPv4 to '%s': %s", proc->username, human_addr((void*)&proc->ipv4->rip, proc->ipv4->rip_len, buf, sizeof(buf))); if (proc->ipv6) mslog(s, proc, LOG_INFO, "assigned IPv6 to '%s': %s", proc->username, human_addr((void*)&proc->ipv6->rip, proc->ipv6->rip_len, buf, sizeof(buf))); return 0; }
int handle_resume_store_req(main_server_st * s, struct proc_st *proc, const SessionResumeStoreReqMsg * req) { tls_cache_st *cache; size_t key; unsigned int max; if (req->session_id.len > GNUTLS_MAX_SESSION_ID) return -1; if (req->session_data.len > MAX_SESSION_DATA_SIZE) return -1; max = MAX(2 * s->config->max_clients, DEFAULT_MAX_CACHED_TLS_SESSIONS); if (s->tls_db.entries >= max) { mslog(s, NULL, LOG_INFO, "maximum number of stored TLS sessions reached (%u)", max); need_maintenance = 1; return -1; } key = hash_any(req->session_id.data, req->session_id.len, 0); cache = talloc(s->tls_db.ht, tls_cache_st); if (cache == NULL) return -1; cache->session_id_size = req->session_id.len; cache->session_data_size = req->session_data.len; cache->remote_addr_len = proc->remote_addr_len; memcpy(cache->session_id, req->session_id.data, req->session_id.len); memcpy(cache->session_data, req->session_data.data, req->session_data.len); memcpy(&cache->remote_addr, &proc->remote_addr, proc->remote_addr_len); htable_add(s->tls_db.ht, key, cache); s->tls_db.entries++; mslog_hex(s, proc, LOG_DEBUG, "TLS session DB storing", req->session_id.data, req->session_id.len, 0); return 0; }
static int call_script(main_server_st *s, proc_st *proc, const char *cmd) { pid_t pid; int ret, status = 0; if (cmd == NULL) return 0; pid = fork(); if (pid == 0) { sigprocmask(SIG_SETMASK, &sig_default_set, NULL); mslog(s, proc, LOG_DEBUG, "executing route script %s", cmd); ret = execl("/bin/sh", "sh", "-c", cmd, NULL); if (ret == -1) { mslog(s, proc, LOG_ERR, "Could not execute route script %s", cmd); exit(1); } exit(77); } else if (pid == -1) { mslog(s, proc, LOG_ERR, "Could not fork()"); return ERR_EXEC; } ret = waitpid(pid, &status, 0); if (ret == -1) { mslog(s, proc, LOG_ERR, "Could not waitpid()"); return ERR_EXEC; } if (!WIFEXITED(status)) { mslog(s, proc, LOG_INFO, "cmd: %s: exited abnormally", cmd); return ERR_EXEC; } if (WEXITSTATUS(status)) { mslog(s, proc, LOG_INFO, "cmd: %s: exited with error %d", cmd, WEXITSTATUS(ret)); return ERR_EXEC; } return 0; }
static int call_script(main_server_st *s, struct proc_st* proc, unsigned up) { pid_t pid; int ret; const char* script; if (up != 0) script = s->config->connect_script; else script = s->config->disconnect_script; if (script == NULL) return 0; pid = fork(); if (pid == 0) { char real[64]; char local[64]; char remote[64]; if (proc->ipv4 == NULL && proc->ipv6 == NULL) exit(1); if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0) exit(1); if (proc->ipv4 && proc->ipv4->lip_len > 0) { if (getnameinfo((void*)&proc->ipv4->lip, proc->ipv4->lip_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) exit(1); } else { if (getnameinfo((void*)&proc->ipv6->lip, proc->ipv6->lip_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) exit(1); } if (proc->ipv4 && proc->ipv4->rip_len > 0) { if (getnameinfo((void*)&proc->ipv4->rip, proc->ipv4->rip_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) exit(1); } else { if (getnameinfo((void*)&proc->ipv6->rip, proc->ipv6->rip_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) exit(1); } setenv("USERNAME", proc->username, 1); setenv("GROUPNAME", proc->groupname, 1); setenv("HOSTNAME", proc->hostname, 1); setenv("DEVICE", proc->tun_lease.name, 1); setenv("IP_REAL", real, 1); setenv("IP_LOCAL", local, 1); setenv("IP_REMOTE", remote, 1); if (up) setenv("REASON", "connect", 1); else setenv("REASON", "disconnect", 1); mslog(s, proc, LOG_DEBUG, "executing script %s", script); ret = execl(script, script, NULL); if (ret == -1) { mslog(s, proc, LOG_ERR, "Could not execute script %s", script); exit(1); } exit(77); } else if (pid == -1) { mslog(s, proc, LOG_ERR, "Could not fork()"); return -1; } if (up) { add_to_script_list(s, pid, up, proc); return ERR_WAIT_FOR_SCRIPT; } else { return 0; } }
static int get_ipv6_lease(main_server_st* s, struct proc_st* proc) { struct sockaddr_storage tmp, mask, network, rnd; unsigned i, max_loops = MAX_IP_TRIES; int ret; const char* c_network, *c_netmask; char buf[64]; if (proc->config.ipv6_network && proc->config.ipv6_netmask) { c_network = proc->config.ipv6_network; c_netmask = proc->config.ipv6_netmask; } else { c_network = s->config->network.ipv6; c_netmask = s->config->network.ipv6_netmask; } if (c_network && c_netmask) { ret = inet_pton(AF_INET6, c_network, SA_IN6_P(&network)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); return -1; } ret = inet_pton(AF_INET6, c_netmask, SA_IN6_P(&mask)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); return -1; } proc->ipv6 = calloc(1, sizeof(*proc->ipv6)); if (proc->ipv6 == NULL) return ERR_MEM; /* mask the network */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]); ((struct sockaddr_in6*)&network)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&network)->sin6_port = 0; memcpy(&tmp, &network, sizeof(tmp)); ((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&tmp)->sin6_port = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_port = AF_INET6; do { if (max_loops == 0) { mslog(s, NULL, LOG_ERR, "could not figure out a valid IPv6 IP."); ret = ERR_NO_IP; goto fail; } if (max_loops == MAX_IP_TRIES) { uint32_t t = hash_any(proc->username, strlen(proc->username), 0); memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr)); memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, &t, 4); } else gnutls_rnd(GNUTLS_RND_NONCE, SA_IN6_U8_P(&rnd), sizeof(struct in6_addr)); max_loops--; /* Mask the random number with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] &= ~(SA_IN6_U8_P(&mask)[i]); SA_IN6_U8_P(&rnd)[sizeof(struct in6_addr)-1] &= 0xFE; /* Now add the network to the masked random number */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] |= (SA_IN6_U8_P(&network)[i]); /* check if it exists in the hash table */ if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign local IP %s to '%s'; it is in use.", human_addr((void*)&rnd, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->lip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len); /* RIP = LIP + 1 */ memcpy(&tmp, &proc->ipv6->lip, proc->ipv6->rip_len); bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1); /* check if it exists in the hash table */ if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s to '%s'; it is in use.", human_addr((void*)&tmp, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->rip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len); /* mask the last IP with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]); /* the result should match the network */ if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) { continue; } mslog(s, proc, LOG_DEBUG, "selected IP for '%s': %s", proc->username, human_addr((void*)&proc->ipv6->lip, proc->ipv6->lip_len, buf, sizeof(buf))); if (icmp_ping6(s, (void*)&proc->ipv6->lip, (void*)&proc->ipv6->rip) == 0) break; } while(1); } return 0; fail: free(proc->ipv6); proc->ipv6 = NULL; return ret; }
static int get_ipv4_lease(main_server_st* s, struct proc_st* proc) { struct sockaddr_storage tmp, mask, network, rnd; unsigned i; unsigned max_loops = MAX_IP_TRIES; int ret; const char* c_network, *c_netmask; char buf[64]; /* Our IP accounting */ if (proc->config.ipv4_network && proc->config.ipv4_netmask) { c_network = proc->config.ipv4_network; c_netmask = proc->config.ipv4_netmask; } else { c_network = s->config->network.ipv4; c_netmask = s->config->network.ipv4_netmask; } if (c_network == NULL || c_netmask == NULL) { mslog(s, NULL, LOG_DEBUG, "there is no IPv4 network assigned"); return 0; } ret = inet_pton(AF_INET, c_network, SA_IN_P(&network)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); return -1; } ret = inet_pton(AF_INET, c_netmask, SA_IN_P(&mask)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); return -1; } /* mask the network (just in case it is wrong) */ for (i=0;i<sizeof(struct in_addr);i++) SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]); ((struct sockaddr_in*)&network)->sin_family = AF_INET; ((struct sockaddr_in*)&network)->sin_port = 0; if (proc->config.explicit_ipv4) { /* if an explicit IP is given for that client, then * do implicit IP accounting. Require the address * to be odd, so we use the next even address as PtP. */ ret = inet_pton(AF_INET, proc->config.explicit_ipv4, SA_IN_P(&tmp)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv4); return -1; } proc->ipv4 = talloc_zero(proc, struct ip_lease_st); if (proc->ipv4 == NULL) return ERR_MEM; ((struct sockaddr_in*)&tmp)->sin_family = AF_INET; ((struct sockaddr_in*)&tmp)->sin_port = 0; memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in)); proc->ipv4->rip_len = sizeof(struct sockaddr_in); if (is_ipv4_ok(s, &proc->ipv4->rip, &network, &mask) == 0) { mslog(s, proc, LOG_DEBUG, "cannot assign explicit IP %s; it is in use or invalid", human_addr((void*)&tmp, sizeof(struct sockaddr_in), buf, sizeof(buf))); ret = ERR_NO_IP; goto fail; } /* LIP = network address + 1 */ memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in)); proc->ipv4->lip_len = sizeof(struct sockaddr_in); SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1; if (ip_cmp(&proc->ipv4->lip, &proc->ipv4->rip) == 0) { mslog(s, NULL, LOG_ERR, "cannot assign explicit IP %s; network: %s", proc->config.explicit_ipv4, c_network); ret = ERR_NO_IP; goto fail; } return 0; }