/** * Disconnect all clients with this CN from all pools and instances * managed by this service. * * @param string $commonName the CN to kill */ public function kill($commonName) { $clientsKilled = 0; // loop over all pools foreach (array_keys($this->instanceConfig->v('vpnPools')) as $poolNumber => $poolId) { $poolConfig = new PoolConfig($this->instanceConfig->v('vpnPools', $poolId)); $managementIp = sprintf('127.42.%d.%d', 100 + $this->instanceConfig->v('instanceNumber'), 100 + $poolNumber); // loop over all processes for ($i = 0; $i < $poolConfig->v('processCount'); ++$i) { // add all kills from this instance to poolKills try { // open the socket connection $this->managementSocket->open(sprintf('tcp://%s:%d', $managementIp, 11940 + $i)); $response = $this->managementSocket->command(sprintf('kill %s', $commonName)); if (0 === mb_strpos($response[0], 'SUCCESS: ')) { ++$clientsKilled; } // close the socket connection $this->managementSocket->close(); } catch (ManagementSocketException $e) { // we log the error, but continue with the next instance $this->logger->error(sprintf('error with socket "%s:%s", message: "%s"', $managementIp, 11940 + $i, $e->getMessage())); } } } return 0 !== $clientsKilled; }
public function init(Service $service) { $service->get('/server_pools', function (Request $request, array $hookData) { Utils::requireUser($hookData, ['vpn-admin-portal', 'vpn-user-portal']); $responseData = []; foreach (array_keys($this->instanceConfig->v('vpnPools')) as $poolId) { $poolConfig = new PoolConfig($this->instanceConfig->v('vpnPools', $poolId)); $responseData[$poolId] = $poolConfig->v(); } return new ApiResponse('server_pools', $responseData); }); $service->get('/server_pool', function (Request $request, array $hookData) { Utils::requireUser($hookData, ['vpn-admin-portal', 'vpn-user-portal']); $poolId = $request->getQueryParameter('pool_id'); InputValidation::poolId($poolId); $poolConfig = new PoolConfig($this->instanceConfig->v('vpnPools', $poolId)); return new ApiResponse('server_pool', $poolConfig->v()); }); }
public function connect(array $envData) { $userId = self::getUserId($envData['common_name']); $dataDir = sprintf('%s/data/%s', $this->baseDir, $envData['INSTANCE_ID']); // is the user account disabled? // XXX we have to be careful, if the directory is not readable by the // openvpn user, it is assumed the user is not disabled! We have to // find a more robust solution for this! $disabledUsersDir = sprintf('%s/users/disabled', $dataDir); if (@file_exists(sprintf('%s/%s', $disabledUsersDir, $userId))) { throw new ConnectionException('client not allowed, user is disabled'); } // is the common name disabled? // XXX we have to be careful, if the directory is not readable by the // openvpn user, it is assumed the user is not disabled! We have to // find a more robust solution for this! $disabledCommonNamesDir = sprintf('%s/common_names/disabled', $dataDir); if (@file_exists(sprintf('%s/%s', $disabledCommonNamesDir, $envData['common_name']))) { throw new ConnectionException('client not allowed, CN is disabled'); } $configDir = sprintf('%s/config/%s', $this->baseDir, $envData['INSTANCE_ID']); // read the instance/pool configuration $instanceConfig = InstanceConfig::fromFile(sprintf('%s/config.yaml', $configDir)); // is the ACL enabled? $poolId = $envData['POOL_ID']; $poolConfig = new PoolConfig($instanceConfig->v('vpnPools', $poolId)); if ($poolConfig->v('enableAcl')) { $aclGroupProvider = $poolConfig->v('aclGroupProvider'); $groupProviderClass = sprintf('SURFnet\\VPN\\Server\\GroupProvider\\%s', $aclGroupProvider); $groupProvider = new $groupProviderClass($dataDir, $instanceConfig); $aclGroupList = $poolConfig->v('aclGroupList'); if (false === self::isMember($groupProvider->getGroups($userId), $aclGroupList)) { throw new ConnectionException(sprintf('client not allowed, not a member of "%s"', implode(',', $aclGroupList))); } } }
* * IPv6: * The IPv6 address is generated according to RFC 4193 (Global ID), it results * in a /60 network. */ try { $p = new CliParser('Automatically generate an IP address and basic config for a pool', ['instance' => ['the instance to target, e.g. vpn.example', true, true], 'pool' => ['the pool to target, e.g. internet', true, true], 'host' => ['the hostname clients connect to', true, true], 'ext' => ['the external interface, e.g. eth0', true, true]]); $opt = $p->parse($argv); if ($opt->e('help')) { echo $p->help(); exit(0); } $v4 = sprintf('10.%s.%s.0/24', hexdec(bin2hex(random_bytes(1))), hexdec(bin2hex(random_bytes(1)))); $v6 = sprintf('fd%s:%s:%s:%s::/60', bin2hex(random_bytes(1)), bin2hex(random_bytes(2)), bin2hex(random_bytes(2)), bin2hex(random_bytes(2) & hex2bin('fff0'))); echo sprintf('IPv4 CIDR : %s', $v4) . PHP_EOL; echo sprintf('IPv6 prefix: %s', $v6) . PHP_EOL; $configFile = sprintf('%s/config/%s/config.yaml', dirname(__DIR__), $opt->v('instance')); $instanceConfig = InstanceConfig::fromFile($configFile); $poolConfig = new PoolConfig($instanceConfig->v('vpnPools', $opt->v('pool'))); $instanceConfigData = $instanceConfig->v(); $poolConfigData = $poolConfig->v(); $poolConfigData['range'] = $v4; $poolConfigData['range6'] = $v6; $poolConfigData['hostName'] = $opt->v('host'); $poolConfigData['extIf'] = $opt->v('ext'); $instanceConfigData['vpnPools'][$opt->v('pool')] = $poolConfigData; InstanceConfig::toFile($configFile, $instanceConfigData); } catch (Exception $e) { echo sprintf('ERROR: %s', $e->getMessage()) . PHP_EOL; exit(1); }
private static function getClientToClient(PoolConfig $poolConfig) { if (!$poolConfig->v('clientToClient')) { return []; } $rangeIp = new IP($poolConfig->v('range')); $range6Ip = new IP($poolConfig->v('range6')); return ['client-to-client', sprintf('push "route %s %s"', $rangeIp->getAddress(), $rangeIp->getNetmask()), sprintf('push "route-ipv6 %s"', $range6Ip->getAddressPrefix())]; }
private static function getForwardFirewall($instanceNumber, $poolNumber, PoolConfig $poolConfig, $inetFamily) { $forwardFirewall = []; if ($poolConfig->v('blockSmb')) { // drop SMB outgoing traffic // @see https://medium.com/@ValdikSS/deanonymizing-windows-users-and-capturing-microsoft-and-vpn-accounts-f7e53fe73834 foreach (['tcp', 'udp'] as $proto) { $forwardFirewall[] = sprintf('-A vpn-%s-%s -o %s -m multiport -p %s --dports 137:139,445 -j REJECT --reject-with %s', $instanceNumber, $poolNumber, $poolConfig->v('extIf'), $proto, 4 === $inetFamily ? 'icmp-host-prohibited' : 'icmp6-adm-prohibited'); } } return $forwardFirewall; }