summaryrefslogtreecommitdiff
path: root/wireguardmeshgenerator.rb
blob: 95f7b70a6125e4faa47816dda1d575b4145afacb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/usr/bin/env ruby

require 'yaml'
require 'fileutils'

# Generates Wireguard keys and config files for each host
class KeyTool
  def initialize(myself)
    raise 'Wireguard tool not found' unless system('which wg > /dev/null 2>&1')

    keys_dir = "keys/#{myself}/"
    FileUtils.mkdir_p(keys_dir) unless Dir.exist?(keys_dir)

    @pubkey_path = "#{keys_dir}/pubkey"
    @privkey_path = "#{keys_dir}/privkey"
    @preshared_path = "#{keys_dir}/preshared"

    generate! if !File.exist?(@pubkey_path) ||
                 !File.exist?(@privkey_path) ||
                 !File.exist?(@preshared_path)
  end

  def pub = File.read(@pubkey_path).strip
  def priv = File.read(@privkey_path).strip
  def preshared = File.read(@preshared_path).strip

  private

  def generate! = gen_privpub! && genpsk!
  def genpsk! = File.write(@preshared_path, `wg genpsk`)

  def gen_privpub!
    privkey = IO.popen('wg genkey', 'r+', &:read)
    IO.popen('wg pubkey', 'r+') do |io|
      io.puts(privkey)
      io.close_write
      File.write(@privkey_path, privkey)
      File.write(@pubkey_path, io.read)
    end
  end
end

PeerSnippet = Struct.new(:myself, :domain, :allowed_ips, :endpoint) do
  def to_s
    keytool = KeyTool.new(myself)

    <<~PEER_CONFIG
      [Peer]
      # #{myself}.#{domain}
      PublicKey = #{keytool.pub}
      PresharedKey = #{keytool.preshared}
      Endpoint = #{endpoint}:56709
      AllowedIPs = #{allowed_ips}/32
    PEER_CONFIG
  end
end

WireguardConfig = Struct.new(:myself, :hosts) do
  def to_s
    keytool = KeyTool.new(myself)

    <<~CONFIG
      [Interface]
      # #{myself}.#{hosts[myself]['wg0']['domain']}
      Address = #{hosts[myself]['wg0']['ip']}
      PrivateKey = #{keytool.priv}
      PresharedKey = #{keytool.preshared}
      ListenPort = 56709

      #{peer_snippets}
    CONFIG
  end

  def generate!
    dist_dir = "dist/#{myself}/etc/wireguard"
    FileUtils.mkdir_p(dist_dir) unless Dir.exist?(dist_dir)
    File.write("#{dist_dir}/wg0.conf", to_s)
  end

  private

  def peer_snippets
    hosts.reject { _1 == myself }.map do |hostname, data|
      PeerSnippet.new(hostname, data['wg0']['domain'],
                      data['wg0']['ip'], data['lan']['ip'])
    end.map(&:to_s).join("\n")
  end
end

CONFIG = YAML.load_file('wireguardmeshgenerator.yaml').freeze
CONFIG['hosts'].each_key do |hostname|
  WireguardConfig.new(hostname, CONFIG['hosts']).generate!
end