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())
|
||||
}
|
||||
|
||||
// Add our DNS resolvers
|
||||
site!!.dnsResolvers.forEach { dnsResolver ->
|
||||
builder.addDnsServer(dnsResolver)
|
||||
}
|
||||
|
||||
try {
|
||||
vpnInterface = builder.establish()
|
||||
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 staticHostmap: HashMap<String, StaticHosts>
|
||||
val unsafeRoutes: List<UnsafeRoute>
|
||||
val dnsResolvers: List<String>
|
||||
var cert: CertificateInfo? = null
|
||||
var ca: Array<CertificateInfo>
|
||||
val lhDuration: Int
|
||||
|
@ -236,6 +237,7 @@ class Site(context: Context, siteDir: File) {
|
|||
id = incomingSite.id
|
||||
staticHostmap = incomingSite.staticHostmap
|
||||
unsafeRoutes = incomingSite.unsafeRoutes ?: ArrayList()
|
||||
dnsResolvers = incomingSite.dnsResolvers ?: ArrayList()
|
||||
lhDuration = incomingSite.lhDuration
|
||||
port = incomingSite.port
|
||||
mtu = incomingSite.mtu ?: 1300
|
||||
|
@ -340,6 +342,7 @@ class IncomingSite(
|
|||
val id: String,
|
||||
val staticHostmap: HashMap<String, StaticHosts>,
|
||||
val unsafeRoutes: List<UnsafeRoute>?,
|
||||
val dnsResolvers: List<String>?,
|
||||
val cert: String,
|
||||
val ca: String,
|
||||
val lhDuration: Int,
|
||||
|
|
|
@ -79,6 +79,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
tunnelNetworkSettings.ipv4Settings!.includedRoutes = routes
|
||||
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
|
||||
if (error != nil) {
|
||||
return completionHandler(error!)
|
||||
|
|
|
@ -121,6 +121,7 @@ class Site: Codable {
|
|||
// Stored in proto
|
||||
var staticHostmap: Dictionary<String, StaticHosts>
|
||||
var unsafeRoutes: [UnsafeRoute]
|
||||
var dnsResolvers: [String]
|
||||
var cert: CertificateInfo?
|
||||
var ca: [CertificateInfo]
|
||||
var lhDuration: Int
|
||||
|
@ -194,6 +195,7 @@ class Site: Codable {
|
|||
id = incoming.id
|
||||
staticHostmap = incoming.staticHostmap
|
||||
unsafeRoutes = incoming.unsafeRoutes ?? []
|
||||
dnsResolvers = incoming.dnsResolvers ?? []
|
||||
lhDuration = incoming.lhDuration
|
||||
port = incoming.port
|
||||
cipher = incoming.cipher
|
||||
|
@ -340,6 +342,7 @@ class Site: Codable {
|
|||
case status
|
||||
case logFile
|
||||
case unsafeRoutes
|
||||
case dnsResolvers
|
||||
case logVerbosity
|
||||
case errors
|
||||
case mtu
|
||||
|
@ -394,6 +397,7 @@ struct IncomingSite: Codable {
|
|||
var id: String
|
||||
var staticHostmap: Dictionary<String, StaticHosts>
|
||||
var unsafeRoutes: [UnsafeRoute]?
|
||||
vat dnsResolvers: [String]?
|
||||
var cert: String
|
||||
var ca: String
|
||||
var lhDuration: Int
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:convert';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:mobile_nebula/models/HostInfo.dart';
|
||||
import 'package:mobile_nebula/models/UnsafeRoute.dart';
|
||||
import 'package:mobile_nebula/models/IPAndPort.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'Certificate.dart';
|
||||
import 'StaticHosts.dart';
|
||||
|
@ -24,6 +25,7 @@ class Site {
|
|||
// static_host_map
|
||||
late Map<String, StaticHost> staticHostmap;
|
||||
late List<UnsafeRoute> unsafeRoutes;
|
||||
late List<String> dnsResolvers;
|
||||
|
||||
// pki fields
|
||||
late List<CertificateInfo> ca;
|
||||
|
@ -69,6 +71,7 @@ class Site {
|
|||
String logVerbosity = 'info',
|
||||
List<String>? errors,
|
||||
List<UnsafeRoute>? unsafeRoutes,
|
||||
List<String>? dnsResolvers,
|
||||
bool managed = false,
|
||||
String? rawConfig,
|
||||
DateTime? lastManagedUpdate,
|
||||
|
@ -89,6 +92,7 @@ class Site {
|
|||
this.logVerbosity = logVerbosity;
|
||||
this.errors = errors ?? [];
|
||||
this.unsafeRoutes = unsafeRoutes ?? [];
|
||||
this.dnsResolvers = dnsResolvers ?? [];
|
||||
this.managed = managed;
|
||||
this.rawConfig = rawConfig;
|
||||
this.lastManagedUpdate = lastManagedUpdate;
|
||||
|
@ -128,6 +132,7 @@ class Site {
|
|||
logVerbosity: decoded['logVerbosity'],
|
||||
errors: decoded['errors'],
|
||||
unsafeRoutes: decoded['unsafeRoutes'],
|
||||
dnsResolvers: decoded['dnsResolvers'],
|
||||
managed: decoded['managed'],
|
||||
rawConfig: decoded['rawConfig'],
|
||||
lastManagedUpdate: decoded['lastManagedUpdate'],
|
||||
|
@ -152,6 +157,7 @@ class Site {
|
|||
this.logVerbosity = decoded['logVerbosity'];
|
||||
this.errors = decoded['errors'];
|
||||
this.unsafeRoutes = decoded['unsafeRoutes'];
|
||||
this.dnsResolvers = decoded['dnsResolvers'];
|
||||
this.managed = decoded['managed'];
|
||||
this.rawConfig = decoded['rawConfig'];
|
||||
this.lastManagedUpdate = decoded['lastManagedUpdate'];
|
||||
|
@ -170,6 +176,12 @@ class Site {
|
|||
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<CertificateInfo> ca = [];
|
||||
rawCA.forEach((val) {
|
||||
|
@ -204,6 +216,7 @@ class Site {
|
|||
"logVerbosity": json['logVerbosity'],
|
||||
"errors": errors,
|
||||
"unsafeRoutes": unsafeRoutes,
|
||||
"dnsResolvers": dnsResolvers,
|
||||
"managed": json['managed'] ?? false,
|
||||
"rawConfig": json['rawConfig'],
|
||||
"lastManagedUpdate": json["lastManagedUpdate"] == null ?
|
||||
|
@ -221,6 +234,7 @@ class Site {
|
|||
'id': id,
|
||||
'staticHostmap': staticHostmap,
|
||||
'unsafeRoutes': unsafeRoutes,
|
||||
'dnsResolvers': dnsResolvers,
|
||||
'ca': ca.map((cert) {
|
||||
return cert.rawCert;
|
||||
}).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/UnsafeRoute.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/RenderedConfigScreen.dart';
|
||||
import 'package:mobile_nebula/services/utils.dart';
|
||||
|
@ -28,6 +29,7 @@ class Advanced {
|
|||
String verbosity;
|
||||
List<UnsafeRoute> unsafeRoutes;
|
||||
int mtu;
|
||||
List<String> dnsResolvers;
|
||||
|
||||
Advanced({
|
||||
required this.lhDuration,
|
||||
|
@ -36,6 +38,7 @@ class Advanced {
|
|||
required this.verbosity,
|
||||
required this.unsafeRoutes,
|
||||
required this.mtu,
|
||||
required this.dnsResolvers,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -66,6 +69,7 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
|
|||
verbosity: widget.site.logVerbosity,
|
||||
unsafeRoutes: widget.site.unsafeRoutes,
|
||||
mtu: widget.site.mtu,
|
||||
dnsResolvers: widget.site.dnsResolvers,
|
||||
);
|
||||
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(
|
||||
|
|
|
@ -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.logVerbosity = settings.verbosity;
|
||||
site.unsafeRoutes = settings.unsafeRoutes;
|
||||
site.dnsResolvers = settings.dnsResolvers;
|
||||
site.mtu = settings.mtu;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -139,6 +139,7 @@ type configTun struct {
|
|||
MTU *int `yaml:"mtu,omitempty"`
|
||||
Routes []configRoute `yaml:"routes"`
|
||||
UnsafeRoutes []configUnsafeRoute `yaml:"unsafe_routes"`
|
||||
DNSResolvers []string `yaml:"dns_resolvers"`
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
Loading…
Reference in New Issue