Skip to content

Commit 7a3eda0

Browse files
committed
Fix AdguardTeam#1069 install: check static ip
Squashed commit of the following: commit 5746623 Merge: 2df5f28 867bf54 Author: Andrey Meshkov <[email protected]> Date: Thu Feb 13 18:39:15 2020 +0300 Merge branch 'master' into 1069-install-static-ip commit 2df5f28 Author: Andrey Meshkov <[email protected]> Date: Thu Feb 13 18:35:54 2020 +0300 *: lang fix commit b4649a6 Merge: c278525 f61d5f0 Author: Andrey Meshkov <[email protected]> Date: Thu Feb 13 16:47:30 2020 +0300 *(home): fixed issues with setting static IP on Mac commit c278525 Author: Andrey Meshkov <[email protected]> Date: Thu Feb 13 14:14:30 2020 +0300 +(dhcpd): added static IP for MacOS commit f61d5f0 Author: Ildar Kamalov <[email protected]> Date: Thu Feb 13 14:13:35 2020 +0300 + client: show confirm before setting static IP commit 7afa16f Author: Ildar Kamalov <[email protected]> Date: Thu Feb 13 13:51:52 2020 +0300 - client: fix text commit 019bff0 Author: Ildar Kamalov <[email protected]> Date: Thu Feb 13 13:49:16 2020 +0300 - client: pass all params to the check_config request commit 194bed7 Author: Andrey Meshkov <[email protected]> Date: Wed Feb 12 17:12:16 2020 +0300 *: fix home_test commit 9359f6b Merge: ae29905 c5ca2a7 Author: Andrey Meshkov <[email protected]> Date: Wed Feb 12 15:54:54 2020 +0300 Merge with master commit ae29905 Author: Andrey Meshkov <[email protected]> Date: Wed Feb 12 15:53:36 2020 +0300 *(global): refactoring - moved runtime properties to Context commit d8d48c5 Author: Andrey Meshkov <[email protected]> Date: Wed Feb 12 15:04:25 2020 +0300 *(dhcpd): refactoring, use dhcpd/network_utils where possible commit 8d039c5 Author: Ildar Kamalov <[email protected]> Date: Fri Feb 7 18:37:39 2020 +0300 - client: fix button position commit 26c47e5 Author: Ildar Kamalov <[email protected]> Date: Fri Feb 7 18:08:56 2020 +0300 - client: fix static ip description commit cb12bab Author: Andrey Meshkov <[email protected]> Date: Fri Feb 7 17:08:39 2020 +0300 *: lower log level for some commands commit d9001ff Author: Andrey Meshkov <[email protected]> Date: Fri Feb 7 16:17:59 2020 +0300 *(documentation): updated openapi commit 1d213d5 Merge: 8406d7d 8086186 Author: Andrey Meshkov <[email protected]> Date: Fri Feb 7 15:16:46 2020 +0300 *: merge with master commit 8406d7d Author: Ildar Kamalov <[email protected]> Date: Fri Jan 31 16:52:22 2020 +0300 - client: fix locales commit fb476b0 Author: Simon Zolin <[email protected]> Date: Fri Jan 31 13:29:03 2020 +0300 linter commit 84b5708 Author: Simon Zolin <[email protected]> Date: Fri Jan 31 13:27:53 2020 +0300 linter commit 143a86a Author: Simon Zolin <[email protected]> Date: Fri Jan 31 13:26:47 2020 +0300 linter ... and 7 more commits
1 parent 867bf54 commit 7a3eda0

38 files changed

+1319
-781
lines changed

AGHTechDoc.md

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,29 @@ Request:
138138
{
139139
"web":{"port":80,"ip":"192.168.11.33"},
140140
"dns":{"port":53,"ip":"127.0.0.1","autofix":false},
141+
"set_static_ip": true | false
141142
}
142143

143144
Server should check whether a port is available only in case it itself isn't already listening on that port.
144145

146+
If `set_static_ip` is `true`, Server attempts to set a static IP for the network interface chosen by `dns.ip` setting. If the operation is successful, `static_ip.static` setting will be `yes`. If it fails, `static_ip.static` setting will be set to `error` and `static_ip.error` will contain the error message.
147+
145148
Server replies on success:
146149

147150
200 OK
148151

149152
{
150153
"web":{"status":""},
151154
"dns":{"status":""},
155+
"static_ip": {
156+
"static": "yes|no|error",
157+
"ip": "<Current dynamic IP address>", // set if static=no
158+
"error": "..." // set if static=error
159+
}
152160
}
153161

162+
If `static_ip.static` is `no`, Server has detected that the system uses a dynamic address and it can automatically set a static address if `set_static_ip` in request is `true`. See section `Static IP check/set` for detailed process.
163+
154164
Server replies on error:
155165

156166
200 OK
@@ -172,7 +182,11 @@ Request:
172182
POST /control/install/check_config
173183

174184
{
175-
"dns":{"port":53,"ip":"127.0.0.1","autofix":false}
185+
"dns":{
186+
"port":53,
187+
"ip":"127.0.0.1",
188+
"autofix":false
189+
}
176190
}
177191

178192
Check if DNSStubListener is enabled:
@@ -499,13 +513,7 @@ which will print:
499513
default via 192.168.0.1 proto dhcp metric 100
500514

501515

502-
#### Phase 2
503-
504-
This method only works on Raspbian.
505-
506-
On Ubuntu DHCP for a network interface can't be disabled via `dhcpcd.conf`. This must be configured in `/etc/netplan/01-netcfg.yaml`.
507-
508-
Fedora doesn't use `dhcpcd.conf` configuration at all.
516+
#### Phase 2 (Raspbian)
509517

510518
Step 1.
511519

@@ -526,6 +534,44 @@ If we would set a different IP address, we'd need to replace the IP address for
526534
ip addr replace dev eth0 192.168.0.1/24
527535

528536

537+
#### Phase 2 (Ubuntu)
538+
539+
`/etc/netplan/01-netcfg.yaml` or `/etc/netplan/01-network-manager-all.yaml`
540+
541+
This configuration example has a static IP set for `enp0s3` interface:
542+
543+
network:
544+
version: 2
545+
renderer: networkd
546+
ethernets:
547+
enp0s3:
548+
dhcp4: no
549+
addresses: [192.168.0.2/24]
550+
gateway: 192.168.0.1
551+
nameservers:
552+
addresses: [192.168.0.1,8.8.8.8]
553+
554+
For dynamic configuration `dhcp4: yes` is set.
555+
556+
Make a backup copy to `/etc/netplan/01-netcfg.yaml.backup`.
557+
558+
Apply:
559+
560+
netplan apply
561+
562+
Restart network:
563+
564+
systemctl restart networking
565+
566+
or:
567+
568+
systemctl restart network-manager
569+
570+
or:
571+
572+
systemctl restart system-networkd
573+
574+
529575
### Add a static lease
530576

531577
Request:

client/src/__locales/en.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,16 @@
458458
"check_reason": "Reason: {{reason}}",
459459
"check_rule": "Rule: {{rule}}",
460460
"check_service": "Service name: {{service}}",
461-
"check_not_found": "Doesn't exist in any filter",
461+
"check_not_found": "Not found in your filter lists",
462462
"client_confirm_block": "Are you sure you want to block the client \"{{ip}}\"?",
463463
"client_confirm_unblock": "Are you sure you want to unblock the client \"{{ip}}\"?",
464464
"client_blocked": "Client \"{{ip}}\" successfully blocked",
465-
"client_unblocked": "Client \"{{ip}}\" successfully unblocked"
465+
"client_unblocked": "Client \"{{ip}}\" successfully unblocked",
466+
"static_ip": "Static IP Address",
467+
"static_ip_desc": "AdGuard Home is a server so it needs a static IP address to function properly. Otherwise, at some point, your router may assign a different IP address to this device.",
468+
"set_static_ip": "Set a static IP address",
469+
"install_static_ok": "Good news! The static IP address is already configured",
470+
"install_static_error": "AdGuard Home cannot configure it automatically for this network interface. Please look for an instruction on how to do this manually.",
471+
"install_static_configure": "We have detected that a dynamic IP address is used — <0>{{ip}}</0>. Do you want to use it as your static address?",
472+
"confirm_static_ip": "AdGuard Home will configure {{ip}} to be your static IP address. Do you want to proceed?"
466473
}

client/src/helpers/form.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,13 @@ export const port = (value) => {
240240
return undefined;
241241
};
242242

243+
export const validInstallPort = (value) => {
244+
if (value < 1 || value > 65535) {
245+
return <Trans>form_error_port</Trans>;
246+
}
247+
return undefined;
248+
};
249+
243250
export const portTLS = (value) => {
244251
if (value === 0) {
245252
return undefined;

client/src/install/Setup/Settings.js

Lines changed: 110 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,17 @@ import flow from 'lodash/flow';
77

88
import Controls from './Controls';
99
import AddressList from './AddressList';
10+
1011
import { getInterfaceIp } from '../../helpers/helpers';
1112
import { ALL_INTERFACES_IP } from '../../helpers/constants';
12-
import { renderInputField } from '../../helpers/form';
13+
import { renderInputField, required, validInstallPort, toNumber } from '../../helpers/form';
1314

14-
const required = (value) => {
15-
if (value || value === 0) {
16-
return false;
17-
}
18-
return <Trans>form_error_required</Trans>;
15+
const STATIC_STATUS = {
16+
ENABLED: 'yes',
17+
DISABLED: 'no',
18+
ERROR: 'error',
1919
};
2020

21-
const port = (value) => {
22-
if (value < 1 || value > 65535) {
23-
return <Trans>form_error_port</Trans>;
24-
}
25-
return false;
26-
};
27-
28-
const toNumber = value => value && parseInt(value, 10);
29-
3021
const renderInterfaces = (interfaces => (
3122
Object.keys(interfaces).map((item) => {
3223
const option = interfaces[item];
@@ -79,11 +70,91 @@ class Settings extends Component {
7970
});
8071
}
8172

73+
getStaticIpMessage = (staticIp) => {
74+
const { static: status, ip } = staticIp;
75+
76+
if (!status) {
77+
return '';
78+
}
79+
80+
return (
81+
<Fragment>
82+
{status === STATIC_STATUS.DISABLED && (
83+
<Fragment>
84+
<div className="mb-2">
85+
<Trans values={{ ip }} components={[<strong key="0">text</strong>]}>
86+
install_static_configure
87+
</Trans>
88+
</div>
89+
<button
90+
type="button"
91+
className="btn btn-outline-primary btn-sm"
92+
onClick={() => this.handleStaticIp(ip)}
93+
>
94+
<Trans>set_static_ip</Trans>
95+
</button>
96+
</Fragment>
97+
)}
98+
{status === STATIC_STATUS.ERROR && (
99+
<div className="text-danger">
100+
<Trans>install_static_error</Trans>
101+
</div>
102+
)}
103+
{status === STATIC_STATUS.ENABLED && (
104+
<div className="text-success">
105+
<Trans>
106+
install_static_ok
107+
</Trans>
108+
</div>
109+
)}
110+
</Fragment>
111+
);
112+
};
113+
114+
handleAutofix = (type) => {
115+
const {
116+
webIp,
117+
webPort,
118+
dnsIp,
119+
dnsPort,
120+
handleFix,
121+
} = this.props;
122+
123+
const web = { ip: webIp, port: webPort, autofix: false };
124+
const dns = { ip: dnsIp, port: dnsPort, autofix: false };
125+
const set_static_ip = false;
126+
127+
if (type === 'web') {
128+
web.autofix = true;
129+
} else {
130+
dns.autofix = true;
131+
}
132+
133+
handleFix(web, dns, set_static_ip);
134+
};
135+
136+
handleStaticIp = (ip) => {
137+
const {
138+
webIp,
139+
webPort,
140+
dnsIp,
141+
dnsPort,
142+
handleFix,
143+
} = this.props;
144+
145+
const web = { ip: webIp, port: webPort, autofix: false };
146+
const dns = { ip: dnsIp, port: dnsPort, autofix: false };
147+
const set_static_ip = true;
148+
149+
if (window.confirm(this.props.t('confirm_static_ip', { ip }))) {
150+
handleFix(web, dns, set_static_ip);
151+
}
152+
};
153+
82154
render() {
83155
const {
84156
handleSubmit,
85157
handleChange,
86-
handleAutofix,
87158
webIp,
88159
webPort,
89160
dnsIp,
@@ -100,6 +171,7 @@ class Settings extends Component {
100171
status: dnsStatus,
101172
can_autofix: isDnsFixAvailable,
102173
} = config.dns;
174+
const { staticIp } = config;
103175

104176
return (
105177
<form className="setup__step" onSubmit={handleSubmit}>
@@ -137,7 +209,7 @@ class Settings extends Component {
137209
type="number"
138210
className="form-control"
139211
placeholder="80"
140-
validate={[port, required]}
212+
validate={[validInstallPort, required]}
141213
normalize={toNumber}
142214
onChange={handleChange}
143215
/>
@@ -151,11 +223,12 @@ class Settings extends Component {
151223
<button
152224
type="button"
153225
className="btn btn-secondary btn-sm ml-2"
154-
onClick={() => handleAutofix('web', webIp, webPort)}
226+
onClick={() => this.handleAutofix('web')}
155227
>
156228
<Trans>fix</Trans>
157229
</button>
158230
}
231+
<hr className="divider--small" />
159232
</div>
160233
}
161234
</div>
@@ -171,6 +244,7 @@ class Settings extends Component {
171244
</div>
172245
</div>
173246
</div>
247+
174248
<div className="setup__group">
175249
<div className="setup__subtitle">
176250
<Trans>install_settings_dns</Trans>
@@ -205,7 +279,7 @@ class Settings extends Component {
205279
type="number"
206280
className="form-control"
207281
placeholder="80"
208-
validate={[port, required]}
282+
validate={[validInstallPort, required]}
209283
normalize={toNumber}
210284
onChange={handleChange}
211285
/>
@@ -220,7 +294,7 @@ class Settings extends Component {
220294
<button
221295
type="button"
222296
className="btn btn-secondary btn-sm ml-2"
223-
onClick={() => handleAutofix('dns', dnsIp, dnsPort)}
297+
onClick={() => this.handleAutofix('dns')}
224298
>
225299
<Trans>fix</Trans>
226300
</button>
@@ -237,6 +311,7 @@ class Settings extends Component {
237311
<Trans>autofix_warning_result</Trans>
238312
</p>
239313
</div>
314+
<hr className="divider--small" />
240315
</Fragment>
241316
}
242317
</div>
@@ -253,6 +328,19 @@ class Settings extends Component {
253328
</div>
254329
</div>
255330
</div>
331+
332+
<div className="setup__group">
333+
<div className="setup__subtitle">
334+
<Trans>static_ip</Trans>
335+
</div>
336+
337+
<div className="mb-2">
338+
<Trans>static_ip_desc</Trans>
339+
</div>
340+
341+
{this.getStaticIpMessage(staticIp)}
342+
</div>
343+
256344
<Controls invalid={invalid} />
257345
</form>
258346
);
@@ -262,7 +350,7 @@ class Settings extends Component {
262350
Settings.propTypes = {
263351
handleSubmit: PropTypes.func.isRequired,
264352
handleChange: PropTypes.func,
265-
handleAutofix: PropTypes.func,
353+
handleFix: PropTypes.func.isRequired,
266354
validateForm: PropTypes.func,
267355
webIp: PropTypes.string.isRequired,
268356
dnsIp: PropTypes.string.isRequired,
@@ -278,6 +366,7 @@ Settings.propTypes = {
278366
interfaces: PropTypes.object.isRequired,
279367
invalid: PropTypes.bool.isRequired,
280368
initialValues: PropTypes.object,
369+
t: PropTypes.func.isRequired,
281370
};
282371

283372
const selector = formValueSelector('install');

client/src/install/Setup/Setup.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,8 @@
119119
.setup__error {
120120
margin: -5px 0 5px;
121121
}
122+
123+
.divider--small {
124+
margin-top: 1rem;
125+
margin-bottom: 1rem;
126+
}

0 commit comments

Comments
 (0)