commit 747122e19c212e0a1d51d100ea8e254c4eff4eaa Author: Eliezer Croitoru Date: Sat Jun 22 23:37:24 2024 +0300 1 diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..785d3ef --- /dev/null +++ b/.htaccess @@ -0,0 +1,2 @@ +Options +ExecCGI +AddHandler cgi-script .rb diff --git a/generate_ipsec_config.php b/generate_ipsec_config.php new file mode 100644 index 0000000..a065103 --- /dev/null +++ b/generate_ipsec_config.php @@ -0,0 +1,88 @@ += 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; +} +?> diff --git a/generate_ipsec_config.rb b/generate_ipsec_config.rb new file mode 100755 index 0000000..d409a3f --- /dev/null +++ b/generate_ipsec_config.rb @@ -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 diff --git a/index.html b/index.html new file mode 100644 index 0000000..a9b55d6 --- /dev/null +++ b/index.html @@ -0,0 +1,117 @@ + + + + + + MikroTik IPsec Configuration + + + +
+

MikroTik IPsec Configuration

+
+
+ Phase 1 + + +

+ + +

+ + +

+ + +

+ + +

+ + +

+ + +

+ + +

+ + +

+ + +

+
+ +
+ Phase 2 + +

+ + +

+ + +

+ + +

+ + +

+ + +

+ +

+
+ + +
+
+ + diff --git a/style.css b/style.css new file mode 100644 index 0000000..61e69a1 --- /dev/null +++ b/style.css @@ -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; + } diff --git a/test-1.sh b/test-1.sh new file mode 100755 index 0000000..a0c7015 --- /dev/null +++ b/test-1.sh @@ -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'