Skip to content

Commit 3507751

Browse files
authored
Corrections to IP address allocations for clients (#121)
1 parent 82852c0 commit 3507751

15 files changed

+243
-74
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ Example response:
109109
{
110110
"id": 15,
111111
"server_public_key": "server_public_key",
112-
"address": "10.8.0.16/24",
112+
"address": "10.8.0.16/29",
113113
"private_key": "private_key",
114114
"preshared_key": "preshared_key",
115115
"enable": true,
@@ -139,7 +139,7 @@ Example response:
139139
{
140140
"id": 15,
141141
"server_public_key": "server_public_key",
142-
"address": "10.8.0.16/24",
142+
"address": "10.8.0.16/29",
143143
"private_key": "private_key",
144144
"preshared_key": "preshared_key",
145145
"enable": true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frozen_string_literal: true
2+
3+
module Errors
4+
class ConnectionLimitExceededError < BaseError # rubocop:disable Style/Documentation
5+
def message
6+
'The server connection limit has been exceeded.'
7+
end
8+
end
9+
end

config/settings/test.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ wg_default_dns: '1.1.1.1'
88
wg_persistent_keepalive: 0
99
auth_token: '123-Ab'
1010
webhooks_url: 'https://test.webhooks.com/event'
11-
connecting_client_limit: '24'
11+
connecting_client_limit: '29'

lib/wire_guard/client_config_builder.rb

+39-11
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,67 @@
33
module WireGuard
44
# The class generates a config file for the client
55
class ClientConfigBuilder
6+
WG_DEFAULT_ADDRESS = IPAddr.new(Settings.wg_default_address.gsub('x', '1'))
7+
CONNECTING_CLIENT_LIMIT = Settings.connecting_client_limit.to_i
8+
69
attr_reader :config
710

811
def initialize(configs, params)
912
@wg_genkey = KeyGenerator.wg_genkey
10-
@wg_pubkey = KeyGenerator.wg_pubkey(@wg_genkey)
11-
@wg_genpsk = KeyGenerator.wg_genpsk
1213
@configs = configs
14+
check_availability_of_space!
1315
@config = build_config(params)
1416
end
1517

1618
private
1719

18-
attr_reader :wg_genkey, :wg_pubkey, :wg_genpsk, :configs
20+
attr_reader :wg_genkey, :configs
1921

2022
def build_config(params)
2123
{
22-
id: new_last_id,
24+
id: configs['last_id'] + 1,
2325
address: new_last_ip,
2426
private_key: wg_genkey,
25-
public_key: wg_pubkey,
26-
preshared_key: wg_genpsk,
27+
public_key: KeyGenerator.wg_pubkey(wg_genkey),
28+
preshared_key: KeyGenerator.wg_genpsk,
2729
enable: true,
2830
data: params
2931
}
3032
end
3133

32-
def new_last_id
33-
configs['last_id'] + 1
34+
def new_last_ip
35+
IPAddr.new(find_current_last_ip.to_i + 1, Socket::AF_INET).to_s
3436
end
3537

36-
def new_last_ip
37-
current_ip = IPAddr.new(configs['last_address'])
38-
IPAddr.new(current_ip.to_i + 1, Socket::AF_INET).to_s
38+
def check_availability_of_space!
39+
return unless all_ip_addresses.size >= available_addresses_count
40+
41+
raise Errors::ConnectionLimitExceededError
42+
end
43+
44+
def available_addresses_count
45+
(2**(32 - CONNECTING_CLIENT_LIMIT)) - 2
46+
end
47+
48+
def all_ip_addresses
49+
@all_ip_addresses ||= begin
50+
configs.except('last_id').filter_map do |_id, config|
51+
# NOTE: This is necessary in order to maintain backward compatibility
52+
# with those who still have the "last_address" field in the config.
53+
# In the next versions this needs to be removed along with the `filter_map`.
54+
next unless config.is_a?(Hash)
55+
56+
IPAddr.new(config['address'])
57+
end << WG_DEFAULT_ADDRESS
58+
end.sort
59+
end
60+
61+
def find_current_last_ip
62+
all_ip_addresses.each_with_index do |ip, index|
63+
next_ip = all_ip_addresses[index + 1]
64+
65+
return ip if next_ip.nil? || (next_ip.to_i - ip.to_i) > 1
66+
end
3967
end
4068
end
4169
end

lib/wire_guard/server.rb

+4-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module WireGuard
55
# Allows you to manage configuration files on the server
66
class Server
77
WG_JSON_PATH = "#{Settings.wg_path}/wg0.json".freeze
8-
WG_DEFAULT_ADDRESS = Settings.wg_default_address
8+
WG_DEFAULT_ADDRESS = Settings.wg_default_address.gsub('x', '1')
99

1010
attr_reader :server_private_key, :server_public_key
1111

@@ -26,7 +26,7 @@ def new_config(params)
2626
def all_configs
2727
return {} if configs_empty?
2828

29-
@configs.except('last_id', 'last_address')
29+
@configs.except('last_id')
3030
end
3131

3232
def config(id)
@@ -89,11 +89,10 @@ def create_json_server_config # rubocop:disable Metrics/MethodLength
8989
server: {
9090
private_key: @server_private_key,
9191
public_key: @server_public_key,
92-
address: WG_DEFAULT_ADDRESS.gsub('x', '1')
92+
address: WG_DEFAULT_ADDRESS
9393
},
9494
configs: {
95-
last_id: 0,
96-
last_address: WG_DEFAULT_ADDRESS.gsub('x', '1')
95+
last_id: 0
9796
}
9897
}
9998

@@ -115,7 +114,6 @@ def dump_wireguard_config
115114
def update_json_config(config)
116115
json_config['configs'][config[:id].to_s] = config
117116
json_config['configs']['last_id'] = config[:id]
118-
json_config['configs']['last_address'] = config[:address]
119117
end
120118

121119
def generate_server_private_key

lib/wire_guard/server_config_updater.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def update
2929
new_config_build = []
3030
new_config_build << base_config
3131

32-
json_config['configs'].except('last_id', 'last_address').each_value do |config|
32+
json_config['configs'].except('last_id').each_value do |config|
3333
# NOTE: We simply skip the config and do not add it to the initial configuration,
3434
# if the 'enable == false'
3535
next if config['enable'] == false

spec/app/clients_controller_spec.rb

+7-11
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
address: '10.8.0.1'
2727
},
2828
configs: {
29-
last_id: 0,
30-
last_address: '10.8.0.1'
29+
last_id: 0
3130
}
3231
}
3332
end
@@ -63,7 +62,7 @@
6362
{
6463
id: 1,
6564
server_public_key: 'uygGKpQt7gOwrP+bqkiXytafHiM+XqFGc0jtZVJ5bnw=',
66-
address: '10.8.0.2/24',
65+
address: '10.8.0.2/29',
6766
private_key: 'MJn6fwoyqG8S6wsrJzWrUow4leZuEM9O8s+G+kcXElU=',
6867
public_key: 'LiXk4UOfnScgf4UnkcYNcz4wWeqTOW1UrHKRVhZ1OXg=',
6968
preshared_key: '3UzAMA6mLIGjHOImShNb5tWlkwxsha8LZZP7dm49meQ=',
@@ -81,7 +80,7 @@
8180
{
8281
id: 2,
8382
server_public_key: 'uygGKpQt7gOwrP+bqkiXytafHiM+XqFGc0jtZVJ5bnw=',
84-
address: '10.8.0.3/24',
83+
address: '10.8.0.3/29',
8584
private_key: 'aN7ye98FKrmydwfA6tHgHE1PbiidWzUJ9cltnies8F4=',
8685
public_key: 'hvIyIW2o8JROVKuY2yYFdUn0oA+43aLuT8KCy0YbORE=',
8786
preshared_key: 'dVW/5kF8wnsx0zAwR4uPIa06btACxpQ/rHBL1B3qPnk=',
@@ -99,7 +98,7 @@
9998
{
10099
id: 3,
101100
server_public_key: 'uygGKpQt7gOwrP+bqkiXytafHiM+XqFGc0jtZVJ5bnw=',
102-
address: '10.8.0.4/24',
101+
address: '10.8.0.4/29',
103102
private_key: 'eF3Owsqd5MGAIXjmALGBi8ea8mkFUmAiyh80U3hVXn8=',
104103
public_key: 'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=',
105104
preshared_key: 'IyVg7fktkSBxJ0uK82j6nlI7Vmo0E53eBmYZ723/45E=',
@@ -135,7 +134,7 @@
135134
{
136135
id: 2,
137136
server_public_key: 'uygGKpQt7gOwrP+bqkiXytafHiM+XqFGc0jtZVJ5bnw=',
138-
address: '10.8.0.3/24',
137+
address: '10.8.0.3/29',
139138
private_key: 'aN7ye98FKrmydwfA6tHgHE1PbiidWzUJ9cltnies8F4=',
140139
public_key: 'hvIyIW2o8JROVKuY2yYFdUn0oA+43aLuT8KCy0YbORE=',
141140
preshared_key: 'dVW/5kF8wnsx0zAwR4uPIa06btACxpQ/rHBL1B3qPnk=',
@@ -171,7 +170,7 @@
171170
{
172171
id: 1,
173172
server_public_key: 'wg_pubkey',
174-
address: '10.8.0.2/24',
173+
address: '10.8.0.2/29',
175174
private_key: 'wg_genkey',
176175
public_key: 'wg_pubkey',
177176
preshared_key: 'wg_genpsk',
@@ -195,7 +194,6 @@
195194
},
196195
configs: {
197196
last_id: 1,
198-
last_address: '10.8.0.2',
199197
'1' => {
200198
id: 1,
201199
address: '10.8.0.2',
@@ -237,7 +235,6 @@
237235
},
238236
configs: {
239237
last_id: 3,
240-
last_address: '10.8.0.4',
241238
'1' => {
242239
id: 1,
243240
address: '10.8.0.2',
@@ -312,7 +309,6 @@
312309
},
313310
'configs' => {
314311
'last_id' => 3,
315-
'last_address' => '10.8.0.4',
316312
'1' => {
317313
'id' => 1,
318314
'address' => '10.8.0.200',
@@ -351,7 +347,7 @@
351347
{
352348
id: 1,
353349
server_public_key: 'uygGKpQt7gOwrP+bqkiXytafHiM+XqFGc0jtZVJ5bnw=',
354-
address: '10.8.0.200/24',
350+
address: '10.8.0.200/29',
355351
private_key: 'a',
356352
public_key: 'b',
357353
preshared_key: 'c',

spec/app/clients_serializer_spec.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
{
3636
id: 1,
3737
server_public_key: '4',
38-
address: '10.8.0.2/24',
38+
address: '10.8.0.2/29',
3939
private_key: '1',
4040
public_key: 'LiXk4UOfnScgf4UnkcYNcz4wWeqTOW1UrHKRVhZ1OXg=',
4141
preshared_key: '3',
@@ -98,7 +98,7 @@
9898
{
9999
id: 1,
100100
server_public_key: '4',
101-
address: '10.8.0.2/24',
101+
address: '10.8.0.2/29',
102102
private_key: '1',
103103
public_key: 'LiXk4UOfnScgf4UnkcYNcz4wWeqTOW1UrHKRVhZ1OXg=',
104104
preshared_key: '3',
@@ -117,7 +117,7 @@
117117
{
118118
id: 2,
119119
server_public_key: '4',
120-
address: '10.8.0.3/24',
120+
address: '10.8.0.3/29',
121121
private_key: '1',
122122
public_key: 'hvIyIW2o8JROVKuY2yYFdUn0oA+43aLuT8KCy0YbORE=',
123123
preshared_key: '3',
@@ -136,7 +136,7 @@
136136
{
137137
id: 3,
138138
server_public_key: '4',
139-
address: '10.8.0.4/24',
139+
address: '10.8.0.4/29',
140140
private_key: '1',
141141
public_key: 'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=',
142142
preshared_key: '3',

spec/fixtures/empty_wg0.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"address": "10.8.0.1"
66
},
77
"configs": {
8-
"last_id": 0,
9-
"last_address": "10.8.0.1"
8+
"last_id": 0
109
}
1110
}

spec/fixtures/wg0.conf

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
# Server
55
[Interface]
66
PrivateKey = 6Mlqg+1Umojm7a4VvgIi+YMp4oPrWNnZ5HLRFu4my2w=
7-
Address = 10.8.0.1/24
7+
Address = 10.8.0.1/29
88
ListenPort = 51820
99
PreUp =
10-
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT;
10+
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/29 -o eth0 -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT;
1111
PreDown =
12-
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; iptables -D INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT;
12+
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/29 -o eth0 -j MASQUERADE; iptables -D INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT;
1313

1414
# Client ID: 1
1515
[Peer]

spec/fixtures/wg0.json

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
},
77
"configs": {
88
"last_id": 3,
9-
"last_address": "10.8.0.4",
109
"1": {
1110
"id": 1,
1211
"address": "10.8.0.2",

0 commit comments

Comments
 (0)