#!/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" puts "Content-Type: text/plain" puts puts config