123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- require 'yaml'
- def sanitize_string str
- return str.dump[1...-1]
- end
- def ansible_encrypt to_encrypt
- res = `echo -n #{to_encrypt} | ansible-vault encrypt_string --vault-password-file=#{$vault_file}`
- if res =~ /(!vault \|[A-Za-z_;.0-9\n\s$]*)$/
- return $1
- else
- raise 'Failed to encrypt'
- end
- end
- if ARGV[0]
- $vault_file = ARGV[0].dup.strip.freeze
- else
- raise "No vault file given"
- end
- puts "Vault file is #{sanitize_string $vault_file}."
- module WGConfParser
- class ParserError < RuntimeError; end;
- # Not suitable for multi-threading!!!
- # Not suitable for wireguard configurations with more than one peer
- def self.load cnt
- current_section = nil
- comment = ''
- res = {}
- cnt.each_line do |line|
- line.strip!
- if line =~ /^\[(\S+)\]$/
- raise ParserError, "Section #{current_section} doubled" if res.has_key? $1
- current_section = $1
- res[current_section] = {}
- elsif line =~ /^#.*$/
- comment += "#{$1}\n"
- elsif line =~ /^(.+?)\s*=\s*(.+?)$/
- raise ParserError, 'Key-Value-Pair outside a section' if current_section == nil
- if ! res[current_section][$1]
- res[current_section][$1] = []
- end
- res[current_section][$1] << $2
- elsif line.empty?
- # ignore line
- else
- puts "Unknown statement: #{line}"
- end
- end
- return res, comment
- end
- end
- configurations = []
- Dir['wireguard/*.conf'].each do |file|
- begin
- puts "Parsing #{sanitize_string file}"
- configurations << [file, WGConfParser.load(File.read file)]
- rescue WGConfParser::ParserError => e
- puts "Failed to parse file #{sanitize_string file}: #{sanitize_string e.message}"
- exit!
- end
- end
- new_configuration = []
- autostart_wg = File.read 'systemd'
- configurations.each do |conf_pair|
- file = conf_pair[0]
- conf = conf_pair[1][0]
- comment = conf_pair[1][1].strip
- puts "Processing #{sanitize_string file}"
- raise 'Configuration has no Interface section' if ! conf.has_key? 'Interface'
- raise 'Configuration has no Peer section' if ! conf.has_key? 'Peer'
- raise 'Configuration has more than two sections' if conf.keys.length > 2
- raise 'Unknown key in Interface section' if ! (conf['Interface'].keys - ['ListenPort', 'PrivateKey', 'PostUp', 'Table', 'Address']).empty?
- raise 'Unknown key in Peer section' if ! (conf['Peer'].keys - ['Endpoint', 'PublicKey', 'PresharedKey', 'AllowedIPs', 'PersistentKeepalive']).empty?
- res = {}
- res['name'] = File.basename(file).delete_suffix('.conf')
- res['autostart'] = autostart_wg.include? res['name']
- res["listen_port"] = conf['Interface']['ListenPort'][0].to_i
- raise 'Unknown listen port' if conf['Interface']['ListenPort'][0] != res["listen_port"].to_s
- res["privkey"] = ansible_encrypt conf['Interface']['PrivateKey'][0]
- res['addresses'] = []
- if conf['Interface']['PostUp']
- conf['Interface']['PostUp'].each do |postup|
- if postup =~ /^(?:\/sbin\/)?ip addr add dev %i ([a-f0-9.:\/]+) peer ([a-f0-9.:\/]+)$/
- inner_res = {}
- inner_res['local'] = $1
- inner_res['remote'] = $2
- res['addresses'] << inner_res
- else
- raise "Unknown PostUp statment"
- end
- end
- end
- res["table"] = true
- if conf['Interface']['Table']
- case conf['Interface']['Table'][0]
- when 'on'
- res["table"] = true
- when 'off'
- res["table"] = false
- else
- raise 'Unknown table value'
- end
- end
- if conf['Interface']['Address']
- conf['Interface']['Address'].each do |addr|
- res["addresses"] << {'local' => addr}
- end
- end
- res["peers"] = []
- peer = {}
- peer['endpoint'] = conf['Peer']['Endpoint'][0] if conf['Peer']['Endpoint']
- peer['pubkey'] = conf['Peer']['PublicKey'][0]
- peer['psk'] = ansible_encrypt conf['Peer']['PresharedKey'][0] if conf['Peer']['PresharedKey']
- peer['allowed_ips'] = conf['Peer']['AllowedIPs'][0].split ','
- peer['keepalive'] = conf['Peer']['PersistentKeepalive'][0] if conf['Peer']['PersistentKeepalive']
- res["peers"] << peer
- res["comment"] = comment if ! comment.empty?
- new_configuration << res
- end
- cnt = YAML.dump({'wireguard' => new_configuration})
- # Necessary, because the Ruby YAML module decodes
- # the vault string as a "normal" string
- cnt.gsub! "|-\n !vault |", '!vault |'
- cnt.gsub! "|-\n !vault |", '!vault |'
- File.write 'wireguard.yml', cnt
|