This commit is contained in:
Eliezer Croitoru 2024-06-22 23:37:24 +03:00
commit 747122e19c
6 changed files with 403 additions and 0 deletions

2
.htaccess Normal file
View File

@ -0,0 +1,2 @@
Options +ExecCGI
AddHandler cgi-script .rb

88
generate_ipsec_config.php Normal file
View File

@ -0,0 +1,88 @@
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// Function to validate IP address
function isValidIpAddress($ip) {
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false;
}
// Function to validate CIDR notation
function isValidCidr($cidr) {
$parts = explode('/', $cidr);
if (count($parts) !== 2) {
return false; // Invalid format
}
$ip = $parts[0];
$netmask = $parts[1];
return isValidIpAddress($ip) && ($netmask >= 0 && $netmask <= 32);
}
// Phase 1 data (with validation)
$errors = [];
$phase1ProfileName = $_POST["phase1_profile_name"];
if (empty($phase1ProfileName)) { $errors[] = "Phase 1 profile name is required."; }
$remoteGateway = $_POST["phase1_remote_gateway"];
if (!isValidIpAddress($remoteGateway)) { $errors[] = "Invalid remote gateway IP address."; }
$localAddress = $_POST["phase1_local_address"];
if (!empty($localAddress) && !isValidIpAddress($localAddress)) { // Check only if not empty
$errors[] = "Invalid local address (must be a single IP).";
}
$ikeVersion = $_POST["phase1_ike_version"];
$authMethod = $_POST["phase1_auth_method"];
$preSharedKey = $authMethod === 'psk' ? $_POST["phase1_pre_shared_key"] : null;
if ($authMethod === 'psk' && empty($preSharedKey)) { $errors[] = "Pre-shared key is required for PSK authentication."; }
$encryptionAlgorithms = implode(",", $_POST["phase1_encryption_algorithm"]);
$hashAlgorithms = implode(",", $_POST["phase1_hash_algorithm"]);
$dhGroup = $_POST["phase1_dh_group"]; // Single DH group for Phase 1
$dhGroupText = implode(",", $_POST["phase1_dh_group"]);
$phase1Lifetime = $_POST["phase1_lifetime"];
$remoteId = $_POST["phase1_remote_id"];
// Phase 2 data (with validation)
$phase2ProfileName = $_POST["phase2_profile_name"];
if (empty($phase2ProfileName)) { $errors[] = "Phase 2 profile name is required."; }
$phase2EncryptionAlgorithms = implode(",", $_POST["phase2_encryption_algorithm"]);
$phase2HashAlgorithms = implode(",", $_POST["phase2_hash_algorithm"]);
$pfsGroup = $_POST["phase2_pfs_group"]; // Single PFS group for Phase 2
$phase2Lifetime = $_POST["phase2_lifetime"];
$phase2LocalAddress = $_POST["phase2_local_address"];
# if (!isValidCidr($phase2LocalAddress)) { $errors[] = "Invalid phase 2 local address or subnet."; }
$remoteAddress = $_POST["phase2_remote_address"];
# if (!isValidCidr($remoteAddress)) { $errors[] = "Invalid phase 2 remote address or subnet."; }
// Handle errors
if (!empty($errors)) {
header('Content-Type: text/plain');
echo "Errors:\n" . implode("\n", $errors); // Output errors as plain text
exit;
}
// Generate MikroTik CLI configuration commands
$config = "";
// Phase 1
$config .= "/ip ipsec profile\nadd name=\"$phase1ProfileName\" dh-group=\"$dhGroupText\" enc-algorithm=\"$encryptionAlgorithms\" hash-algorithm=\"$hashAlgorithms\" nat-traversal=no\n\n";
$config .= "/ip ipsec peer\nadd address=$remoteGateway";
if (!empty($localAddress) && isValidIpAddress($localAddress)) {
$config .= " local-address=$localAddress";
}
$config .= " disabled=yes name=$phase1ProfileName passive=yes profile=$phase1ProfileName\n\n";
// Move pre-shared key to /ip ipsec identity
$config .= "/ip ipsec identity\nadd peer=$phase1ProfileName secret=\"$preSharedKey\"\n\n";
// Phase 2
$config .= "/ip ipsec proposal\nadd name=\"$phase2ProfileName\" auth-algorithms=\"$phase2HashAlgorithms\" enc-algorithms=\"$phase2EncryptionAlgorithms\" pfs-group=$pfsGroup\n\n";
$config .= "/ip ipsec policy\nadd disabled=yes dst-address=$remoteAddress peer=$phase1ProfileName proposal=$phase2ProfileName src-address=$phase2LocalAddress tunnel=yes\n\n";
// Output configuration as plain text without download
header('Content-Type: text/plain');
echo $config;
}
?>

90
generate_ipsec_config.rb Executable file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env ruby
require 'cgi'
require 'ipaddr' # Load the IPAddr library
cgi = CGI.new
params = cgi.params
errors = []
# Phase 1 data (with validation)
phase1_profile_name = params['phase1_profile_name'][0]
errors << "Phase 1 profile name is required." if phase1_profile_name.nil? || phase1_profile_name.empty?
remote_gateway = params['phase1_remote_gateway'][0]
begin
IPAddr.new(remote_gateway)
rescue IPAddr::InvalidAddressError
errors << "Invalid remote gateway IP address."
end
local_address = params['phase1_local_address'][0] || '' # Optional
if !local_address.empty?
begin
IPAddr.new(local_address) # Check if it's a valid IP address
errors << "Invalid local address (must be a single IP)." if IPAddr.new(local_address).prefix != 32
rescue IPAddr::InvalidAddressError
errors << "Invalid local address."
end
end
ike_version = params['phase1_ike_version'][0]
auth_method = params['phase1_auth_method'][0]
pre_shared_key = (auth_method == 'psk') ? params['phase1_pre_shared_key'][0] : nil
errors << "Pre-shared key is required for PSK authentication." if auth_method == 'psk' && (pre_shared_key.nil? || pre_shared_key.empty?)
encryption_algorithms = params['phase1_encryption_algorithm'] || []
hash_algorithms = params['phase1_hash_algorithm'] || []
dh_group = params['phase1_dh_group'][0]
phase1_lifetime = params['phase1_lifetime'][0]
remote_id = params['phase1_remote_id'][0] || '' # Optional
# Phase 2 data (with validation)
phase2_profile_name = params['phase2_profile_name'][0]
errors << "Phase 2 profile name is required." if phase2_profile_name.nil? || phase2_profile_name.empty?
phase2_encryption_algorithms = params['phase2_encryption_algorithm'] || []
phase2_hash_algorithms = params['phase2_hash_algorithm'] || []
pfs_group = params['phase2_pfs_group'][0] || ''
phase2_lifetime = params['phase2_lifetime'][0]
phase2_local_address = params['phase2_local_address'][0]
begin
IPAddr.new(phase2_local_address) # Check if it's a valid IP address or CIDR
rescue IPAddr::InvalidAddressError
errors << "Invalid phase 2 local address or subnet."
end
remote_address = params['phase2_remote_address'][0]
begin
IPAddr.new(remote_address) # Check if it's a valid IP address or CIDR
rescue IPAddr::InvalidAddressError
errors << "Invalid phase 2 remote address or subnet."
end
# Handle errors
if errors.any?
cgi.header('type' => 'text/plain')
puts "Errors:\n#{errors.join("\n")}"
exit
end
# Generate MikroTik CLI configuration commands
config = ""
# Phase 1
config << "/ip ipsec profile\nadd name=\"#{phase1_profile_name}\" dh-group=#{dh_group} enc-algorithm=\"#{encryption_algorithms.join(',')}\" hash-algorithm=\"#{hash_algorithms.join(',')}\" nat-traversal=no\n\n"
config << "/ip ipsec peer\nadd address=#{remote_gateway} "
config << "local-address=#{local_address} " unless local_address.empty?
config << "disabled=yes name=#{phase1_profile_name} passive=yes profile=#{phase1_profile_name}\n\n"
# Move pre-shared key to /ip ipsec identity
config << "/ip ipsec identity\nadd peer=#{phase1_profile_name} secret=\"#{pre_shared_key}\"\n\n"
# Phase 2
config << "/ip ipsec proposal\nadd name=\"#{phase2_profile_name}\" auth-algorithms=\"#{phase2_hash_algorithms.join(',')}\" enc-algorithms=\"#{phase2_encryption_algorithms.join(',')}\" pfs-group=#{pfs_group}\n\n"
config << "/ip ipsec policy\nadd disabled=yes dst-address=#{remote_address} peer=#{phase1_profile_name} proposal=#{phase2_profile_name} src-address=#{phase2_local_address} tunnel=yes\n\n"
# Output configuration as plain text without download
cgi.header('type' => 'text/plain')
puts
puts config

117
index.html Normal file
View File

@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MikroTik IPsec Configuration</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>MikroTik IPsec Configuration</h1>
<form action="generate_ipsec_config.rb" method="post" autocomplete="off">
<fieldset>
<legend>Phase 1</legend>
<label for="phase1-profile-name">Profile Name:</label>
<input type="text" id="phase1-profile-name" name="phase1_profile_name" autocomplete="new-password" required><br><br>
<label for="phase1-remote-gateway">Remote Gateway (IP Address):</label>
<input type="text" id="phase1-remote-gateway" name="phase1_remote_gateway" autocomplete="new-password" required><br><br>
<label for="phase1-local-address">Local Address (Single IP, optional):</label>
<input type="text" id="phase1-local-address" name="phase1_local_address" autocomplete="new-password"><br><br>
<label for="phase1-ike-version">IKE Version:</label>
<select id="phase1-ike-version" name="phase1_ike_version" autocomplete="new-password" required>
<option value="ike2" selected>IKEv2</option>
<option value="ike1">IKEv1</option>
</select><br><br>
<label for="phase1-auth-method">Authentication Method:</label>
<select id="phase1-auth-method" name="phase1_auth_method" autocomplete="new-password" required>
<option value="psk" selected>Pre-shared Key</option>
<option value="rsa">RSA Signatures</option>
</select><br><br>
<label for="phase1-pre-shared-key">Pre-shared Key:</label>
<input type="password" id="phase1-pre-shared-key" name="phase1_pre_shared_key" autocomplete="new-password" required><br><br>
<label for="phase1-encryption-algorithm">Encryption Algorithms (multiple allowed):</label>
<select id="phase1-encryption-algorithm" name="phase1_encryption_algorithm[]" multiple autocomplete="new-password" required>
<option value="aes-128" selected>AES-128</option>
<option value="aes-192">AES-192</option>
<option value="aes-256">AES-256</option>
</select><br><br>
<label for="phase1-hash-algorithm">Hash Algorithms (multiple allowed):</label>
<select id="phase1-hash-algorithm" name="phase1_hash_algorithm[]" multiple autocomplete="new-password" required>
<option value="sha1">SHA1</option>
<option value="sha256" selected>SHA256</option>
<option value="sha384">SHA384</option>
<option value="sha512">SHA512</option>
</select><br><br>
<label for="phase1-dh-group">DH Groups (multiple allowed):</label>
<select id="phase1-dh-group" name="phase1_dh_group[]" multiple autocomplete="new-password" required>
<option value="modp1024">Group 2</option>
<option value="modp1536" selected>Group 14</option>
<option value="modp2048" selected>Group 15</option>
<option value="modp3072">Group 16</option>
<option value="modp4096">Group 17</option>
<option value="modp6144">Group 18</option>
<option value="modp8192">Group 19</option>
</select><br><br>
<label for="phase1-remote-id">Remote ID (optional):</label>
<input type="text" id="phase1-remote-id" name="phase1_remote_id" autocomplete="new-password"><br><br>
</fieldset>
<fieldset>
<legend>Phase 2</legend>
<label for="phase2-profile-name">Profile Name:</label>
<input type="text" id="phase2-profile-name" name="phase2_profile_name" autocomplete="new-password" required><br><br>
<label for="phase2-local-address">Local Address (or Subnet):</label>
<input type="text" id="phase2-local-address" name="phase2_local_address" placeholder="e.g., 192.168.1.0/24" autocomplete="new-password" required><br><br>
<label for="phase2-remote-address">Remote Address (or Subnet):</label>
<input type="text" id="phase2-remote-address" name="phase2_remote_address" placeholder="e.g., 10.0.0.0/24" autocomplete="new-password" required><br><br>
<label for="phase2-encryption-algorithm">Encryption Algorithms (multiple allowed):</label>
<select id="phase2-encryption-algorithm" name="phase2_encryption_algorithm[]" multiple autocomplete="new-password" required>
<option value="aes-128-cbc" selected>aes-128-cbc</option>
<option value="aes-128-ctr" selected>aes-128-ctr</option>
<option value="aes-128-gcm" selected>aes-128-gcm</option>
<option value="aes-192-cbc" selected>aes-192-cbc</option>
<option value="aes-256-cbc" selected>aes-256-cbc</option>
<option value="aes-256-ctr" selected>aes-256-ctr</option>
<option value="aes-256-gcm" selected>aes-256-gcm</option>
</select><br><br>
<label for="phase2-hash-algorithm">Hash Algorithms (multiple allowed):</label>
<select id="phase2-hash-algorithm" name="phase2_hash_algorithm[]" multiple autocomplete="new-password" required>
<option value="sha1" selected>SHA1</option>
<option value="sha256" selected>SHA256</option>
<option value="sha384">SHA384</option>
<option value="sha512">SHA512</option>
</select><br><br>
<label for="phase2-pfs-group">PFS Group:</label>
<select id="phase2-pfs-group" name="phase2_pfs_group" autocomplete="new-password" required>
<option value="modp1536">Group 14</option>
<option value="modp2048" selected>Group 15</option>
<option value="modp3072">Group 16</option>
<option value="modp4096">Group 17</option>
<option value="modp6144">Group 18</option>
<option value="modp8192">Group 19</option>
</select><br><br>
<label for="phase2-lifetime">Lifetime (seconds):</label>
<input type="number" id="phase2-lifetime" name="phase2_lifetime" value="43200" min="1" autocomplete="new-password" required><br><br>
</fieldset>
<input type="submit" value="Generate Configuration">
</form>
</div>
</body>
</html>

94
style.css Normal file
View File

@ -0,0 +1,94 @@
/* Basic Styling */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; /* Modern, readable font */
margin: 0;
padding: 0;
background-color: #f4f4f4; /* Light background */
color: #333; /* Dark text for contrast */
}
.container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
margin-bottom: 20px;
}
fieldset {
border: 1px solid #ddd;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
}
legend {
font-weight: bold;
padding: 0 10px; /* Add some padding around the legend text */
}
label {
display: block;
margin-bottom: 5px;
font-weight: 600; /* Slightly bolder labels */
}
input[type="text"],
input[type="password"],
input[type="number"],
select {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
select {
height: 45px; /* Consistent height for selects */
}
input[type="submit"] {
background-color: #007bff; /* Blue button */
color: white;
padding: 12px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s; /* Smooth transition on hover */
}
input[type="submit"]:hover {
background-color: #0056b3; /* Darker blue on hover */
}
/* Responsive Styles */
@media (max-width: 768px) {
.container {
max-width: 95%;
}
input[type="text"],
input[type="password"],
input[type="number"],
select {
font-size: 16px;
}
}
@media (max-width: 480px) {
fieldset {
padding: 10px;
}
label {
font-size: 14px;
}

12
test-1.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
# 'https://www.ngtech.co.il/ipracticom/ipsec/2/generate_ipsec_config.rb'
URL="$1"
curl "${URL}" \
-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
-H 'content-type: application/x-www-form-urlencoded' \
-H 'origin: https://www.ngtech.co.il' \
-H 'priority: u=0, i' \
-H 'referer: https://www.ngtech.co.il/ipracticom/ipsec/2/' \
--data-raw 'phase1_profile_name=test2-p1&phase1_remote_gateway=1.1.1.1&phase1_local_address=&phase1_ike_version=ike2&phase1_auth_method=psk&phase1_pre_shared_key=Test123&phase1_encryption_algorithm%5B%5D=aes-128&phase1_hash_algorithm%5B%5D=sha256&phase1_dh_group%5B%5D=modp1536&phase1_dh_group%5B%5D=modp2048&phase1_remote_id=&phase2_profile_name=test2-ph2&phase2_local_address=192.168.0.0%2F24&phase2_remote_address=192.168.1.0%2F24&phase2_encryption_algorithm%5B%5D=aes-128-cbc&phase2_encryption_algorithm%5B%5D=aes-128-ctr&phase2_encryption_algorithm%5B%5D=aes-128-gcm&phase2_encryption_algorithm%5B%5D=aes-192-cbc&phase2_encryption_algorithm%5B%5D=aes-256-cbc&phase2_encryption_algorithm%5B%5D=aes-256-ctr&phase2_encryption_algorithm%5B%5D=aes-256-gcm&phase2_hash_algorithm%5B%5D=sha1&phase2_hash_algorithm%5B%5D=sha256&phase2_pfs_group=modp2048&phase2_lifetime=43200'