forked from core/mobile_nebula
Add DNS resolver support
This commit is contained in:
parent
ec1af2974a
commit
1ecaaa60ff
|
@ -131,6 +131,11 @@ class NebulaVpnService : VpnService() {
|
||||||
builder.addRoute(unsafeIPNet.network, unsafeIPNet.maskSize.toInt())
|
builder.addRoute(unsafeIPNet.network, unsafeIPNet.maskSize.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add our DNS resolvers
|
||||||
|
site!!.dnsResolvers.forEach { dnsResolver ->
|
||||||
|
builder.addDnsServer(dnsResolver)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
vpnInterface = builder.establish()
|
vpnInterface = builder.establish()
|
||||||
nebula = mobileNebula.MobileNebula.newNebula(site!!.config, site!!.getKey(this), site!!.logFile, vpnInterface!!.detachFd().toLong())
|
nebula = mobileNebula.MobileNebula.newNebula(site!!.config, site!!.getKey(this), site!!.logFile, vpnInterface!!.detachFd().toLong())
|
||||||
|
|
|
@ -201,6 +201,7 @@ class Site(context: Context, siteDir: File) {
|
||||||
val id: String
|
val id: String
|
||||||
val staticHostmap: HashMap<String, StaticHosts>
|
val staticHostmap: HashMap<String, StaticHosts>
|
||||||
val unsafeRoutes: List<UnsafeRoute>
|
val unsafeRoutes: List<UnsafeRoute>
|
||||||
|
val dnsResolvers: List<String>
|
||||||
var cert: CertificateInfo? = null
|
var cert: CertificateInfo? = null
|
||||||
var ca: Array<CertificateInfo>
|
var ca: Array<CertificateInfo>
|
||||||
val lhDuration: Int
|
val lhDuration: Int
|
||||||
|
@ -236,6 +237,7 @@ class Site(context: Context, siteDir: File) {
|
||||||
id = incomingSite.id
|
id = incomingSite.id
|
||||||
staticHostmap = incomingSite.staticHostmap
|
staticHostmap = incomingSite.staticHostmap
|
||||||
unsafeRoutes = incomingSite.unsafeRoutes ?: ArrayList()
|
unsafeRoutes = incomingSite.unsafeRoutes ?: ArrayList()
|
||||||
|
dnsResolvers = incomingSite.dnsResolvers ?: ArrayList()
|
||||||
lhDuration = incomingSite.lhDuration
|
lhDuration = incomingSite.lhDuration
|
||||||
port = incomingSite.port
|
port = incomingSite.port
|
||||||
mtu = incomingSite.mtu ?: 1300
|
mtu = incomingSite.mtu ?: 1300
|
||||||
|
@ -340,6 +342,7 @@ class IncomingSite(
|
||||||
val id: String,
|
val id: String,
|
||||||
val staticHostmap: HashMap<String, StaticHosts>,
|
val staticHostmap: HashMap<String, StaticHosts>,
|
||||||
val unsafeRoutes: List<UnsafeRoute>?,
|
val unsafeRoutes: List<UnsafeRoute>?,
|
||||||
|
val dnsResolvers: List<String>?,
|
||||||
val cert: String,
|
val cert: String,
|
||||||
val ca: String,
|
val ca: String,
|
||||||
val lhDuration: Int,
|
val lhDuration: Int,
|
||||||
|
|
|
@ -78,6 +78,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
|
|
||||||
tunnelNetworkSettings.ipv4Settings!.includedRoutes = routes
|
tunnelNetworkSettings.ipv4Settings!.includedRoutes = routes
|
||||||
tunnelNetworkSettings.mtu = _site.mtu as NSNumber
|
tunnelNetworkSettings.mtu = _site.mtu as NSNumber
|
||||||
|
|
||||||
|
if !_site.dnsResolvers.isEmpty {
|
||||||
|
let dnsSettings = NEDNSSettings(servers: _site.dnsResolvers)
|
||||||
|
tunnelNetworkSettings.dnsSettings = dnsSettings
|
||||||
|
}
|
||||||
|
|
||||||
self.setTunnelNetworkSettings(tunnelNetworkSettings, completionHandler: {(error:Error?) in
|
self.setTunnelNetworkSettings(tunnelNetworkSettings, completionHandler: {(error:Error?) in
|
||||||
if (error != nil) {
|
if (error != nil) {
|
||||||
|
|
|
@ -121,6 +121,7 @@ class Site: Codable {
|
||||||
// Stored in proto
|
// Stored in proto
|
||||||
var staticHostmap: Dictionary<String, StaticHosts>
|
var staticHostmap: Dictionary<String, StaticHosts>
|
||||||
var unsafeRoutes: [UnsafeRoute]
|
var unsafeRoutes: [UnsafeRoute]
|
||||||
|
var dnsResolvers: [String]
|
||||||
var cert: CertificateInfo?
|
var cert: CertificateInfo?
|
||||||
var ca: [CertificateInfo]
|
var ca: [CertificateInfo]
|
||||||
var lhDuration: Int
|
var lhDuration: Int
|
||||||
|
@ -194,6 +195,7 @@ class Site: Codable {
|
||||||
id = incoming.id
|
id = incoming.id
|
||||||
staticHostmap = incoming.staticHostmap
|
staticHostmap = incoming.staticHostmap
|
||||||
unsafeRoutes = incoming.unsafeRoutes ?? []
|
unsafeRoutes = incoming.unsafeRoutes ?? []
|
||||||
|
dnsResolvers = incoming.dnsResolvers ?? []
|
||||||
lhDuration = incoming.lhDuration
|
lhDuration = incoming.lhDuration
|
||||||
port = incoming.port
|
port = incoming.port
|
||||||
cipher = incoming.cipher
|
cipher = incoming.cipher
|
||||||
|
@ -340,6 +342,7 @@ class Site: Codable {
|
||||||
case status
|
case status
|
||||||
case logFile
|
case logFile
|
||||||
case unsafeRoutes
|
case unsafeRoutes
|
||||||
|
case dnsResolvers
|
||||||
case logVerbosity
|
case logVerbosity
|
||||||
case errors
|
case errors
|
||||||
case mtu
|
case mtu
|
||||||
|
@ -394,6 +397,7 @@ struct IncomingSite: Codable {
|
||||||
var id: String
|
var id: String
|
||||||
var staticHostmap: Dictionary<String, StaticHosts>
|
var staticHostmap: Dictionary<String, StaticHosts>
|
||||||
var unsafeRoutes: [UnsafeRoute]?
|
var unsafeRoutes: [UnsafeRoute]?
|
||||||
|
vat dnsResolvers: [String]?
|
||||||
var cert: String
|
var cert: String
|
||||||
var ca: String
|
var ca: String
|
||||||
var lhDuration: Int
|
var lhDuration: Int
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:convert';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:mobile_nebula/models/HostInfo.dart';
|
import 'package:mobile_nebula/models/HostInfo.dart';
|
||||||
import 'package:mobile_nebula/models/UnsafeRoute.dart';
|
import 'package:mobile_nebula/models/UnsafeRoute.dart';
|
||||||
|
import 'package:mobile_nebula/models/IPAndPort.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import 'Certificate.dart';
|
import 'Certificate.dart';
|
||||||
import 'StaticHosts.dart';
|
import 'StaticHosts.dart';
|
||||||
|
@ -24,6 +25,7 @@ class Site {
|
||||||
// static_host_map
|
// static_host_map
|
||||||
late Map<String, StaticHost> staticHostmap;
|
late Map<String, StaticHost> staticHostmap;
|
||||||
late List<UnsafeRoute> unsafeRoutes;
|
late List<UnsafeRoute> unsafeRoutes;
|
||||||
|
late List<String> dnsResolvers;
|
||||||
|
|
||||||
// pki fields
|
// pki fields
|
||||||
late List<CertificateInfo> ca;
|
late List<CertificateInfo> ca;
|
||||||
|
@ -69,6 +71,7 @@ class Site {
|
||||||
String logVerbosity = 'info',
|
String logVerbosity = 'info',
|
||||||
List<String>? errors,
|
List<String>? errors,
|
||||||
List<UnsafeRoute>? unsafeRoutes,
|
List<UnsafeRoute>? unsafeRoutes,
|
||||||
|
List<String>? dnsResolvers,
|
||||||
bool managed = false,
|
bool managed = false,
|
||||||
String? rawConfig,
|
String? rawConfig,
|
||||||
DateTime? lastManagedUpdate,
|
DateTime? lastManagedUpdate,
|
||||||
|
@ -89,6 +92,7 @@ class Site {
|
||||||
this.logVerbosity = logVerbosity;
|
this.logVerbosity = logVerbosity;
|
||||||
this.errors = errors ?? [];
|
this.errors = errors ?? [];
|
||||||
this.unsafeRoutes = unsafeRoutes ?? [];
|
this.unsafeRoutes = unsafeRoutes ?? [];
|
||||||
|
this.dnsResolvers = dnsResolvers ?? [];
|
||||||
this.managed = managed;
|
this.managed = managed;
|
||||||
this.rawConfig = rawConfig;
|
this.rawConfig = rawConfig;
|
||||||
this.lastManagedUpdate = lastManagedUpdate;
|
this.lastManagedUpdate = lastManagedUpdate;
|
||||||
|
@ -128,6 +132,7 @@ class Site {
|
||||||
logVerbosity: decoded['logVerbosity'],
|
logVerbosity: decoded['logVerbosity'],
|
||||||
errors: decoded['errors'],
|
errors: decoded['errors'],
|
||||||
unsafeRoutes: decoded['unsafeRoutes'],
|
unsafeRoutes: decoded['unsafeRoutes'],
|
||||||
|
dnsResolvers: decoded['dnsResolvers'],
|
||||||
managed: decoded['managed'],
|
managed: decoded['managed'],
|
||||||
rawConfig: decoded['rawConfig'],
|
rawConfig: decoded['rawConfig'],
|
||||||
lastManagedUpdate: decoded['lastManagedUpdate'],
|
lastManagedUpdate: decoded['lastManagedUpdate'],
|
||||||
|
@ -152,6 +157,7 @@ class Site {
|
||||||
this.logVerbosity = decoded['logVerbosity'];
|
this.logVerbosity = decoded['logVerbosity'];
|
||||||
this.errors = decoded['errors'];
|
this.errors = decoded['errors'];
|
||||||
this.unsafeRoutes = decoded['unsafeRoutes'];
|
this.unsafeRoutes = decoded['unsafeRoutes'];
|
||||||
|
this.dnsResolvers = decoded['dnsResolvers'];
|
||||||
this.managed = decoded['managed'];
|
this.managed = decoded['managed'];
|
||||||
this.rawConfig = decoded['rawConfig'];
|
this.rawConfig = decoded['rawConfig'];
|
||||||
this.lastManagedUpdate = decoded['lastManagedUpdate'];
|
this.lastManagedUpdate = decoded['lastManagedUpdate'];
|
||||||
|
@ -170,6 +176,12 @@ class Site {
|
||||||
unsafeRoutes.add(UnsafeRoute.fromJson(val));
|
unsafeRoutes.add(UnsafeRoute.fromJson(val));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
List<dynamic> rawDNSResolvers = json['dnsResolvers'];
|
||||||
|
List<String> dnsResolvers = [];
|
||||||
|
rawDNSResolvers.forEach((val) {
|
||||||
|
dnsResolvers.add(val);
|
||||||
|
});
|
||||||
|
|
||||||
List<dynamic> rawCA = json['ca'];
|
List<dynamic> rawCA = json['ca'];
|
||||||
List<CertificateInfo> ca = [];
|
List<CertificateInfo> ca = [];
|
||||||
rawCA.forEach((val) {
|
rawCA.forEach((val) {
|
||||||
|
@ -204,6 +216,7 @@ class Site {
|
||||||
"logVerbosity": json['logVerbosity'],
|
"logVerbosity": json['logVerbosity'],
|
||||||
"errors": errors,
|
"errors": errors,
|
||||||
"unsafeRoutes": unsafeRoutes,
|
"unsafeRoutes": unsafeRoutes,
|
||||||
|
"dnsResolvers": dnsResolvers,
|
||||||
"managed": json['managed'] ?? false,
|
"managed": json['managed'] ?? false,
|
||||||
"rawConfig": json['rawConfig'],
|
"rawConfig": json['rawConfig'],
|
||||||
"lastManagedUpdate": json["lastManagedUpdate"] == null ?
|
"lastManagedUpdate": json["lastManagedUpdate"] == null ?
|
||||||
|
@ -221,6 +234,7 @@ class Site {
|
||||||
'id': id,
|
'id': id,
|
||||||
'staticHostmap': staticHostmap,
|
'staticHostmap': staticHostmap,
|
||||||
'unsafeRoutes': unsafeRoutes,
|
'unsafeRoutes': unsafeRoutes,
|
||||||
|
'dnsResolvers': dnsResolvers,
|
||||||
'ca': ca.map((cert) {
|
'ca': ca.map((cert) {
|
||||||
return cert.rawCert;
|
return cert.rawCert;
|
||||||
}).join('\n'),
|
}).join('\n'),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:mobile_nebula/components/config/ConfigSection.dart';
|
||||||
import 'package:mobile_nebula/models/Site.dart';
|
import 'package:mobile_nebula/models/Site.dart';
|
||||||
import 'package:mobile_nebula/models/UnsafeRoute.dart';
|
import 'package:mobile_nebula/models/UnsafeRoute.dart';
|
||||||
import 'package:mobile_nebula/screens/siteConfig/CipherScreen.dart';
|
import 'package:mobile_nebula/screens/siteConfig/CipherScreen.dart';
|
||||||
|
import 'package:mobile_nebula/screens/siteConfig/DNSResolversScreen.dart';
|
||||||
import 'package:mobile_nebula/screens/siteConfig/LogVerbosityScreen.dart';
|
import 'package:mobile_nebula/screens/siteConfig/LogVerbosityScreen.dart';
|
||||||
import 'package:mobile_nebula/screens/siteConfig/RenderedConfigScreen.dart';
|
import 'package:mobile_nebula/screens/siteConfig/RenderedConfigScreen.dart';
|
||||||
import 'package:mobile_nebula/services/utils.dart';
|
import 'package:mobile_nebula/services/utils.dart';
|
||||||
|
@ -28,6 +29,7 @@ class Advanced {
|
||||||
String verbosity;
|
String verbosity;
|
||||||
List<UnsafeRoute> unsafeRoutes;
|
List<UnsafeRoute> unsafeRoutes;
|
||||||
int mtu;
|
int mtu;
|
||||||
|
List<String> dnsResolvers;
|
||||||
|
|
||||||
Advanced({
|
Advanced({
|
||||||
required this.lhDuration,
|
required this.lhDuration,
|
||||||
|
@ -36,6 +38,7 @@ class Advanced {
|
||||||
required this.verbosity,
|
required this.verbosity,
|
||||||
required this.unsafeRoutes,
|
required this.unsafeRoutes,
|
||||||
required this.mtu,
|
required this.mtu,
|
||||||
|
required this.dnsResolvers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +69,7 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
|
||||||
verbosity: widget.site.logVerbosity,
|
verbosity: widget.site.logVerbosity,
|
||||||
unsafeRoutes: widget.site.unsafeRoutes,
|
unsafeRoutes: widget.site.unsafeRoutes,
|
||||||
mtu: widget.site.mtu,
|
mtu: widget.site.mtu,
|
||||||
|
dnsResolvers: widget.site.dnsResolvers,
|
||||||
);
|
);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
@ -192,7 +196,26 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
ConfigPageItem(
|
||||||
|
label: Text('DNS Resolvers'),
|
||||||
|
labelWidth: 150,
|
||||||
|
content: Text(
|
||||||
|
Utils.itemCountFormat(settings.dnsResolvers.length),
|
||||||
|
textAlign: TextAlign.end),
|
||||||
|
onPressed: () {
|
||||||
|
Utils.openPage(context, (context) {
|
||||||
|
return DNSResolversScreen(
|
||||||
|
dnsResolvers: settings.dnsResolversmm
|
||||||
|
onSave: (dnsResolvers) {
|
||||||
|
setState(() {
|
||||||
|
settings.dnsResolvers = dnsResolvers;
|
||||||
|
changed = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
ConfigSection(
|
ConfigSection(
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
|
import 'package:mobile_nebula/components/FormPage.dart';
|
||||||
|
import 'package:mobile_nebula/components/IPFormField.dart';
|
||||||
|
import 'package:mobile_nebula/components/config/ConfigItem.dart';
|
||||||
|
import 'package:mobile_nebula/components/config/ConfigSection.dart';
|
||||||
|
import 'package:mobile_nebula/services/utils.dart';
|
||||||
|
|
||||||
|
lass DNSResolverScreen extends StatefulWidget {
|
||||||
|
const DNSResolverScreen({Key? key, required this.dnsResolver, required this.onDelete, required this.onSave}) : super(key: key);
|
||||||
|
|
||||||
|
final String dnsResolver;
|
||||||
|
final ValueChanged<String> onSave;
|
||||||
|
final Function onDelete;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DNSResolverScreenState createState() => _DNSResolverScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DNSResolverScreenState extends State<DNSResolverScreen> {
|
||||||
|
late String dnsResolver;
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
FocusNode dnsResolverFocus = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
dnsResolver = widget.dnsResolver;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FormPage(
|
||||||
|
title: widget.onDelete == null ? 'New DNS Resolver' : 'Edit DNS Resolver',
|
||||||
|
changed: changed,
|
||||||
|
onSave: _onSave,
|
||||||
|
child: Column(children: [
|
||||||
|
ConfigSection(children: <Widget>[
|
||||||
|
ConfigItem(
|
||||||
|
label: Text('Address'),
|
||||||
|
content: IPFormField(
|
||||||
|
initialValue: dnsResolver,
|
||||||
|
ipOnly: true,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
focusNode: dnsResolverFocus,
|
||||||
|
onSaved: (v) {
|
||||||
|
dnsResolver = v.toString();
|
||||||
|
})),
|
||||||
|
]),
|
||||||
|
widget.onDelete != null
|
||||||
|
? Padding(
|
||||||
|
padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: PlatformElevatedButton(
|
||||||
|
child: Text('Delete'),
|
||||||
|
color: CupertinoColors.systemRed.resolveFrom(context),
|
||||||
|
onPressed: () => Utils.confirmDelete(context, 'Delete DNS Resolver?', () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
widget.onDelete();
|
||||||
|
}),
|
||||||
|
)))
|
||||||
|
: Container()
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
_onSave() {
|
||||||
|
Navigator.pop(context);
|
||||||
|
if (widget.onSave != null) {
|
||||||
|
widget.onSave(dnsResolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:mobile_nebula/components/FormPage.dart';
|
||||||
|
import 'package:mobile_nebula/components/config/ConfigButtonItem.dart';
|
||||||
|
import 'package:mobile_nebula/components/config/ConfigPageItem.dart';
|
||||||
|
import 'package:mobile_nebula/components/config/ConfigSection.dart';
|
||||||
|
import 'package:mobile_nebula/screens/siteConfig/DNSResolverScreen.dart';
|
||||||
|
import 'package:mobile_nebula/services/utils.dart';
|
||||||
|
|
||||||
|
class DNSResolversScreen extends StatefulWidget {
|
||||||
|
const DNSResolversScreen(
|
||||||
|
{Key? key, required this.dnsResolvers, required this.onSave})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final List<String> dnsResolvers;
|
||||||
|
final ValueChanged<List<String>> onSave;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DNSResolversScreenState createState() => _DNSResolversScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DNSResolversScreenState extends State<DNSResolversScreen> {
|
||||||
|
late List<String> dnsResolvers = [];
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
widget.dnsResolvers.forEach((dnsResolver) {
|
||||||
|
dnsResolvers.add(dnsResolver);
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FormPage(
|
||||||
|
title: 'DNS Resolvers',
|
||||||
|
changed: changed,
|
||||||
|
onSave: _onSave,
|
||||||
|
child: ConfigSection(
|
||||||
|
children: _build(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
_onSave() {
|
||||||
|
Navigator.pop(context);
|
||||||
|
if (widget.onSave != null) {
|
||||||
|
widget.onSave(dnsResolvers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _build() {
|
||||||
|
List<Widget> items = [];
|
||||||
|
for (var i=0; i<dnsResolvers.length;i++) {
|
||||||
|
final dnsResolver = dnsResolvers[i];
|
||||||
|
items.add(ConfigPageItem(
|
||||||
|
label: Text("Resolver"),
|
||||||
|
content: Text(dnsResolver, textAlign: TextAlign.end),
|
||||||
|
onPressed: () {
|
||||||
|
Utils.openPage(context, (context) {
|
||||||
|
return DNSResolverScreen(
|
||||||
|
dnsResolver: dnsResolver,
|
||||||
|
onSave: (dnsResolver) {
|
||||||
|
setState(() {
|
||||||
|
changed = true;
|
||||||
|
dnsResolvers[i] = dnsResolver;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDelete: () {
|
||||||
|
setState(() {
|
||||||
|
changed = true;
|
||||||
|
dnsResolvers.removeAt(i);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
items.add(ConfigButtonItem(
|
||||||
|
content: Text('Add a new DNS resolver'),
|
||||||
|
onPressed: () {
|
||||||
|
Utils.openPage(context, (context) {
|
||||||
|
return DNSResolverScreen(
|
||||||
|
dnsResolver: "",
|
||||||
|
onSave: (dnsResolver) {
|
||||||
|
setState(() {
|
||||||
|
changed = true;
|
||||||
|
});
|
||||||
|
dnsResolvers.add(dnsResolver);
|
||||||
|
},
|
||||||
|
onDelete: () {},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
|
@ -292,6 +292,7 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
||||||
site.port = settings.port;
|
site.port = settings.port;
|
||||||
site.logVerbosity = settings.verbosity;
|
site.logVerbosity = settings.verbosity;
|
||||||
site.unsafeRoutes = settings.unsafeRoutes;
|
site.unsafeRoutes = settings.unsafeRoutes;
|
||||||
|
site.dnsResolvers = settings.dnsResolvers;
|
||||||
site.mtu = settings.mtu;
|
site.mtu = settings.mtu;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -139,6 +139,7 @@ type configTun struct {
|
||||||
MTU *int `yaml:"mtu,omitempty"`
|
MTU *int `yaml:"mtu,omitempty"`
|
||||||
Routes []configRoute `yaml:"routes"`
|
Routes []configRoute `yaml:"routes"`
|
||||||
UnsafeRoutes []configUnsafeRoute `yaml:"unsafe_routes"`
|
UnsafeRoutes []configUnsafeRoute `yaml:"unsafe_routes"`
|
||||||
|
DNSResolvers []string `yaml:"dns_resolvers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type configRoute struct {
|
type configRoute struct {
|
||||||
|
|
|
@ -116,6 +116,13 @@ func RenderConfig(configData string, key string) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dnsResolvers, ok := d["dnsResolvers"].([]interface{}); ok {
|
||||||
|
cfg.Tun.DNSResolvers = make([]string, len(dnsResolvers))
|
||||||
|
for i, r := range dnsResolvers {
|
||||||
|
cfg.Tun.DNSResolvers[i] = r.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
finalConfig, err := yaml.Marshal(cfg)
|
finalConfig, err := yaml.Marshal(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
Loading…
Reference in New Issue