From 2fe23e3ed221c51fa4a858c5c343fc5b8f9ecae9 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Tue, 19 Jul 2022 13:08:54 +0300 Subject: [PATCH 01/36] Updated dependencies --- CHANGELOG.md | 6 ++++++ pubspec.yaml | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b777ef6..38e99b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 1.0.9 + +1. Updated dart_ping package version to 7.0.1 + +2. Updated test package version to 1.21.4 + ## 1.0.8 Fixes diff --git a/pubspec.yaml b/pubspec.yaml index bab8be9..74a1d01 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 1.0.8 +version: 1.0.9 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools homepage: https://github.com/git-elliot/network_tools @@ -9,11 +9,11 @@ environment: sdk: ">=2.12.0 <3.0.0" dependencies: - dart_ping: ^6.1.1 + dart_ping: ^7.0.1 intl: ^0.17.0 logging: ^1.0.2 universal_io: ^2.0.4 dev_dependencies: lint: ^1.8.2 - test: ^1.20.1 + test: ^1.21.4 From 921917edbc5990925e84476f00fd0da0c7be780a Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Tue, 19 Jul 2022 15:53:38 +0300 Subject: [PATCH 02/36] Added comments to each dependency --- pubspec.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pubspec.yaml b/pubspec.yaml index 74a1d01..c5df4f5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,11 +9,17 @@ environment: sdk: ">=2.12.0 <3.0.0" dependencies: + # Multi-platform network ping utility. dart_ping: ^7.0.1 + # Deal with internationalized/localized messages and more. intl: ^0.17.0 + # Debugging and error logging. logging: ^1.0.2 + # Cross-platform 'dart:io' that works in all platforms. universal_io: ^2.0.4 dev_dependencies: + # Set of lint rules for Dart. lint: ^1.8.2 + # Writing and running Dart tests. test: ^1.21.4 From 27978a26871bfcfbba1fe2522a9326182027b89d Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Tue, 19 Jul 2022 16:00:57 +0300 Subject: [PATCH 03/36] Decided to update min dart version to 2.17.0 (even though pub get didn't show any errors) because it is the min version in dart_ping 7.0.0 --- CHANGELOG.md | 8 +++++--- pubspec.yaml | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38e99b9..06cbde1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ # Change Log -## 1.0.9 +## 2.0.0 -1. Updated dart_ping package version to 7.0.1 +1. **Breaking change**. Bump minimum dart version to 2.17.0. -2. Updated test package version to 1.21.4 +2. Updated dart_ping package version to 7.0.1. + +3. Updated test package version to 1.21.4. ## 1.0.8 diff --git a/pubspec.yaml b/pubspec.yaml index c5df4f5..db787cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,12 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 1.0.9 +version: 2.0.0 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools homepage: https://github.com/git-elliot/network_tools environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" dependencies: # Multi-platform network ping utility. From 1fa7444cff39f728181860e5670303f7f3cdb93f Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Tue, 19 Jul 2022 18:13:46 +0300 Subject: [PATCH 04/36] Reverted min dart version back to 2.12.0 as it is not mandatory --- CHANGELOG.md | 8 +++----- pubspec.yaml | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06cbde1..43138c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,10 @@ # Change Log -## 2.0.0 +## 1.0.9 -1. **Breaking change**. Bump minimum dart version to 2.17.0. +1. Updated dart_ping package version to 7.0.1. -2. Updated dart_ping package version to 7.0.1. - -3. Updated test package version to 1.21.4. +2. Updated test package version to 1.21.4. ## 1.0.8 diff --git a/pubspec.yaml b/pubspec.yaml index db787cf..c5df4f5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,12 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 2.0.0 +version: 1.0.9 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools homepage: https://github.com/git-elliot/network_tools environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: # Multi-platform network ping utility. From 9610258895e83b0d4510316a1a176019438dd54c Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sat, 23 Jul 2022 16:33:50 +0300 Subject: [PATCH 05/36] Updated min dart version to 2.17.0. --- CHANGELOG.md | 8 +++++--- pubspec.yaml | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43138c6..06cbde1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ # Change Log -## 1.0.9 +## 2.0.0 -1. Updated dart_ping package version to 7.0.1. +1. **Breaking change**. Bump minimum dart version to 2.17.0. -2. Updated test package version to 1.21.4. +2. Updated dart_ping package version to 7.0.1. + +3. Updated test package version to 1.21.4. ## 1.0.8 diff --git a/pubspec.yaml b/pubspec.yaml index c5df4f5..db787cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,12 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 1.0.9 +version: 2.0.0 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools homepage: https://github.com/git-elliot/network_tools environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" dependencies: # Multi-platform network ping utility. From 42987e9215b23075c1afff86e3b14ed3bc5a60e7 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 04:04:57 +0300 Subject: [PATCH 06/36] Added a function to find some of the mdns devices on the network --- network_tools/lib/src/host_scanner.dart | 2 +- .../lib/src/list_of_srv_records.dart | 23 +++++ network_tools/lib/src/mdns_scanner.dart | 83 +++++++++++++++++++ network_tools/lib/src/models/active_host.dart | 13 ++- network_tools/lib/src/models/mdns_info.dart | 16 ++++ network_tools/pubspec.yaml | 3 +- 6 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 network_tools/lib/src/list_of_srv_records.dart create mode 100644 network_tools/lib/src/mdns_scanner.dart create mode 100644 network_tools/lib/src/models/mdns_info.dart diff --git a/network_tools/lib/src/host_scanner.dart b/network_tools/lib/src/host_scanner.dart index d7b5229..e6cc465 100644 --- a/network_tools/lib/src/host_scanner.dart +++ b/network_tools/lib/src/host_scanner.dart @@ -80,7 +80,7 @@ class HostScanner { final Duration? time = response.time; if (time != null) { final ActiveHost tempActiveHost = - ActiveHost(host, i, ActiveHost.generic, pingData); + ActiveHost(host, ActiveHost.generic, pingData); activeHostsController.add(tempActiveHost); return tempActiveHost; } diff --git a/network_tools/lib/src/list_of_srv_records.dart b/network_tools/lib/src/list_of_srv_records.dart new file mode 100644 index 0000000..ac9507e --- /dev/null +++ b/network_tools/lib/src/list_of_srv_records.dart @@ -0,0 +1,23 @@ +List srvRecordsList = [ + '_uscan._tcp', // Any HP-compatible network scanners + '_uscans._tcp', // Any SSL/TLS-capable HP-compatible network scanners + '_privet._tcp', // Any Google CloudPrint-capable printers or print services + '_http-alt._tcp', + '_scanner._tcp', // Are there any Bonjour-capable scanners + '_home-assistant._tcp', + '_pdl-datastream._tcp', // Any HP JetDirect-style network printers + '_ipp._tcp', // Are there any printers using the IPP protocol + '_ipps._tcp', // Any SSL/TLS capable IPP printers + '_http._tcp', + '_ldap._tcp', + '_gc._tcp', + '_kerberos._tcp', + '_kpasswd._tcp', + '_airplay._tcp', // Any Apple AirPlay-capable video displays here_ipps + '_raop._tcp', // Any Apple AirPlay-capable audio devices + '_ippusb._tcp', // Are there any shared printers that are using the IPP-over-USB protocol, i.e. USB-connected printers shared by a Mac + '_printer._tcp', // Any kinds of shared printers at all + '_ptp._tcp', // Any devices supporting the Picture Transfer Protocol over this network + '_googlecast._tcp', // Is there a ChromeCast-capable device in this network + '_airport._tcp', // Any Apple AirPort WiFi APs +]; diff --git a/network_tools/lib/src/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner.dart new file mode 100644 index 0000000..1451268 --- /dev/null +++ b/network_tools/lib/src/mdns_scanner.dart @@ -0,0 +1,83 @@ +import 'dart:io'; + +import 'package:dart_ping/dart_ping.dart'; +import 'package:multicast_dns/multicast_dns.dart'; +import 'package:network_tools/network_tools.dart'; +import 'package:network_tools/src/list_of_srv_records.dart'; +import 'package:network_tools/src/models/mdns_info.dart'; + +class MdnsScanner { + /// This method searching for all the mdns devices in the network. + /// The implementation is **Lacking!** and will not find all the results + /// that actual exist in the network!, only some of them. + static Future> searchMdnsDevices() async { + final List>> activeHostListsFuture = []; + for (final String srvRecord in srvRecordsList) { + activeHostListsFuture.add(_findingMdnsWithIp(srvRecord)); + } + + final List activeHostList = []; + + for (final Future> activeHostListFuture + in activeHostListsFuture) { + activeHostList.addAll(await activeHostListFuture); + } + + return activeHostList; + } + + static Future> _findingMdnsWithIp(String serviceType) async { + final List mdnsFoundList = []; + + final MDnsClient client = MDnsClient(); + await client.start(); + + await for (final PtrResourceRecord ptr in client.lookup( + ResourceRecordQuery.serverPointer(serviceType), + )) { + await for (final SrvResourceRecord srv + in client.lookup( + ResourceRecordQuery.service(ptr.domainName), + )) { + final MdnsInfo mdnsFound = MdnsInfo( + mdnsName: srv.target, + mdnsPort: srv.port, + mdnsDomainName: ptr.domainName, + mdnsServiceType: serviceType, + ); + mdnsFoundList.add(mdnsFound); + } + } + client.stop(); + + final List listOfActiveHost = []; + for (final MdnsInfo foundMdns in mdnsFoundList) { + final String hostIp = + (await InternetAddress.lookup(foundMdns.mdnsName))[0].address; + final ActiveHost tempHost = ActiveHost( + hostIp, + ActiveHost.generic, + await getPingData(hostIp), + ); + listOfActiveHost.add(tempHost); + } + + return listOfActiveHost; + } + + static Future getPingData(String host) async { + const int timeoutInSeconds = 1; + + await for (final PingData pingData + in Ping(host, count: 1, timeout: timeoutInSeconds).stream) { + final PingResponse? response = pingData.response; + if (response != null) { + final Duration? time = response.time; + if (time != null) { + return pingData; + } + } + } + return const PingData(); + } +} diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index 806a410..f29d6e9 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -1,16 +1,25 @@ import 'package:dart_ping/dart_ping.dart'; +import 'package:network_tools/src/models/mdns_info.dart'; /// ActiveHost which implements comparable /// By default sort by hostId ascending class ActiveHost extends Comparable { - ActiveHost(this._ip, this.hostId, this._make, this._pingData); + ActiveHost( + this._ip, + this._make, + this._pingData, { + this.mdnsInfo, + }) { + hostId = int.parse(_ip.substring(_ip.lastIndexOf('.') + 1, _ip.length)); + } static const generic = 'Generic Device'; static const router = 'Router'; final String _ip; - int hostId; + late int hostId; final String _make; final PingData _pingData; + MdnsInfo? mdnsInfo; String get ip => _ip; String get make => _make; diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart new file mode 100644 index 0000000..45a1b81 --- /dev/null +++ b/network_tools/lib/src/models/mdns_info.dart @@ -0,0 +1,16 @@ +class MdnsInfo { + MdnsInfo({ + required this.mdnsName, + required this.mdnsPort, + required this.mdnsDomainName, + required this.mdnsServiceType, + }); + + /// Also can be called target + String mdnsName; + int mdnsPort; + + /// Also can be called bundleId + String mdnsDomainName; + String mdnsServiceType; +} diff --git a/network_tools/pubspec.yaml b/network_tools/pubspec.yaml index ddbc89d..502e203 100644 --- a/network_tools/pubspec.yaml +++ b/network_tools/pubspec.yaml @@ -14,6 +14,8 @@ dependencies: intl: ^0.17.0 # Debugging and error logging. logging: ^1.0.2 + # Performing mDNS queries (e.g. Bonjour, Avahi). + multicast_dns: ^0.3.2+1 # Cross-platform 'dart:io' that works in all platforms. universal_io: ^2.0.4 @@ -22,4 +24,3 @@ dev_dependencies: lint: ^1.8.2 # Writing and running Dart tests. test: ^1.21.4 - From eb0c466e8d1bb0d12f01426d3185e9fcd8b8b6ce Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 11:11:23 +0300 Subject: [PATCH 07/36] Added todo part for searchMdnsDevices and more srv record. --- network_tools/lib/src/list_of_srv_records.dart | 1 + network_tools/lib/src/mdns_scanner.dart | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/network_tools/lib/src/list_of_srv_records.dart b/network_tools/lib/src/list_of_srv_records.dart index ac9507e..76f52bf 100644 --- a/network_tools/lib/src/list_of_srv_records.dart +++ b/network_tools/lib/src/list_of_srv_records.dart @@ -20,4 +20,5 @@ List srvRecordsList = [ '_ptp._tcp', // Any devices supporting the Picture Transfer Protocol over this network '_googlecast._tcp', // Is there a ChromeCast-capable device in this network '_airport._tcp', // Any Apple AirPort WiFi APs + '_esphomelib._tcp' ]; diff --git a/network_tools/lib/src/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner.dart index 1451268..af77b16 100644 --- a/network_tools/lib/src/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner.dart @@ -8,8 +8,10 @@ import 'package:network_tools/src/models/mdns_info.dart'; class MdnsScanner { /// This method searching for all the mdns devices in the network. - /// The implementation is **Lacking!** and will not find all the results - /// that actual exist in the network!, only some of them. + /// TODO: The implementation is **Lacking!** and will not find all the + /// TODO: results that actual exist in the network!, only some of them. + /// TODO: This is because missing functionality in dart + /// TODO: https://github.com/flutter/flutter/issues/97210 static Future> searchMdnsDevices() async { final List>> activeHostListsFuture = []; for (final String srvRecord in srvRecordsList) { From 81e43c26dd3f7d8e0bcde1c922a3bc17250fb52c Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 11:27:31 +0300 Subject: [PATCH 08/36] Inserting the name from the mdns into _make var in ActiveHost --- network_tools/lib/src/mdns_scanner.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/network_tools/lib/src/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner.dart index af77b16..e38533b 100644 --- a/network_tools/lib/src/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner.dart @@ -56,10 +56,15 @@ class MdnsScanner { for (final MdnsInfo foundMdns in mdnsFoundList) { final String hostIp = (await InternetAddress.lookup(foundMdns.mdnsName))[0].address; + final String fullMdnsName = foundMdns.mdnsName; + final String mdnsNameOnlyStart = + fullMdnsName.substring(0, fullMdnsName.indexOf('.')); + final ActiveHost tempHost = ActiveHost( hostIp, - ActiveHost.generic, + mdnsNameOnlyStart, await getPingData(hostIp), + mdnsInfo: foundMdns, ); listOfActiveHost.add(tempHost); } From 35f92b15560e30934da7e0b187c6751c52d14e2d Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 11:49:23 +0300 Subject: [PATCH 09/36] More srv records. --- network_tools/lib/src/list_of_srv_records.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/network_tools/lib/src/list_of_srv_records.dart b/network_tools/lib/src/list_of_srv_records.dart index 76f52bf..0cf0460 100644 --- a/network_tools/lib/src/list_of_srv_records.dart +++ b/network_tools/lib/src/list_of_srv_records.dart @@ -20,5 +20,8 @@ List srvRecordsList = [ '_ptp._tcp', // Any devices supporting the Picture Transfer Protocol over this network '_googlecast._tcp', // Is there a ChromeCast-capable device in this network '_airport._tcp', // Any Apple AirPort WiFi APs - '_esphomelib._tcp' + '_esphomelib._tcp', + '_mqtt._tcp', + '_autodiscover._tcp', + '_sip._tcp', ]; From d4bfb579ec832f509483909dbfb4e403c067c520 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 11:52:46 +0300 Subject: [PATCH 10/36] More srv records. --- network_tools/lib/src/list_of_srv_records.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/network_tools/lib/src/list_of_srv_records.dart b/network_tools/lib/src/list_of_srv_records.dart index 0cf0460..77c3854 100644 --- a/network_tools/lib/src/list_of_srv_records.dart +++ b/network_tools/lib/src/list_of_srv_records.dart @@ -1,3 +1,5 @@ +/// Service record list that is including the protocol, mostly _tcp, _udp may +/// not work List srvRecordsList = [ '_uscan._tcp', // Any HP-compatible network scanners '_uscans._tcp', // Any SSL/TLS-capable HP-compatible network scanners @@ -24,4 +26,5 @@ List srvRecordsList = [ '_mqtt._tcp', '_autodiscover._tcp', '_sip._tcp', + '_minecraft._tcp' ]; From 6d50eaa5e7cb2ccd44b2c50d05a00758c5eba9c2 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 13:56:03 +0300 Subject: [PATCH 11/36] Added mdns scanner to example and Changelog. Changed network_tool version to 2.1.0 --- network_tools/CHANGELOG.md | 28 ++++++------ network_tools/README.md | 47 +++++++++++++-------- network_tools/analysis_options.yaml | 1 + network_tools/example/main.dart | 3 +- network_tools/example/mdns_scan.dart | 12 ++++++ network_tools/lib/src/mdns_scanner.dart | 5 +-- network_tools/lib/src/models/mdns_info.dart | 6 +++ network_tools/pubspec.yaml | 2 +- 8 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 network_tools/example/mdns_scan.dart diff --git a/network_tools/CHANGELOG.md b/network_tools/CHANGELOG.md index 06cbde1..c3b491e 100644 --- a/network_tools/CHANGELOG.md +++ b/network_tools/CHANGELOG.md @@ -1,38 +1,42 @@ # Change Log +## 2.1.0 + +Added partly support for searching mdns devices. + ## 2.0.0 -1. **Breaking change**. Bump minimum dart version to 2.17.0. +**Breaking change**. Bump minimum dart version to 2.17.0. -2. Updated dart_ping package version to 7.0.1. +Updated dart_ping package version to 7.0.1. -3. Updated test package version to 1.21.4. +Updated test package version to 1.21.4. ## 1.0.8 Fixes -1. #13: Add logs using logging package +Add logs using logging package #13. -2. #20: Even more points in pub.dev page +Even more points in pub.dev page #20. ## 1.0.7 Fixed -1. Saving the response time from each device #9 +Saving the response time from each device #9. -2. Example crash on Windows #14 +Example crash on Windows #14. -3. Bump package version #15 +Bump package version #15. ## 0.0.6 -Resolved issue #9 and #10 +Resolved issue #9 and #10. ## 0.0.5 -Resolved issue #1 +Resolved issue #1. ## 0.0.4 @@ -44,8 +48,8 @@ Subnet and Port range added. ## 0.0.2 -Added example and followed pub conventions +Added example and followed pub conventions. ## 0.0.1 -* PortScanner and HostScanner +PortScanner and HostScanner. diff --git a/network_tools/README.md b/network_tools/README.md index bec3155..ada7426 100644 --- a/network_tools/README.md +++ b/network_tools/README.md @@ -11,9 +11,9 @@ Network Tools Supported 2. Range 3. Custom -What's not supported +Partly Work: -1. Mac Address of other devices on network +1. Mdns Scanner ## Import package in your app @@ -48,41 +48,52 @@ import 'package:network_tools/network_tools.dart'; ### Port Scanner ```dart - //1. Range - String target = '192.168.1.1'; - PortScanner.discover(target, startPort: 1, endPort: 1024, + //1. Range + String target = '192.168.1.1'; + PortScanner.discover(target, startPort: 1, endPort: 1024, progressCallback: (progress) { print('Progress for port discovery : $progress'); - }).listen((event) { + }).listen((event) { if (event.isOpen) { print('Found open port : $event'); } - }, onDone: () { + }, onDone: () { print('Scan completed'); - }); - //2. Single - bool isOpen = PortScanner.isOpen(target,80); - //3. Custom - PortScanner.customDiscover(target, portList : const [22, 80, 139]); + }); + //2. Single + bool isOpen = PortScanner.isOpen(target,80); + //3. Custom + PortScanner.customDiscover(target, portList : const [22, 80, 139]); +``` +### Mdns Scanner + +```dart + for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { + final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; + print( + 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + ); + } ``` + ### Run examples 1. Run host scan : `dart example/host_scan.dart` 2. Run port scan : `dart example/port_scan.dart` +3. Run mdns scan : `dart example/mdns_scan.dart` ## Enable Debugging Add this code to your `main.dart` file ```dart -Logger.root.level = Level.FINE; //set to finest for detailed log - Logger.root.onRecord.listen((record) { - print( - '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}'); - }); - + Logger.root.level = Level.FINE; //set to finest for detailed log + Logger.root.onRecord.listen((record) { + print( + '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}'); + }); ``` ## Sample App diff --git a/network_tools/analysis_options.yaml b/network_tools/analysis_options.yaml index d95779a..34b4773 100644 --- a/network_tools/analysis_options.yaml +++ b/network_tools/analysis_options.yaml @@ -20,6 +20,7 @@ analyzer: - "**/*.pbgrpc.dart" - "**/*.pbjson.dart" - "**/*.gr.dart" + - "**/*.md" linter: rules: diff --git a/network_tools/example/main.dart b/network_tools/example/main.dart index d9635a6..b272d94 100644 --- a/network_tools/example/main.dart +++ b/network_tools/example/main.dart @@ -1,4 +1,5 @@ -void main() { +Future main() async { print("Run host scan : 'dart example/host_scan.dart'"); print("Run port scan : 'dart example/port_scan.dart'"); + print("Run mdns scan : 'dart example/mdns_scan.dart'"); } diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart new file mode 100644 index 0000000..f995299 --- /dev/null +++ b/network_tools/example/mdns_scan.dart @@ -0,0 +1,12 @@ +import 'package:network_tools/network_tools.dart'; +import 'package:network_tools/src/mdns_scanner.dart'; +import 'package:network_tools/src/models/mdns_info.dart'; + +Future main() async { + for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { + final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; + print( + 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + ); + } +} diff --git a/network_tools/lib/src/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner.dart index e38533b..aeadb30 100644 --- a/network_tools/lib/src/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner.dart @@ -56,13 +56,10 @@ class MdnsScanner { for (final MdnsInfo foundMdns in mdnsFoundList) { final String hostIp = (await InternetAddress.lookup(foundMdns.mdnsName))[0].address; - final String fullMdnsName = foundMdns.mdnsName; - final String mdnsNameOnlyStart = - fullMdnsName.substring(0, fullMdnsName.indexOf('.')); final ActiveHost tempHost = ActiveHost( hostIp, - mdnsNameOnlyStart, + foundMdns.getOnlyTheStartOfMdnsName(), await getPingData(hostIp), mdnsInfo: foundMdns, ); diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart index 45a1b81..b7d22b7 100644 --- a/network_tools/lib/src/models/mdns_info.dart +++ b/network_tools/lib/src/models/mdns_info.dart @@ -12,5 +12,11 @@ class MdnsInfo { /// Also can be called bundleId String mdnsDomainName; + + /// Srv record of the dns String mdnsServiceType; + + String getOnlyTheStartOfMdnsName() { + return mdnsName.substring(0, mdnsName.indexOf('.')); + } } diff --git a/network_tools/pubspec.yaml b/network_tools/pubspec.yaml index 502e203..501b187 100644 --- a/network_tools/pubspec.yaml +++ b/network_tools/pubspec.yaml @@ -1,6 +1,6 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 2.0.0 +version: 2.1.0 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools/tree/main/network_tools From 53f368f45e1ff05d722df5f64ca1dc1d38d5acbb Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 14:02:07 +0300 Subject: [PATCH 12/36] Remove Future from main function in example folder --- network_tools/example/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network_tools/example/main.dart b/network_tools/example/main.dart index b272d94..09e0de3 100644 --- a/network_tools/example/main.dart +++ b/network_tools/example/main.dart @@ -1,4 +1,4 @@ -Future main() async { +void main() { print("Run host scan : 'dart example/host_scan.dart'"); print("Run port scan : 'dart example/port_scan.dart'"); print("Run mdns scan : 'dart example/mdns_scan.dart'"); From 2254177af737f80aaf86553bbe5e8aea65d38db0 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 19:32:43 +0300 Subject: [PATCH 13/36] Made searching for mdns process better for Linux if avahi-browse or mdns-scan is installed on it. --- network_tools/example/mdns_scan.dart | 2 +- .../get_srv_list_by_os/srv_list.dart | 15 +++ .../get_srv_list_by_os/srv_list_linux.dart | 105 ++++++++++++++++++ .../list_of_srv_records.dart | 0 .../src/{ => mdns_scanner}/mdns_scanner.dart | 26 ++++- network_tools/lib/src/models/mdns_info.dart | 2 + network_tools/pubspec.yaml | 2 + 7 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart create mode 100644 network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart rename network_tools/lib/src/{ => mdns_scanner}/list_of_srv_records.dart (100%) rename network_tools/lib/src/{ => mdns_scanner}/mdns_scanner.dart (74%) diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart index f995299..becac00 100644 --- a/network_tools/example/mdns_scan.dart +++ b/network_tools/example/mdns_scan.dart @@ -1,5 +1,5 @@ import 'package:network_tools/network_tools.dart'; -import 'package:network_tools/src/mdns_scanner.dart'; +import 'package:network_tools/src/mdns_scanner/mdns_scanner.dart'; import 'package:network_tools/src/models/mdns_info.dart'; Future main() async { diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart new file mode 100644 index 0000000..de43751 --- /dev/null +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart @@ -0,0 +1,15 @@ +import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart'; +import 'package:universal_io/io.dart'; + +/// This class is common interface for executing functions on different os +class SrvList { + /// Will get the srv record in the local network. + static Future?> getSrvRecordList() async { + if (Platform.isLinux) { + return SrvListLinux.getSrvRecordList(); + } + + // Get srv record list is not supported on this os + return []; + } +} diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart new file mode 100644 index 0000000..ee21287 --- /dev/null +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart @@ -0,0 +1,105 @@ +import 'dart:collection'; + +import 'package:process_run/shell.dart'; + +class SrvListLinux { + static Future?> getSrvRecordList() async { + final HashSet srvList = HashSet(); + + try { + srvList.addAll(await runAvahiBrowseCommand()); + srvList.addAll(await runMdnsScanCommand()); + } catch (e) { + print('Error:\n$e'); + } + return srvList.toList(); + } + + /// Will try to get results from avahi-browse, it is not installed by default + /// on all Linux machines + static Future> runAvahiBrowseCommand() async { + final shell = Shell(verbose: false); + + final List srvListAvahi = []; + + List resultForEachLine = []; + + await shell.run( + ''' +timeout 2s avahi-browse --all -p +''', + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout + + final String? resultStderr = error.result?.stderr.toString(); + if (resultStderr != null && + resultStderr.contains('No such file or directory')) { + print( + 'You can make the mdns process better by installing `avahi-browse`', + ); + return []; + } + final String? resultStdout = error.result?.stdout.toString(); + if (resultStdout == null) { + return []; + } + resultForEachLine = resultStdout.split('\n'); + + return []; + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split(';'); + if (lineSeparated.length >= 6) { + final String srvString = lineSeparated[lineSeparated.length - 2]; + if (!srvString.contains(' ')) { + srvListAvahi.add(srvString); + } + } + } + return srvListAvahi; + } + + /// Will try to get results from mdns-scan, it is not installed by default + /// on all Linux machines + static Future> runMdnsScanCommand() async { + final shell = Shell(verbose: false); + + final List srvListMdnsScan = []; + + List resultForEachLine = []; + + await shell.run( + ''' +timeout 2s mdns-scan +''', + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout + + final String? resultStderr = error.result?.stderr.toString(); + + if (resultStderr == null || + (resultStderr.contains('No such file or directory'))) { + print( + 'You can make the mdns process better by installing `mdns-scan`', + ); + return []; + } + resultForEachLine = resultStderr.split('\n'); + + return []; + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split('.'); + if (lineSeparated.length >= 4) { + final String srvString = + '${lineSeparated[lineSeparated.length - 3]}.${lineSeparated[lineSeparated.length - 2]}'; + if (!srvString.contains(' ') && srvString != '.') { + srvListMdnsScan.add(srvString); + } + } + } + return srvListMdnsScan; + } +} diff --git a/network_tools/lib/src/list_of_srv_records.dart b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart similarity index 100% rename from network_tools/lib/src/list_of_srv_records.dart rename to network_tools/lib/src/mdns_scanner/list_of_srv_records.dart diff --git a/network_tools/lib/src/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart similarity index 74% rename from network_tools/lib/src/mdns_scanner.dart rename to network_tools/lib/src/mdns_scanner/mdns_scanner.dart index aeadb30..bdf16ff 100644 --- a/network_tools/lib/src/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -3,18 +3,35 @@ import 'dart:io'; import 'package:dart_ping/dart_ping.dart'; import 'package:multicast_dns/multicast_dns.dart'; import 'package:network_tools/network_tools.dart'; -import 'package:network_tools/src/list_of_srv_records.dart'; +import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list.dart'; +import 'package:network_tools/src/mdns_scanner/list_of_srv_records.dart'; import 'package:network_tools/src/models/mdns_info.dart'; class MdnsScanner { /// This method searching for all the mdns devices in the network. + /// Shows only results for IPv4. /// TODO: The implementation is **Lacking!** and will not find all the /// TODO: results that actual exist in the network!, only some of them. /// TODO: This is because missing functionality in dart /// TODO: https://github.com/flutter/flutter/issues/97210 + /// TODO: In some cases we resolve this missing functionality using + /// TODO: specific os tools. static Future> searchMdnsDevices() async { + List srvRecordListToSearchIn; + + final List? srvRecordsFromOs = await SrvList.getSrvRecordList(); + + if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) { + print("Commands for os couldn't be found"); + srvRecordListToSearchIn = srvRecordsList; + } else { + srvRecordListToSearchIn = srvRecordsFromOs; + } + + await Future.delayed(const Duration(milliseconds: 5)); + final List>> activeHostListsFuture = []; - for (final String srvRecord in srvRecordsList) { + for (final String srvRecord in srvRecordListToSearchIn) { activeHostListsFuture.add(_findingMdnsWithIp(srvRecord)); } @@ -42,10 +59,11 @@ class MdnsScanner { ResourceRecordQuery.service(ptr.domainName), )) { final MdnsInfo mdnsFound = MdnsInfo( - mdnsName: srv.target, + mdnsName: srv.name, mdnsPort: srv.port, mdnsDomainName: ptr.domainName, mdnsServiceType: serviceType, + mdnsSrvTarget: srv.target, ); mdnsFoundList.add(mdnsFound); } @@ -55,7 +73,7 @@ class MdnsScanner { final List listOfActiveHost = []; for (final MdnsInfo foundMdns in mdnsFoundList) { final String hostIp = - (await InternetAddress.lookup(foundMdns.mdnsName))[0].address; + (await InternetAddress.lookup(foundMdns.mdnsSrvTarget))[0].address; final ActiveHost tempHost = ActiveHost( hostIp, diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart index b7d22b7..e121aff 100644 --- a/network_tools/lib/src/models/mdns_info.dart +++ b/network_tools/lib/src/models/mdns_info.dart @@ -4,10 +4,12 @@ class MdnsInfo { required this.mdnsPort, required this.mdnsDomainName, required this.mdnsServiceType, + required this.mdnsSrvTarget, }); /// Also can be called target String mdnsName; + String mdnsSrvTarget; int mdnsPort; /// Also can be called bundleId diff --git a/network_tools/pubspec.yaml b/network_tools/pubspec.yaml index 501b187..12dd246 100644 --- a/network_tools/pubspec.yaml +++ b/network_tools/pubspec.yaml @@ -16,6 +16,8 @@ dependencies: logging: ^1.0.2 # Performing mDNS queries (e.g. Bonjour, Avahi). multicast_dns: ^0.3.2+1 + # Process run helpers + process_run: ^0.12.3+2 # Cross-platform 'dart:io' that works in all platforms. universal_io: ^2.0.4 From e5fda64e5ba4722a058aabc63b559112a8450ae9 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 19:33:34 +0300 Subject: [PATCH 14/36] Removing print --- network_tools/lib/src/mdns_scanner/mdns_scanner.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index bdf16ff..790f3cf 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -22,7 +22,6 @@ class MdnsScanner { final List? srvRecordsFromOs = await SrvList.getSrvRecordList(); if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) { - print("Commands for os couldn't be found"); srvRecordListToSearchIn = srvRecordsList; } else { srvRecordListToSearchIn = srvRecordsFromOs; From 7b7108791e6474534668b00a23c11d77cd52b0c7 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 19:49:07 +0300 Subject: [PATCH 15/36] Added small comment for future mac implementation. --- .../lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart index de43751..d7d3207 100644 --- a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart @@ -8,6 +8,12 @@ class SrvList { if (Platform.isLinux) { return SrvListLinux.getSrvRecordList(); } + // else if (Platform.isMacOS){ + // // I think the command should be dns-sd so + // // dns-sd -B _services._dns-sd._udp local. + // // and + // // dns-sd -B _ipp._tcp local. + // } // Get srv record list is not supported on this os return []; From 90a524fa8ea7551c8c7f157f52b33ad5c8461f52 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sun, 24 Jul 2022 19:57:20 +0300 Subject: [PATCH 16/36] Small fix to srv results as avahi command does not return all of them. --- .../src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart index ee21287..e4c3a14 100644 --- a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart @@ -7,7 +7,9 @@ class SrvListLinux { final HashSet srvList = HashSet(); try { - srvList.addAll(await runAvahiBrowseCommand()); + // Using this command is missing some results and could make the rest of + // the program not search all needed srv types. + // srvList.addAll(await runAvahiBrowseCommand()); srvList.addAll(await runMdnsScanCommand()); } catch (e) { print('Error:\n$e'); From fa9e1bb258ae22c71d4784670acb6e6827e49939 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Mon, 25 Jul 2022 04:03:20 +0300 Subject: [PATCH 17/36] Added a lot entry's to the tcpSrvRecords list, added udpSrvRecordList. --- .../src/mdns_scanner/list_of_srv_records.dart | 72 ++++++++++++++++--- .../lib/src/mdns_scanner/mdns_scanner.dart | 2 +- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart index 77c3854..b522308 100644 --- a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart +++ b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart @@ -1,6 +1,6 @@ /// Service record list that is including the protocol, mostly _tcp, _udp may /// not work -List srvRecordsList = [ +List tcpSrvRecordsList = [ '_uscan._tcp', // Any HP-compatible network scanners '_uscans._tcp', // Any SSL/TLS-capable HP-compatible network scanners '_privet._tcp', // Any Google CloudPrint-capable printers or print services @@ -8,23 +8,73 @@ List srvRecordsList = [ '_scanner._tcp', // Are there any Bonjour-capable scanners '_home-assistant._tcp', '_pdl-datastream._tcp', // Any HP JetDirect-style network printers - '_ipp._tcp', // Are there any printers using the IPP protocol - '_ipps._tcp', // Any SSL/TLS capable IPP printers - '_http._tcp', + '_ipp._tcp', // Are there any printers using the IPP protocol // "domain": "ipp" + '_ipps._tcp', // Any SSL/TLS capable IPP printers // "domain": "ipp" + '_http._tcp', // "domain": "bosch_shc", "name": "bosch shc*" '_ldap._tcp', '_gc._tcp', '_kerberos._tcp', '_kpasswd._tcp', - '_airplay._tcp', // Any Apple AirPlay-capable video displays here_ipps - '_raop._tcp', // Any Apple AirPlay-capable audio devices + '_airplay._tcp', // Any Apple AirPlay-capable video displays here_ipps // [ { "domain": "apple_tv", "properties": { "model": "appletv*" } }, { "domain": "apple_tv", "properties": { "model": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } }, { "domain": "samsungtv", "properties": { "manufacturer": "samsung*" } } ] + '_raop._tcp', // Any Apple AirPlay-capable audio devices [ { "domain": "apple_tv", "properties": { "am": "appletv*" } }, { "domain": "apple_tv", "properties": { "am": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } } ], '_ippusb._tcp', // Are there any shared printers that are using the IPP-over-USB protocol, i.e. USB-connected printers shared by a Mac - '_printer._tcp', // Any kinds of shared printers at all + '_printer._tcp', // Any kinds of shared printers at all "domain": "brother", "name": "brother*" '_ptp._tcp', // Any devices supporting the Picture Transfer Protocol over this network - '_googlecast._tcp', // Is there a ChromeCast-capable device in this network - '_airport._tcp', // Any Apple AirPort WiFi APs - '_esphomelib._tcp', + '_googlecast._tcp', // Is there a ChromeCast-capable device in this network "domain": "cast" + '_airport._tcp', // Any Apple AirPort WiFi APs // "domain": "apple_tv" + '_esphomelib._tcp', // [ { "domain": "esphome" }, { "domain": "zha", "name": "tube*" } ] '_mqtt._tcp', '_autodiscover._tcp', '_sip._tcp', - '_minecraft._tcp' + '_minecraft._tcp', + '_Volumio._tcp', // "domain": "volumio" + '_api._tcp', // [ { "domain": "baf", "properties": { "model": "haiku*" } }, { "domain": "baf", "properties": { "model": "i6*" } } ] + '_appletv-v2._tcp', // "domain": "apple_tv" + '_axis-video._tcp', // [ { "domain": "axis", "properties": { "macaddress": "00408c*" } }, { "domain": "axis", "properties": { "macaddress": "accc8e*" } }, { "domain": "axis", "properties": { "macaddress": "b8a44f*" } }, { "domain": "doorbird", "properties": { "macaddress": "1ccae3*"} } ], + '_bond._tcp', // "domain": "bond" + '_companion-link._tcp', // "domain": "apple_tv" + '_daap._tcp', // "domain": "forked_daapd" + '_dkapi._tcp', // "domain": "daikin" + '_dvl-deviceapi._tcp', // [ { "domain": "devolo_home_control" }, { "domain": "devolo_home_network", "properties": { "MT": "*" } } ] + '_easylink._tcp', // "domain": "modern_forms", "name": "wac*" + '_elg._tcp', // "domain": "elgato" + '_enphase-envoy._tcp', // "domain": "enphase_envoy" + '_fbx-api._tcp', // "domain": "freebox" + '_hap._tcp', // [ { "domain": "homekit_controller" }, { "domain": "zwave_me", "name": "*z.wave-me*" } ] + '_homekit._tcp', // "domain": "homekit" + '_hscp._tcp', // "domain": "apple_tv" + '_hue._tcp', // "domain": "hue" + '_hwenergy._tcp', // "domain": "homewizard", + '_kizbox._tcp', // "domain": "overkiz", "name": "gateway*" + '_leap._tcp', // "domain": "lutron_caseta" + '_lookin._tcp', // "domain": "lookin" + '_mediaremotetv._tcp', // "domain": "apple_tv" + '_nanoleafapi._tcp', // "domain": "nanoleaf" + '_nanoleafms._tcp', // "domain": "nanoleaf" + '_nut._tcp', // "domain": "nut" + '_octoprint._tcp', // "domain": "octoprint" + '_plexmediasvr._tcp', // "domain": "plex" + '_plugwise._tcp', // "domain": "plugwise" + '_powerview._tcp', // "domain": "hunterdouglas_powerview" + '_sideplay._tcp', // { "domain": "ecobee", "properties": { "mdl": "eb-*" } }, { "domain": "ecobee", "properties": { "mdl": "ecobee*" } } + '_sonos._tcp', // "domain": "sonos" + '_soundtouch._tcp', // "domain": "soundtouch" + '_spotify-connect', // "domain": "spotify" + '_ssh._tcp', // { "domain": "smappee", "name": "smappee1*" }, { "domain": "smappee", "name": "smappee2*" }, { "domain": "smappee", "name": "smappee50*" } + '_system-bridge._tcp', // "domain": "system_bridge" + '_touch-able._tcp', // "domain": "apple_tv" + '_viziocast._tcp', // "domain": "vizio" + '_wled._tcp', // "domain": "wled" + '_xbmc-jsonrpc-h._tcp', // "domain": "kodi" + '_zigate-zigbee-gateway._tcp', // "domain": "zha", "name": "*zigate*" + '_zwave-js-server._tcp', // "domain": "zwave_js" + '_axis-video._tcp', // "properties": { "macaddress": "00408c*" } "properties": { "macaddress": "accc8e*" } "properties": { "macaddress": "b8a44f*" } +]; + +List udpSrvRecordsList = [ + '_api._udp', // "domain": "guardian" + '_hap._udp', // "domain": "homekit_controller" + '_miio._udp', // [ { "domain": "xiaomi_aqara" }, { "domain": "xiaomi_miio" }, { "domain": "yeelight", "name": "yeelink-*" } ] + '_sleep-proxy._udp', // "domain": "apple_tv" + '_system-bridge._udp', ]; diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 790f3cf..0968c2c 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -22,7 +22,7 @@ class MdnsScanner { final List? srvRecordsFromOs = await SrvList.getSrvRecordList(); if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) { - srvRecordListToSearchIn = srvRecordsList; + srvRecordListToSearchIn = tcpSrvRecordsList; } else { srvRecordListToSearchIn = srvRecordsFromOs; } From 9e02c6f6c06bc1d84b306a486e7c457fc5f8067f Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Mon, 25 Jul 2022 10:49:20 +0300 Subject: [PATCH 18/36] Added the udp list to the search. Small fix for multiple devices with the same mDNS name different address. --- .../lib/src/mdns_scanner/mdns_scanner.dart | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 0968c2c..b392d86 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -23,6 +23,7 @@ class MdnsScanner { if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) { srvRecordListToSearchIn = tcpSrvRecordsList; + srvRecordListToSearchIn.addAll(udpSrvRecordsList); } else { srvRecordListToSearchIn = srvRecordsFromOs; } @@ -71,16 +72,21 @@ class MdnsScanner { final List listOfActiveHost = []; for (final MdnsInfo foundMdns in mdnsFoundList) { - final String hostIp = - (await InternetAddress.lookup(foundMdns.mdnsSrvTarget))[0].address; - - final ActiveHost tempHost = ActiveHost( - hostIp, - foundMdns.getOnlyTheStartOfMdnsName(), - await getPingData(hostIp), - mdnsInfo: foundMdns, - ); - listOfActiveHost.add(tempHost); + final List internetAddressList = + await InternetAddress.lookup(foundMdns.mdnsSrvTarget); + + // There can be multiple devices with the same name + for (final InternetAddress internetAddress in internetAddressList) { + final String hostIp = internetAddress.address; + + final ActiveHost tempHost = ActiveHost( + hostIp, + foundMdns.getOnlyTheStartOfMdnsName(), + await getPingData(hostIp), + mdnsInfo: foundMdns, + ); + listOfActiveHost.add(tempHost); + } } return listOfActiveHost; From 245e0e4a1a77d2e085e6ee31ad0169e25c01961d Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Tue, 26 Jul 2022 14:43:23 +0300 Subject: [PATCH 19/36] Made mdns_scanner accessible to users of the package. --- network_tools/lib/network_tools.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/network_tools/lib/network_tools.dart b/network_tools/lib/network_tools.dart index 70b9595..e81f45b 100644 --- a/network_tools/lib/network_tools.dart +++ b/network_tools/lib/network_tools.dart @@ -2,6 +2,7 @@ library network_tools; //TODO: add dartdocs export 'src/host_scanner.dart'; +export 'src/mdns_scanner/mdns_scanner.dart'; export 'src/models/active_host.dart'; export 'src/models/callbacks.dart'; export 'src/models/open_port.dart'; From bcbe83cd5510842086710f301d9d4973306a265d Mon Sep 17 00:00:00 2001 From: Guy Luz Date: Tue, 26 Jul 2022 19:21:09 +0300 Subject: [PATCH 20/36] Added some support for finding mdns (#36) * Updated dependencies * Added comments to each dependency * Decided to update min dart version to 2.17.0 (even though pub get didn't show any errors) because it is the min version in dart_ping 7.0.0 * Reverted min dart version back to 2.12.0 as it is not mandatory * Updated min dart version to 2.17.0. * Added a function to find some of the mdns devices on the network * Added todo part for searchMdnsDevices and more srv record. * Inserting the name from the mdns into _make var in ActiveHost * More srv records. * More srv records. * Added mdns scanner to example and Changelog. Changed network_tool version to 2.1.0 * Remove Future from main function in example folder * Made searching for mdns process better for Linux if avahi-browse or mdns-scan is installed on it. * Removing print * Added small comment for future mac implementation. * Small fix to srv results as avahi command does not return all of them. * Added a lot entry's to the tcpSrvRecords list, added udpSrvRecordList. * Added the udp list to the search. Small fix for multiple devices with the same mDNS name different address. * Made mdns_scanner accessible to users of the package. --- network_tools/CHANGELOG.md | 28 +++-- network_tools/README.md | 47 +++++--- network_tools/analysis_options.yaml | 1 + network_tools/example/main.dart | 1 + network_tools/example/mdns_scan.dart | 12 ++ network_tools/lib/network_tools.dart | 1 + network_tools/lib/src/host_scanner.dart | 2 +- .../get_srv_list_by_os/srv_list.dart | 21 ++++ .../get_srv_list_by_os/srv_list_linux.dart | 107 +++++++++++++++++ .../src/mdns_scanner/list_of_srv_records.dart | 80 +++++++++++++ .../lib/src/mdns_scanner/mdns_scanner.dart | 110 ++++++++++++++++++ network_tools/lib/src/models/active_host.dart | 13 ++- network_tools/lib/src/models/mdns_info.dart | 24 ++++ network_tools/pubspec.yaml | 7 +- 14 files changed, 419 insertions(+), 35 deletions(-) create mode 100644 network_tools/example/mdns_scan.dart create mode 100644 network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart create mode 100644 network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart create mode 100644 network_tools/lib/src/mdns_scanner/list_of_srv_records.dart create mode 100644 network_tools/lib/src/mdns_scanner/mdns_scanner.dart create mode 100644 network_tools/lib/src/models/mdns_info.dart diff --git a/network_tools/CHANGELOG.md b/network_tools/CHANGELOG.md index 06cbde1..c3b491e 100644 --- a/network_tools/CHANGELOG.md +++ b/network_tools/CHANGELOG.md @@ -1,38 +1,42 @@ # Change Log +## 2.1.0 + +Added partly support for searching mdns devices. + ## 2.0.0 -1. **Breaking change**. Bump minimum dart version to 2.17.0. +**Breaking change**. Bump minimum dart version to 2.17.0. -2. Updated dart_ping package version to 7.0.1. +Updated dart_ping package version to 7.0.1. -3. Updated test package version to 1.21.4. +Updated test package version to 1.21.4. ## 1.0.8 Fixes -1. #13: Add logs using logging package +Add logs using logging package #13. -2. #20: Even more points in pub.dev page +Even more points in pub.dev page #20. ## 1.0.7 Fixed -1. Saving the response time from each device #9 +Saving the response time from each device #9. -2. Example crash on Windows #14 +Example crash on Windows #14. -3. Bump package version #15 +Bump package version #15. ## 0.0.6 -Resolved issue #9 and #10 +Resolved issue #9 and #10. ## 0.0.5 -Resolved issue #1 +Resolved issue #1. ## 0.0.4 @@ -44,8 +48,8 @@ Subnet and Port range added. ## 0.0.2 -Added example and followed pub conventions +Added example and followed pub conventions. ## 0.0.1 -* PortScanner and HostScanner +PortScanner and HostScanner. diff --git a/network_tools/README.md b/network_tools/README.md index bec3155..ada7426 100644 --- a/network_tools/README.md +++ b/network_tools/README.md @@ -11,9 +11,9 @@ Network Tools Supported 2. Range 3. Custom -What's not supported +Partly Work: -1. Mac Address of other devices on network +1. Mdns Scanner ## Import package in your app @@ -48,41 +48,52 @@ import 'package:network_tools/network_tools.dart'; ### Port Scanner ```dart - //1. Range - String target = '192.168.1.1'; - PortScanner.discover(target, startPort: 1, endPort: 1024, + //1. Range + String target = '192.168.1.1'; + PortScanner.discover(target, startPort: 1, endPort: 1024, progressCallback: (progress) { print('Progress for port discovery : $progress'); - }).listen((event) { + }).listen((event) { if (event.isOpen) { print('Found open port : $event'); } - }, onDone: () { + }, onDone: () { print('Scan completed'); - }); - //2. Single - bool isOpen = PortScanner.isOpen(target,80); - //3. Custom - PortScanner.customDiscover(target, portList : const [22, 80, 139]); + }); + //2. Single + bool isOpen = PortScanner.isOpen(target,80); + //3. Custom + PortScanner.customDiscover(target, portList : const [22, 80, 139]); +``` +### Mdns Scanner + +```dart + for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { + final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; + print( + 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + ); + } ``` + ### Run examples 1. Run host scan : `dart example/host_scan.dart` 2. Run port scan : `dart example/port_scan.dart` +3. Run mdns scan : `dart example/mdns_scan.dart` ## Enable Debugging Add this code to your `main.dart` file ```dart -Logger.root.level = Level.FINE; //set to finest for detailed log - Logger.root.onRecord.listen((record) { - print( - '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}'); - }); - + Logger.root.level = Level.FINE; //set to finest for detailed log + Logger.root.onRecord.listen((record) { + print( + '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}'); + }); ``` ## Sample App diff --git a/network_tools/analysis_options.yaml b/network_tools/analysis_options.yaml index d95779a..34b4773 100644 --- a/network_tools/analysis_options.yaml +++ b/network_tools/analysis_options.yaml @@ -20,6 +20,7 @@ analyzer: - "**/*.pbgrpc.dart" - "**/*.pbjson.dart" - "**/*.gr.dart" + - "**/*.md" linter: rules: diff --git a/network_tools/example/main.dart b/network_tools/example/main.dart index d9635a6..09e0de3 100644 --- a/network_tools/example/main.dart +++ b/network_tools/example/main.dart @@ -1,4 +1,5 @@ void main() { print("Run host scan : 'dart example/host_scan.dart'"); print("Run port scan : 'dart example/port_scan.dart'"); + print("Run mdns scan : 'dart example/mdns_scan.dart'"); } diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart new file mode 100644 index 0000000..becac00 --- /dev/null +++ b/network_tools/example/mdns_scan.dart @@ -0,0 +1,12 @@ +import 'package:network_tools/network_tools.dart'; +import 'package:network_tools/src/mdns_scanner/mdns_scanner.dart'; +import 'package:network_tools/src/models/mdns_info.dart'; + +Future main() async { + for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { + final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; + print( + 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + ); + } +} diff --git a/network_tools/lib/network_tools.dart b/network_tools/lib/network_tools.dart index 70b9595..e81f45b 100644 --- a/network_tools/lib/network_tools.dart +++ b/network_tools/lib/network_tools.dart @@ -2,6 +2,7 @@ library network_tools; //TODO: add dartdocs export 'src/host_scanner.dart'; +export 'src/mdns_scanner/mdns_scanner.dart'; export 'src/models/active_host.dart'; export 'src/models/callbacks.dart'; export 'src/models/open_port.dart'; diff --git a/network_tools/lib/src/host_scanner.dart b/network_tools/lib/src/host_scanner.dart index d7b5229..e6cc465 100644 --- a/network_tools/lib/src/host_scanner.dart +++ b/network_tools/lib/src/host_scanner.dart @@ -80,7 +80,7 @@ class HostScanner { final Duration? time = response.time; if (time != null) { final ActiveHost tempActiveHost = - ActiveHost(host, i, ActiveHost.generic, pingData); + ActiveHost(host, ActiveHost.generic, pingData); activeHostsController.add(tempActiveHost); return tempActiveHost; } diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart new file mode 100644 index 0000000..d7d3207 --- /dev/null +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list.dart @@ -0,0 +1,21 @@ +import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart'; +import 'package:universal_io/io.dart'; + +/// This class is common interface for executing functions on different os +class SrvList { + /// Will get the srv record in the local network. + static Future?> getSrvRecordList() async { + if (Platform.isLinux) { + return SrvListLinux.getSrvRecordList(); + } + // else if (Platform.isMacOS){ + // // I think the command should be dns-sd so + // // dns-sd -B _services._dns-sd._udp local. + // // and + // // dns-sd -B _ipp._tcp local. + // } + + // Get srv record list is not supported on this os + return []; + } +} diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart new file mode 100644 index 0000000..e4c3a14 --- /dev/null +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart @@ -0,0 +1,107 @@ +import 'dart:collection'; + +import 'package:process_run/shell.dart'; + +class SrvListLinux { + static Future?> getSrvRecordList() async { + final HashSet srvList = HashSet(); + + try { + // Using this command is missing some results and could make the rest of + // the program not search all needed srv types. + // srvList.addAll(await runAvahiBrowseCommand()); + srvList.addAll(await runMdnsScanCommand()); + } catch (e) { + print('Error:\n$e'); + } + return srvList.toList(); + } + + /// Will try to get results from avahi-browse, it is not installed by default + /// on all Linux machines + static Future> runAvahiBrowseCommand() async { + final shell = Shell(verbose: false); + + final List srvListAvahi = []; + + List resultForEachLine = []; + + await shell.run( + ''' +timeout 2s avahi-browse --all -p +''', + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout + + final String? resultStderr = error.result?.stderr.toString(); + if (resultStderr != null && + resultStderr.contains('No such file or directory')) { + print( + 'You can make the mdns process better by installing `avahi-browse`', + ); + return []; + } + final String? resultStdout = error.result?.stdout.toString(); + if (resultStdout == null) { + return []; + } + resultForEachLine = resultStdout.split('\n'); + + return []; + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split(';'); + if (lineSeparated.length >= 6) { + final String srvString = lineSeparated[lineSeparated.length - 2]; + if (!srvString.contains(' ')) { + srvListAvahi.add(srvString); + } + } + } + return srvListAvahi; + } + + /// Will try to get results from mdns-scan, it is not installed by default + /// on all Linux machines + static Future> runMdnsScanCommand() async { + final shell = Shell(verbose: false); + + final List srvListMdnsScan = []; + + List resultForEachLine = []; + + await shell.run( + ''' +timeout 2s mdns-scan +''', + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout + + final String? resultStderr = error.result?.stderr.toString(); + + if (resultStderr == null || + (resultStderr.contains('No such file or directory'))) { + print( + 'You can make the mdns process better by installing `mdns-scan`', + ); + return []; + } + resultForEachLine = resultStderr.split('\n'); + + return []; + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split('.'); + if (lineSeparated.length >= 4) { + final String srvString = + '${lineSeparated[lineSeparated.length - 3]}.${lineSeparated[lineSeparated.length - 2]}'; + if (!srvString.contains(' ') && srvString != '.') { + srvListMdnsScan.add(srvString); + } + } + } + return srvListMdnsScan; + } +} diff --git a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart new file mode 100644 index 0000000..b522308 --- /dev/null +++ b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart @@ -0,0 +1,80 @@ +/// Service record list that is including the protocol, mostly _tcp, _udp may +/// not work +List tcpSrvRecordsList = [ + '_uscan._tcp', // Any HP-compatible network scanners + '_uscans._tcp', // Any SSL/TLS-capable HP-compatible network scanners + '_privet._tcp', // Any Google CloudPrint-capable printers or print services + '_http-alt._tcp', + '_scanner._tcp', // Are there any Bonjour-capable scanners + '_home-assistant._tcp', + '_pdl-datastream._tcp', // Any HP JetDirect-style network printers + '_ipp._tcp', // Are there any printers using the IPP protocol // "domain": "ipp" + '_ipps._tcp', // Any SSL/TLS capable IPP printers // "domain": "ipp" + '_http._tcp', // "domain": "bosch_shc", "name": "bosch shc*" + '_ldap._tcp', + '_gc._tcp', + '_kerberos._tcp', + '_kpasswd._tcp', + '_airplay._tcp', // Any Apple AirPlay-capable video displays here_ipps // [ { "domain": "apple_tv", "properties": { "model": "appletv*" } }, { "domain": "apple_tv", "properties": { "model": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } }, { "domain": "samsungtv", "properties": { "manufacturer": "samsung*" } } ] + '_raop._tcp', // Any Apple AirPlay-capable audio devices [ { "domain": "apple_tv", "properties": { "am": "appletv*" } }, { "domain": "apple_tv", "properties": { "am": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } } ], + '_ippusb._tcp', // Are there any shared printers that are using the IPP-over-USB protocol, i.e. USB-connected printers shared by a Mac + '_printer._tcp', // Any kinds of shared printers at all "domain": "brother", "name": "brother*" + '_ptp._tcp', // Any devices supporting the Picture Transfer Protocol over this network + '_googlecast._tcp', // Is there a ChromeCast-capable device in this network "domain": "cast" + '_airport._tcp', // Any Apple AirPort WiFi APs // "domain": "apple_tv" + '_esphomelib._tcp', // [ { "domain": "esphome" }, { "domain": "zha", "name": "tube*" } ] + '_mqtt._tcp', + '_autodiscover._tcp', + '_sip._tcp', + '_minecraft._tcp', + '_Volumio._tcp', // "domain": "volumio" + '_api._tcp', // [ { "domain": "baf", "properties": { "model": "haiku*" } }, { "domain": "baf", "properties": { "model": "i6*" } } ] + '_appletv-v2._tcp', // "domain": "apple_tv" + '_axis-video._tcp', // [ { "domain": "axis", "properties": { "macaddress": "00408c*" } }, { "domain": "axis", "properties": { "macaddress": "accc8e*" } }, { "domain": "axis", "properties": { "macaddress": "b8a44f*" } }, { "domain": "doorbird", "properties": { "macaddress": "1ccae3*"} } ], + '_bond._tcp', // "domain": "bond" + '_companion-link._tcp', // "domain": "apple_tv" + '_daap._tcp', // "domain": "forked_daapd" + '_dkapi._tcp', // "domain": "daikin" + '_dvl-deviceapi._tcp', // [ { "domain": "devolo_home_control" }, { "domain": "devolo_home_network", "properties": { "MT": "*" } } ] + '_easylink._tcp', // "domain": "modern_forms", "name": "wac*" + '_elg._tcp', // "domain": "elgato" + '_enphase-envoy._tcp', // "domain": "enphase_envoy" + '_fbx-api._tcp', // "domain": "freebox" + '_hap._tcp', // [ { "domain": "homekit_controller" }, { "domain": "zwave_me", "name": "*z.wave-me*" } ] + '_homekit._tcp', // "domain": "homekit" + '_hscp._tcp', // "domain": "apple_tv" + '_hue._tcp', // "domain": "hue" + '_hwenergy._tcp', // "domain": "homewizard", + '_kizbox._tcp', // "domain": "overkiz", "name": "gateway*" + '_leap._tcp', // "domain": "lutron_caseta" + '_lookin._tcp', // "domain": "lookin" + '_mediaremotetv._tcp', // "domain": "apple_tv" + '_nanoleafapi._tcp', // "domain": "nanoleaf" + '_nanoleafms._tcp', // "domain": "nanoleaf" + '_nut._tcp', // "domain": "nut" + '_octoprint._tcp', // "domain": "octoprint" + '_plexmediasvr._tcp', // "domain": "plex" + '_plugwise._tcp', // "domain": "plugwise" + '_powerview._tcp', // "domain": "hunterdouglas_powerview" + '_sideplay._tcp', // { "domain": "ecobee", "properties": { "mdl": "eb-*" } }, { "domain": "ecobee", "properties": { "mdl": "ecobee*" } } + '_sonos._tcp', // "domain": "sonos" + '_soundtouch._tcp', // "domain": "soundtouch" + '_spotify-connect', // "domain": "spotify" + '_ssh._tcp', // { "domain": "smappee", "name": "smappee1*" }, { "domain": "smappee", "name": "smappee2*" }, { "domain": "smappee", "name": "smappee50*" } + '_system-bridge._tcp', // "domain": "system_bridge" + '_touch-able._tcp', // "domain": "apple_tv" + '_viziocast._tcp', // "domain": "vizio" + '_wled._tcp', // "domain": "wled" + '_xbmc-jsonrpc-h._tcp', // "domain": "kodi" + '_zigate-zigbee-gateway._tcp', // "domain": "zha", "name": "*zigate*" + '_zwave-js-server._tcp', // "domain": "zwave_js" + '_axis-video._tcp', // "properties": { "macaddress": "00408c*" } "properties": { "macaddress": "accc8e*" } "properties": { "macaddress": "b8a44f*" } +]; + +List udpSrvRecordsList = [ + '_api._udp', // "domain": "guardian" + '_hap._udp', // "domain": "homekit_controller" + '_miio._udp', // [ { "domain": "xiaomi_aqara" }, { "domain": "xiaomi_miio" }, { "domain": "yeelight", "name": "yeelink-*" } ] + '_sleep-proxy._udp', // "domain": "apple_tv" + '_system-bridge._udp', +]; diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart new file mode 100644 index 0000000..b392d86 --- /dev/null +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -0,0 +1,110 @@ +import 'dart:io'; + +import 'package:dart_ping/dart_ping.dart'; +import 'package:multicast_dns/multicast_dns.dart'; +import 'package:network_tools/network_tools.dart'; +import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list.dart'; +import 'package:network_tools/src/mdns_scanner/list_of_srv_records.dart'; +import 'package:network_tools/src/models/mdns_info.dart'; + +class MdnsScanner { + /// This method searching for all the mdns devices in the network. + /// Shows only results for IPv4. + /// TODO: The implementation is **Lacking!** and will not find all the + /// TODO: results that actual exist in the network!, only some of them. + /// TODO: This is because missing functionality in dart + /// TODO: https://github.com/flutter/flutter/issues/97210 + /// TODO: In some cases we resolve this missing functionality using + /// TODO: specific os tools. + static Future> searchMdnsDevices() async { + List srvRecordListToSearchIn; + + final List? srvRecordsFromOs = await SrvList.getSrvRecordList(); + + if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) { + srvRecordListToSearchIn = tcpSrvRecordsList; + srvRecordListToSearchIn.addAll(udpSrvRecordsList); + } else { + srvRecordListToSearchIn = srvRecordsFromOs; + } + + await Future.delayed(const Duration(milliseconds: 5)); + + final List>> activeHostListsFuture = []; + for (final String srvRecord in srvRecordListToSearchIn) { + activeHostListsFuture.add(_findingMdnsWithIp(srvRecord)); + } + + final List activeHostList = []; + + for (final Future> activeHostListFuture + in activeHostListsFuture) { + activeHostList.addAll(await activeHostListFuture); + } + + return activeHostList; + } + + static Future> _findingMdnsWithIp(String serviceType) async { + final List mdnsFoundList = []; + + final MDnsClient client = MDnsClient(); + await client.start(); + + await for (final PtrResourceRecord ptr in client.lookup( + ResourceRecordQuery.serverPointer(serviceType), + )) { + await for (final SrvResourceRecord srv + in client.lookup( + ResourceRecordQuery.service(ptr.domainName), + )) { + final MdnsInfo mdnsFound = MdnsInfo( + mdnsName: srv.name, + mdnsPort: srv.port, + mdnsDomainName: ptr.domainName, + mdnsServiceType: serviceType, + mdnsSrvTarget: srv.target, + ); + mdnsFoundList.add(mdnsFound); + } + } + client.stop(); + + final List listOfActiveHost = []; + for (final MdnsInfo foundMdns in mdnsFoundList) { + final List internetAddressList = + await InternetAddress.lookup(foundMdns.mdnsSrvTarget); + + // There can be multiple devices with the same name + for (final InternetAddress internetAddress in internetAddressList) { + final String hostIp = internetAddress.address; + + final ActiveHost tempHost = ActiveHost( + hostIp, + foundMdns.getOnlyTheStartOfMdnsName(), + await getPingData(hostIp), + mdnsInfo: foundMdns, + ); + listOfActiveHost.add(tempHost); + } + } + + return listOfActiveHost; + } + + static Future getPingData(String host) async { + const int timeoutInSeconds = 1; + + await for (final PingData pingData + in Ping(host, count: 1, timeout: timeoutInSeconds).stream) { + final PingResponse? response = pingData.response; + if (response != null) { + final Duration? time = response.time; + if (time != null) { + return pingData; + } + } + } + return const PingData(); + } +} diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index 806a410..f29d6e9 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -1,16 +1,25 @@ import 'package:dart_ping/dart_ping.dart'; +import 'package:network_tools/src/models/mdns_info.dart'; /// ActiveHost which implements comparable /// By default sort by hostId ascending class ActiveHost extends Comparable { - ActiveHost(this._ip, this.hostId, this._make, this._pingData); + ActiveHost( + this._ip, + this._make, + this._pingData, { + this.mdnsInfo, + }) { + hostId = int.parse(_ip.substring(_ip.lastIndexOf('.') + 1, _ip.length)); + } static const generic = 'Generic Device'; static const router = 'Router'; final String _ip; - int hostId; + late int hostId; final String _make; final PingData _pingData; + MdnsInfo? mdnsInfo; String get ip => _ip; String get make => _make; diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart new file mode 100644 index 0000000..e121aff --- /dev/null +++ b/network_tools/lib/src/models/mdns_info.dart @@ -0,0 +1,24 @@ +class MdnsInfo { + MdnsInfo({ + required this.mdnsName, + required this.mdnsPort, + required this.mdnsDomainName, + required this.mdnsServiceType, + required this.mdnsSrvTarget, + }); + + /// Also can be called target + String mdnsName; + String mdnsSrvTarget; + int mdnsPort; + + /// Also can be called bundleId + String mdnsDomainName; + + /// Srv record of the dns + String mdnsServiceType; + + String getOnlyTheStartOfMdnsName() { + return mdnsName.substring(0, mdnsName.indexOf('.')); + } +} diff --git a/network_tools/pubspec.yaml b/network_tools/pubspec.yaml index ddbc89d..12dd246 100644 --- a/network_tools/pubspec.yaml +++ b/network_tools/pubspec.yaml @@ -1,6 +1,6 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 2.0.0 +version: 2.1.0 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools/tree/main/network_tools @@ -14,6 +14,10 @@ dependencies: intl: ^0.17.0 # Debugging and error logging. logging: ^1.0.2 + # Performing mDNS queries (e.g. Bonjour, Avahi). + multicast_dns: ^0.3.2+1 + # Process run helpers + process_run: ^0.12.3+2 # Cross-platform 'dart:io' that works in all platforms. universal_io: ^2.0.4 @@ -22,4 +26,3 @@ dev_dependencies: lint: ^1.8.2 # Writing and running Dart tests. test: ^1.21.4 - From b7a92c2f6ad9e0fe482e077018cdb117e0d6023a Mon Sep 17 00:00:00 2001 From: Guy Luz Date: Tue, 26 Jul 2022 19:40:29 +0300 Subject: [PATCH 21/36] Combine activehost and openport (#37) * Updated dependencies * Added comments to each dependency * Decided to update min dart version to 2.17.0 (even though pub get didn't show any errors) because it is the min version in dart_ping 7.0.0 * Reverted min dart version back to 2.12.0 as it is not mandatory * Updated min dart version to 2.17.0. * Added a function to find some of the mdns devices on the network * Added todo part for searchMdnsDevices and more srv record. * Inserting the name from the mdns into _make var in ActiveHost * More srv records. * More srv records. * Made ActiveHost class mre generic. Added fix when multiple hosts have the same name. * PortScanner now retrieve ActiveHost instead of OpenPort * Added mdns scanner to example and Changelog. Changed network_tool version to 2.1.0 * Remove Future from main function in example folder * Fixed conflicts from dev * Made searching for mdns process better for Linux if avahi-browse or mdns-scan is installed on it. * Removing print * Added small comment for future mac implementation. * Small fix to srv results as avahi command does not return all of them. * Added a lot entry's to the tcpSrvRecords list, added udpSrvRecordList. * Added the udp list to the search. Small fix for multiple devices with the same mDNS name different address. * Fix marge from last pr * Made mdns_scanner accessible to users of the package. * Made MdnsInfo accessible to users of the package. * Removed redundant delayed * Small fix for case were ActiveHost find ip that is not regular with dots. Added more Srv record --- network_tools/example/port_scan.dart | 16 +++--- network_tools/lib/network_tools.dart | 2 + network_tools/lib/src/host_scanner.dart | 21 ++++---- .../src/mdns_scanner/list_of_srv_records.dart | 1 + .../lib/src/mdns_scanner/mdns_scanner.dart | 22 +------- network_tools/lib/src/models/active_host.dart | 50 ++++++++++++++++--- network_tools/lib/src/models/open_port.dart | 4 +- network_tools/lib/src/port_scanner.dart | 37 +++++++------- 8 files changed, 88 insertions(+), 65 deletions(-) diff --git a/network_tools/example/port_scan.dart b/network_tools/example/port_scan.dart index 4093340..573ab07 100644 --- a/network_tools/example/port_scan.dart +++ b/network_tools/example/port_scan.dart @@ -29,9 +29,11 @@ void main() { ); stream2.listen( - (port) { - if (port.isOpen) { - _log.fine('Found open port: ${port.port} on ${port.ip}'); + (activeHost) { + final OpenPort deviceWithOpenPort = activeHost.openPort[0]; + if (deviceWithOpenPort.isOpen) { + _log.fine( + 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.ip}'); } }, onDone: () { @@ -49,9 +51,11 @@ void main() { _log.finer('Progress for port discovery : $progress'); }, ).listen( - (event) { - if (event.isOpen) { - _log.fine('Found open port : ${event.port}'); + (activeHost) { + final OpenPort deviceWithOpenPort = activeHost.openPort[0]; + + if (deviceWithOpenPort.isOpen) { + _log.fine('Found open port : ${deviceWithOpenPort.port}'); } }, onDone: () { diff --git a/network_tools/lib/network_tools.dart b/network_tools/lib/network_tools.dart index e81f45b..7509198 100644 --- a/network_tools/lib/network_tools.dart +++ b/network_tools/lib/network_tools.dart @@ -1,9 +1,11 @@ library network_tools; + //TODO: add dartdocs export 'src/host_scanner.dart'; export 'src/mdns_scanner/mdns_scanner.dart'; export 'src/models/active_host.dart'; export 'src/models/callbacks.dart'; +export 'src/models/mdns_info.dart'; export 'src/models/open_port.dart'; export 'src/port_scanner.dart'; diff --git a/network_tools/lib/src/host_scanner.dart b/network_tools/lib/src/host_scanner.dart index e6cc465..978121f 100644 --- a/network_tools/lib/src/host_scanner.dart +++ b/network_tools/lib/src/host_scanner.dart @@ -4,7 +4,6 @@ import 'dart:math'; import 'package:dart_ping/dart_ping.dart'; import 'package:network_tools/src/models/active_host.dart'; import 'package:network_tools/src/models/callbacks.dart'; -import 'package:network_tools/src/models/open_port.dart'; import 'package:network_tools/src/port_scanner.dart'; /// Scans for all hosts in a subnet. @@ -80,7 +79,7 @@ class HostScanner { final Duration? time = response.time; if (time != null) { final ActiveHost tempActiveHost = - ActiveHost(host, ActiveHost.generic, pingData); + ActiveHost(host, pingData: pingData); activeHostsController.add(tempActiveHost); return tempActiveHost; } @@ -92,7 +91,7 @@ class HostScanner { /// Scans for all hosts that have the specific port that was given. /// [resultsInIpAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream discoverPort( + static Stream discoverPort( String subnet, int port, { int firstSubnet = 1, @@ -110,13 +109,13 @@ class HostScanner { throw 'Invalid subnet range or firstSubnet < lastSubnet is not true'; } final int lastValidSubnet = min(lastSubnet, maxEnd); - final List> openPortList = []; - final StreamController activeHostsController = - StreamController(); + final List> activeHostOpenPortList = []; + final StreamController activeHostsController = + StreamController(); for (int i = firstSubnet; i <= lastValidSubnet; i++) { final host = '$subnet.$i'; - openPortList.add( + activeHostOpenPortList.add( PortScanner.connectToPort( ip: host, port: port, @@ -131,8 +130,12 @@ class HostScanner { } int counter = firstSubnet; - for (final Future openPortFuture in openPortList) { - yield await openPortFuture; + for (final Future openPortActiveHostFuture + in activeHostOpenPortList) { + final ActiveHost? activeHost = await openPortActiveHostFuture; + if (activeHost != null) { + yield activeHost; + } progressCallback?.call( (counter - firstSubnet) * 100 / (lastValidSubnet - firstSubnet), ); diff --git a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart index b522308..155e444 100644 --- a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart +++ b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart @@ -69,6 +69,7 @@ List tcpSrvRecordsList = [ '_zigate-zigbee-gateway._tcp', // "domain": "zha", "name": "*zigate*" '_zwave-js-server._tcp', // "domain": "zwave_js" '_axis-video._tcp', // "properties": { "macaddress": "00408c*" } "properties": { "macaddress": "accc8e*" } "properties": { "macaddress": "b8a44f*" } + '_androidtvremote2._tcp', ]; List udpSrvRecordsList = [ diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index b392d86..a107cc9 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:dart_ping/dart_ping.dart'; import 'package:multicast_dns/multicast_dns.dart'; import 'package:network_tools/network_tools.dart'; import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list.dart'; @@ -28,8 +27,6 @@ class MdnsScanner { srvRecordListToSearchIn = srvRecordsFromOs; } - await Future.delayed(const Duration(milliseconds: 5)); - final List>> activeHostListsFuture = []; for (final String srvRecord in srvRecordListToSearchIn) { activeHostListsFuture.add(_findingMdnsWithIp(srvRecord)); @@ -81,8 +78,7 @@ class MdnsScanner { final ActiveHost tempHost = ActiveHost( hostIp, - foundMdns.getOnlyTheStartOfMdnsName(), - await getPingData(hostIp), + deviceName: foundMdns.getOnlyTheStartOfMdnsName(), mdnsInfo: foundMdns, ); listOfActiveHost.add(tempHost); @@ -91,20 +87,4 @@ class MdnsScanner { return listOfActiveHost; } - - static Future getPingData(String host) async { - const int timeoutInSeconds = 1; - - await for (final PingData pingData - in Ping(host, count: 1, timeout: timeoutInSeconds).stream) { - final PingResponse? response = pingData.response; - if (response != null) { - final Duration? time = response.time; - if (time != null) { - return pingData; - } - } - } - return const PingData(); - } } diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index f29d6e9..d68e0de 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -1,28 +1,45 @@ import 'package:dart_ping/dart_ping.dart'; import 'package:network_tools/src/models/mdns_info.dart'; +import 'package:network_tools/src/models/open_port.dart'; /// ActiveHost which implements comparable /// By default sort by hostId ascending class ActiveHost extends Comparable { ActiveHost( - this._ip, - this._make, - this._pingData, { + this._ip, { + this.openPort = const [], + PingData? pingData, + this.deviceName = generic, this.mdnsInfo, }) { - hostId = int.parse(_ip.substring(_ip.lastIndexOf('.') + 1, _ip.length)); + if (_ip.contains('.')) { + hostId = int.parse(_ip.substring(_ip.lastIndexOf('.') + 1, _ip.length)); + } else if (_ip.contains(':')) { + hostId = int.parse(_ip.substring(_ip.lastIndexOf(':') + 1, _ip.length)); + } else { + hostId = -1; + } + pingData ??= getPingData(_ip); + _pingData = pingData; } static const generic = 'Generic Device'; static const router = 'Router'; final String _ip; late int hostId; - final String _make; - final PingData _pingData; + late final PingData _pingData; + + /// Mdns information of this device MdnsInfo? mdnsInfo; + /// List of all the open port of this device + List openPort; + String get ip => _ip; - String get make => _make; + + /// This device name does not following any guideline and is just some name + /// that we find for the device + final String deviceName; PingData get pingData => _pingData; Duration? get responseTime => _pingData.response?.time; @@ -39,6 +56,23 @@ class ActiveHost extends Comparable { @override String toString() { - return 'IP : $_ip, HostId : $hostId, make: $_make, Time: ${responseTime?.inMilliseconds}ms'; + return 'IP : $_ip, HostId : $hostId, make: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; + } + + static PingData getPingData(String host) { + const int timeoutInSeconds = 1; + + PingData tempPingData = const PingData(); + + Ping(host, count: 1, timeout: timeoutInSeconds).stream.listen((pingData) { + final PingResponse? response = pingData.response; + if (response != null) { + final Duration? time = response.time; + if (time != null) { + tempPingData = pingData; + } + } + }); + return tempPingData; } } diff --git a/network_tools/lib/src/models/open_port.dart b/network_tools/lib/src/models/open_port.dart index 70b2af0..049f6bc 100644 --- a/network_tools/lib/src/models/open_port.dart +++ b/network_tools/lib/src/models/open_port.dart @@ -1,11 +1,9 @@ /// Represents open port for a target IP class OpenPort { - OpenPort(this._ip, this._port, {this.isOpen = false}); + OpenPort(this._port, {this.isOpen = true}); - final String _ip; final int _port; final bool isOpen; - String get ip => _ip; int get port => _port; } diff --git a/network_tools/lib/src/port_scanner.dart b/network_tools/lib/src/port_scanner.dart index 27f6d71..f389681 100644 --- a/network_tools/lib/src/port_scanner.dart +++ b/network_tools/lib/src/port_scanner.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:network_tools/src/models/active_host.dart'; import 'package:network_tools/src/models/callbacks.dart'; import 'package:network_tools/src/models/open_port.dart'; import 'package:universal_io/io.dart'; @@ -37,7 +38,7 @@ class PortScanner { ]; /// Checks if the single [port] is open or not for the [target]. - static Future isOpen( + static Future isOpen( String target, int port, { Duration timeout = const Duration(milliseconds: 2000), @@ -51,7 +52,7 @@ class PortScanner { if (address.isNotEmpty) { final String hostIP = address[0].address; return connectToPort( - activeHostsController: StreamController(), + activeHostsController: StreamController(), ip: hostIP, port: port, timeout: timeout, @@ -66,7 +67,7 @@ class PortScanner { /// Tries connecting ports before until [timeout] reached. /// [resultsInIpAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream customDiscover( + static Stream customDiscover( String target, { List portList = commonPorts, ProgressCallback? progressCallback, @@ -77,9 +78,9 @@ class PortScanner { await InternetAddress.lookup(target, type: InternetAddressType.IPv4); if (address.isNotEmpty) { final String hostIP = address[0].address; - final List> openPortList = []; - final StreamController activeHostsController = - StreamController(); + final List> openPortList = []; + final StreamController activeHostsController = + StreamController(); for (int k = 0; k < portList.length; k++) { if (portList[k] >= 0 && portList[k] <= 65535) { @@ -100,8 +101,11 @@ class PortScanner { int counter = 0; - for (final Future openPortFuture in openPortList) { - final OpenPort openPort = await openPortFuture; + for (final Future openPortFuture in openPortList) { + final ActiveHost? openPort = await openPortFuture; + if (openPort == null) { + continue; + } progressCallback?.call(counter * 100 / portList.length); yield openPort; counter++; @@ -114,7 +118,7 @@ class PortScanner { /// Scans port from [startPort] to [endPort] of [target]. Progress can be /// retrieved by [progressCallback] /// Tries connecting ports before until [timeout] reached. - static Stream discover( + static Stream discover( String target, { int startPort = defaultStartPort, int endPort = defaultEndPort, @@ -146,19 +150,19 @@ class PortScanner { ); } - static Future connectToPort({ + static Future connectToPort({ required String ip, required int port, required Duration timeout, - required StreamController activeHostsController, + required StreamController activeHostsController, }) async { try { final Socket s = await Socket.connect(ip, port, timeout: timeout); s.destroy(); - final OpenPort tempOpenPort = OpenPort(ip, port, isOpen: true); - activeHostsController.add(tempOpenPort); + final ActiveHost activeHost = ActiveHost(ip, openPort: [OpenPort(port)]); + activeHostsController.add(activeHost); - return tempOpenPort; + return activeHost; } catch (e) { if (e is! SocketException) { rethrow; @@ -166,10 +170,7 @@ class PortScanner { // Check if connection timed out or we got one of predefined errors if (e.osError == null || _errorCodes.contains(e.osError?.errorCode)) { - final OpenPort tempOpenPort = OpenPort(ip, port); - - activeHostsController.add(tempOpenPort); - return tempOpenPort; + return null; } else { // Error 23,24: Too many open files in system rethrow; From 1acdc5901796f9ae2cb81d9672f1e7148c0cc057 Mon Sep 17 00:00:00 2001 From: Paras Date: Tue, 26 Jul 2022 23:13:29 +0530 Subject: [PATCH 22/36] Readme Update --- README.md | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index bec3155..ada7426 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ Network Tools Supported 2. Range 3. Custom -What's not supported +Partly Work: -1. Mac Address of other devices on network +1. Mdns Scanner ## Import package in your app @@ -48,41 +48,52 @@ import 'package:network_tools/network_tools.dart'; ### Port Scanner ```dart - //1. Range - String target = '192.168.1.1'; - PortScanner.discover(target, startPort: 1, endPort: 1024, + //1. Range + String target = '192.168.1.1'; + PortScanner.discover(target, startPort: 1, endPort: 1024, progressCallback: (progress) { print('Progress for port discovery : $progress'); - }).listen((event) { + }).listen((event) { if (event.isOpen) { print('Found open port : $event'); } - }, onDone: () { + }, onDone: () { print('Scan completed'); - }); - //2. Single - bool isOpen = PortScanner.isOpen(target,80); - //3. Custom - PortScanner.customDiscover(target, portList : const [22, 80, 139]); + }); + //2. Single + bool isOpen = PortScanner.isOpen(target,80); + //3. Custom + PortScanner.customDiscover(target, portList : const [22, 80, 139]); +``` +### Mdns Scanner + +```dart + for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { + final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; + print( + 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + ); + } ``` + ### Run examples 1. Run host scan : `dart example/host_scan.dart` 2. Run port scan : `dart example/port_scan.dart` +3. Run mdns scan : `dart example/mdns_scan.dart` ## Enable Debugging Add this code to your `main.dart` file ```dart -Logger.root.level = Level.FINE; //set to finest for detailed log - Logger.root.onRecord.listen((record) { - print( - '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}'); - }); - + Logger.root.level = Level.FINE; //set to finest for detailed log + Logger.root.onRecord.listen((record) { + print( + '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}'); + }); ``` ## Sample App From 1f83493d334343c24c7901496b12ef49ef020149 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Wed, 27 Jul 2022 18:30:59 +0300 Subject: [PATCH 23/36] Fix for #3. Improved pub.dev score. Change method names to be more precise. --- network_tools/example/host_scan.dart | 2 +- network_tools/example/port_scan.dart | 9 +++-- network_tools/lib/src/host_scanner.dart | 6 +-- .../lib/src/mdns_scanner/mdns_scanner.dart | 6 +-- network_tools/lib/src/models/active_host.dart | 38 +++++++++++++++---- network_tools/lib/src/port_scanner.dart | 5 ++- 6 files changed, 43 insertions(+), 23 deletions(-) diff --git a/network_tools/example/host_scan.dart b/network_tools/example/host_scan.dart index 7f82b58..9f6c2da 100644 --- a/network_tools/example/host_scan.dart +++ b/network_tools/example/host_scan.dart @@ -18,7 +18,7 @@ void main() { // You can set [firstSubnet] and scan will start from this host in the network. // Similarly set [lastSubnet] and scan will end at this host in the network. - final stream = HostScanner.discover( + final stream = HostScanner.getAllPingableDevices( subnet, // firstSubnet: 1, // lastSubnet: 254, diff --git a/network_tools/example/port_scan.dart b/network_tools/example/port_scan.dart index 573ab07..e8c964a 100644 --- a/network_tools/example/port_scan.dart +++ b/network_tools/example/port_scan.dart @@ -18,7 +18,7 @@ void main() { // [New] Scan for a single open port in a subnet // You can set [firstSubnet] and scan will start from this host in the network. // Similarly set [lastSubnet] and scan will end at this host in the network. - final stream2 = HostScanner.discoverPort( + final stream2 = HostScanner.scanDevicesForSinglePort( subnet, 53, // firstSubnet: 1, @@ -33,7 +33,8 @@ void main() { final OpenPort deviceWithOpenPort = activeHost.openPort[0]; if (deviceWithOpenPort.isOpen) { _log.fine( - 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.ip}'); + 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.ip}', + ); } }, onDone: () { @@ -42,7 +43,7 @@ void main() { ); // Don't forget to cancel the stream when not in use. const String target = '192.168.1.1'; - PortScanner.discover( + PortScanner.scanPortsForSingleDevice( target, // Scan will start from this port. // startPort: 1, @@ -55,7 +56,7 @@ void main() { final OpenPort deviceWithOpenPort = activeHost.openPort[0]; if (deviceWithOpenPort.isOpen) { - _log.fine('Found open port : ${deviceWithOpenPort.port}'); + _log.fine('Found open port: ${deviceWithOpenPort.port}'); } }, onDone: () { diff --git a/network_tools/lib/src/host_scanner.dart b/network_tools/lib/src/host_scanner.dart index 978121f..7adda1f 100644 --- a/network_tools/lib/src/host_scanner.dart +++ b/network_tools/lib/src/host_scanner.dart @@ -14,7 +14,7 @@ class HostScanner { /// resource consumption. /// [resultsInIpAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream discover( + static Stream getAllPingableDevices( String subnet, { int firstSubnet = 1, int lastSubnet = 254, @@ -79,7 +79,7 @@ class HostScanner { final Duration? time = response.time; if (time != null) { final ActiveHost tempActiveHost = - ActiveHost(host, pingData: pingData); + ActiveHost.buildWithIp(ip: host, pingData: pingData); activeHostsController.add(tempActiveHost); return tempActiveHost; } @@ -91,7 +91,7 @@ class HostScanner { /// Scans for all hosts that have the specific port that was given. /// [resultsInIpAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream discoverPort( + static Stream scanDevicesForSinglePort( String subnet, int port, { int firstSubnet = 1, diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index a107cc9..6b8960d 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -4,11 +4,9 @@ import 'package:multicast_dns/multicast_dns.dart'; import 'package:network_tools/network_tools.dart'; import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list.dart'; import 'package:network_tools/src/mdns_scanner/list_of_srv_records.dart'; -import 'package:network_tools/src/models/mdns_info.dart'; class MdnsScanner { /// This method searching for all the mdns devices in the network. - /// Shows only results for IPv4. /// TODO: The implementation is **Lacking!** and will not find all the /// TODO: results that actual exist in the network!, only some of them. /// TODO: This is because missing functionality in dart @@ -74,10 +72,8 @@ class MdnsScanner { // There can be multiple devices with the same name for (final InternetAddress internetAddress in internetAddressList) { - final String hostIp = internetAddress.address; - final ActiveHost tempHost = ActiveHost( - hostIp, + internetAddress: internetAddress, deviceName: foundMdns.getOnlyTheStartOfMdnsName(), mdnsInfo: foundMdns, ); diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index d68e0de..f7832c6 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -1,17 +1,19 @@ import 'package:dart_ping/dart_ping.dart'; import 'package:network_tools/src/models/mdns_info.dart'; import 'package:network_tools/src/models/open_port.dart'; +import 'package:universal_io/io.dart'; /// ActiveHost which implements comparable /// By default sort by hostId ascending class ActiveHost extends Comparable { - ActiveHost( - this._ip, { + ActiveHost({ + required this.internetAddress, this.openPort = const [], PingData? pingData, this.deviceName = generic, this.mdnsInfo, }) { + final String _ip = internetAddress.address; if (_ip.contains('.')) { hostId = int.parse(_ip.substring(_ip.lastIndexOf('.') + 1, _ip.length)); } else if (_ip.contains(':')) { @@ -23,9 +25,29 @@ class ActiveHost extends Comparable { _pingData = pingData; } + factory ActiveHost.buildWithIp({ + required String ip, + List openPort = const [], + PingData? pingData, + String deviceName = generic, + MdnsInfo? mdnsInfo, + }) { + final InternetAddress? internetAddressTemp = InternetAddress.tryParse(ip); + if (internetAddressTemp == null) { + throw 'Cant parse ip $ip to InternetAddress'; + } + return ActiveHost( + internetAddress: internetAddressTemp, + openPort: openPort, + pingData: pingData, + deviceName: deviceName, + mdnsInfo: mdnsInfo, + ); + } + static const generic = 'Generic Device'; static const router = 'Router'; - final String _ip; + final InternetAddress internetAddress; late int hostId; late final PingData _pingData; @@ -35,19 +57,19 @@ class ActiveHost extends Comparable { /// List of all the open port of this device List openPort; - String get ip => _ip; - /// This device name does not following any guideline and is just some name /// that we find for the device final String deviceName; PingData get pingData => _pingData; Duration? get responseTime => _pingData.response?.time; + String get ip => internetAddress.address; @override - int get hashCode => _ip.hashCode; + int get hashCode => internetAddress.address.hashCode; @override - bool operator ==(dynamic o) => o is ActiveHost && _ip == o._ip; + bool operator ==(dynamic o) => + o is ActiveHost && internetAddress.address == o.internetAddress.address; @override int compareTo(ActiveHost other) { @@ -56,7 +78,7 @@ class ActiveHost extends Comparable { @override String toString() { - return 'IP : $_ip, HostId : $hostId, make: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; + return 'IP : ${internetAddress.address}, HostId : $hostId, make: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; } static PingData getPingData(String host) { diff --git a/network_tools/lib/src/port_scanner.dart b/network_tools/lib/src/port_scanner.dart index f389681..b515882 100644 --- a/network_tools/lib/src/port_scanner.dart +++ b/network_tools/lib/src/port_scanner.dart @@ -118,7 +118,7 @@ class PortScanner { /// Scans port from [startPort] to [endPort] of [target]. Progress can be /// retrieved by [progressCallback] /// Tries connecting ports before until [timeout] reached. - static Stream discover( + static Stream scanPortsForSingleDevice( String target, { int startPort = defaultStartPort, int endPort = defaultEndPort, @@ -159,7 +159,8 @@ class PortScanner { try { final Socket s = await Socket.connect(ip, port, timeout: timeout); s.destroy(); - final ActiveHost activeHost = ActiveHost(ip, openPort: [OpenPort(port)]); + final ActiveHost activeHost = + ActiveHost.buildWithIp(ip: ip, openPort: [OpenPort(port)]); activeHostsController.add(activeHost); return activeHost; From 8ce02a836e07f038d495797668c090d047fa4eba Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Thu, 28 Jul 2022 02:56:26 +0300 Subject: [PATCH 24/36] Each ActiveHost object will automatically get host name when waitingForActiveHostSetupToComplete is done, fix for #3. --- network_tools/example/mdns_scan.dart | 2 - .../lib/src/mdns_scanner/mdns_scanner.dart | 1 - network_tools/lib/src/models/active_host.dart | 48 +++++++++++++++---- network_tools/lib/src/models/mdns_info.dart | 1 + 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart index becac00..43000e9 100644 --- a/network_tools/example/mdns_scan.dart +++ b/network_tools/example/mdns_scan.dart @@ -1,6 +1,4 @@ import 'package:network_tools/network_tools.dart'; -import 'package:network_tools/src/mdns_scanner/mdns_scanner.dart'; -import 'package:network_tools/src/models/mdns_info.dart'; Future main() async { for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 6b8960d..8570d59 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -74,7 +74,6 @@ class MdnsScanner { for (final InternetAddress internetAddress in internetAddressList) { final ActiveHost tempHost = ActiveHost( internetAddress: internetAddress, - deviceName: foundMdns.getOnlyTheStartOfMdnsName(), mdnsInfo: foundMdns, ); listOfActiveHost.add(tempHost); diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index f7832c6..e81cf1d 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -10,7 +10,6 @@ class ActiveHost extends Comparable { required this.internetAddress, this.openPort = const [], PingData? pingData, - this.deviceName = generic, this.mdnsInfo, }) { final String _ip = internetAddress.address; @@ -23,13 +22,13 @@ class ActiveHost extends Comparable { } pingData ??= getPingData(_ip); _pingData = pingData; + waitingForActiveHostSetupToComplete = setHostNameAndMdns(); } factory ActiveHost.buildWithIp({ required String ip, List openPort = const [], PingData? pingData, - String deviceName = generic, MdnsInfo? mdnsInfo, }) { final InternetAddress? internetAddressTemp = InternetAddress.tryParse(ip); @@ -40,15 +39,15 @@ class ActiveHost extends Comparable { internetAddress: internetAddressTemp, openPort: openPort, pingData: pingData, - deviceName: deviceName, mdnsInfo: mdnsInfo, ); } static const generic = 'Generic Device'; - static const router = 'Router'; - final InternetAddress internetAddress; + InternetAddress internetAddress; late int hostId; + String? hostName; + String? weirdHostName; late final PingData _pingData; /// Mdns information of this device @@ -58,12 +57,21 @@ class ActiveHost extends Comparable { List openPort; /// This device name does not following any guideline and is just some name - /// that we find for the device - final String deviceName; + /// that we can show for the device. + /// Preferably hostName, if not than mDNS name, if not than will get the + /// value of [generic]. + /// This value **can change after the object got created** since getting + /// host name of device is running async function. + String deviceName = generic; PingData get pingData => _pingData; Duration? get responseTime => _pingData.response?.time; String get ip => internetAddress.address; + /// This var let us know from out side if all the setup got completed. + /// Since getting host name is async function [ActiveHost] does not contain + /// all of the values when the constructor completed + late Future waitingForActiveHostSetupToComplete; + @override int get hashCode => internetAddress.address.hashCode; @@ -78,7 +86,7 @@ class ActiveHost extends Comparable { @override String toString() { - return 'IP : ${internetAddress.address}, HostId : $hostId, make: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; + return 'IP: ${internetAddress.address}, HostId: $hostId, deviceName: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; } static PingData getPingData(String host) { @@ -97,4 +105,28 @@ class ActiveHost extends Comparable { }); return tempPingData; } + + /// Try to find the host name of this device, if not exist host name will + /// stay null + Future setHostNameAndMdns() async { + // For some reason when internetAddress.host get called before the reverse + // there is weired value + weirdHostName = internetAddress.host; + + // In the future if mdnsInfo is null it will execute a search + // Currently the functionality is missing in dart multicast_dns package + // https://github.com/flutter/flutter/issues/96755 + + try { + internetAddress = await internetAddress.reverse(); + hostName = internetAddress.host; + deviceName = hostName!; + } catch (e) { + // Some devices does not have host name and the reverse search will just + // throw exception. + if (mdnsInfo != null) { + deviceName = mdnsInfo!.getOnlyTheStartOfMdnsName(); + } + } + } } diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart index e121aff..340859e 100644 --- a/network_tools/lib/src/models/mdns_info.dart +++ b/network_tools/lib/src/models/mdns_info.dart @@ -18,6 +18,7 @@ class MdnsInfo { /// Srv record of the dns String mdnsServiceType; + /// mDNS name without the ._tcp.local String getOnlyTheStartOfMdnsName() { return mdnsName.substring(0, mdnsName.indexOf('.')); } From e3d545a6d217e086fa2ecbe6f001a5f0a71618d7 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Thu, 28 Jul 2022 19:38:34 +0300 Subject: [PATCH 25/36] Fix for #44 --- network_tools/lib/src/models/active_host.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index e81cf1d..96f02ce 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -13,13 +13,15 @@ class ActiveHost extends Comparable { this.mdnsInfo, }) { final String _ip = internetAddress.address; + if (_ip.contains('.')) { - hostId = int.parse(_ip.substring(_ip.lastIndexOf('.') + 1, _ip.length)); + hostId = _ip.substring(_ip.lastIndexOf('.') + 1, _ip.length); } else if (_ip.contains(':')) { - hostId = int.parse(_ip.substring(_ip.lastIndexOf(':') + 1, _ip.length)); + hostId = _ip.substring(_ip.lastIndexOf(':') + 1, _ip.length); } else { - hostId = -1; + hostId = '-1'; } + pingData ??= getPingData(_ip); _pingData = pingData; waitingForActiveHostSetupToComplete = setHostNameAndMdns(); @@ -45,7 +47,7 @@ class ActiveHost extends Comparable { static const generic = 'Generic Device'; InternetAddress internetAddress; - late int hostId; + late String hostId; String? hostName; String? weirdHostName; late final PingData _pingData; From 4fca45f08f9a7b00145883d242707e2cd1f2d5a0 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Thu, 28 Jul 2022 19:56:19 +0300 Subject: [PATCH 26/36] Updated package version to 2.2.0, updated changelog for the new version .Updated lint to 1.10.0. --- network_tools/CHANGELOG.md | 8 ++++++++ network_tools/pubspec.yaml | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/network_tools/CHANGELOG.md b/network_tools/CHANGELOG.md index c3b491e..70cc00f 100644 --- a/network_tools/CHANGELOG.md +++ b/network_tools/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## 2.2.0 + +Ip field in ActiveHost is now InternetAddress type instead of string which improve handling of IPv6. + +ActiveHost now contains host name of the address if exist. + +Better naming of methods + ## 2.1.0 Added partly support for searching mdns devices. diff --git a/network_tools/pubspec.yaml b/network_tools/pubspec.yaml index 12dd246..633ae1d 100644 --- a/network_tools/pubspec.yaml +++ b/network_tools/pubspec.yaml @@ -1,6 +1,6 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 2.1.0 +version: 2.2.0 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools/tree/main/network_tools @@ -23,6 +23,6 @@ dependencies: dev_dependencies: # Set of lint rules for Dart. - lint: ^1.8.2 + lint: ^1.10.0 # Writing and running Dart tests. test: ^1.21.4 From 866c46c90d845291c94b8a5594e751f52b25e6c5 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Thu, 28 Jul 2022 20:02:04 +0300 Subject: [PATCH 27/36] Changed ip to address --- README.md | 10 +++--- network_tools/README.md | 10 +++--- network_tools/example/host_scan.dart | 8 ++--- network_tools/example/mdns_scan.dart | 2 +- network_tools/example/port_scan.dart | 10 +++--- network_tools/lib/src/host_scanner.dart | 16 ++++----- .../lib/src/mdns_scanner/mdns_scanner.dart | 6 ++-- network_tools/lib/src/models/active_host.dart | 34 ++++++++++--------- network_tools/lib/src/models/open_port.dart | 2 +- network_tools/lib/src/port_scanner.dart | 28 +++++++-------- 10 files changed, 65 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index ada7426..72a4ae7 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,10 @@ import 'package:network_tools/network_tools.dart'; ### Host Scanner ```dart - String ip = '192.168.1.12'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + String address = '192.168.1.12'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); final stream = HostScanner.discover(subnet, firstSubnet: 1, lastSubnet: 50, progressCallback: (progress) { print('Progress for host discovery : $progress'); @@ -72,7 +72,7 @@ import 'package:network_tools/network_tools.dart'; for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; print( - 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); } ``` diff --git a/network_tools/README.md b/network_tools/README.md index ada7426..72a4ae7 100644 --- a/network_tools/README.md +++ b/network_tools/README.md @@ -26,10 +26,10 @@ import 'package:network_tools/network_tools.dart'; ### Host Scanner ```dart - String ip = '192.168.1.12'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + String address = '192.168.1.12'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); final stream = HostScanner.discover(subnet, firstSubnet: 1, lastSubnet: 50, progressCallback: (progress) { print('Progress for host discovery : $progress'); @@ -72,7 +72,7 @@ import 'package:network_tools/network_tools.dart'; for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; print( - 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); } ``` diff --git a/network_tools/example/host_scan.dart b/network_tools/example/host_scan.dart index 9f6c2da..73deebe 100644 --- a/network_tools/example/host_scan.dart +++ b/network_tools/example/host_scan.dart @@ -11,10 +11,10 @@ void main() { }); final _log = Logger('host_scan'); - const String ip = '192.168.1.1'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + const String address = '192.168.1.1'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); // You can set [firstSubnet] and scan will start from this host in the network. // Similarly set [lastSubnet] and scan will end at this host in the network. diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart index 43000e9..7a913c7 100644 --- a/network_tools/example/mdns_scan.dart +++ b/network_tools/example/mdns_scan.dart @@ -4,7 +4,7 @@ Future main() async { for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; print( - 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); } } diff --git a/network_tools/example/port_scan.dart b/network_tools/example/port_scan.dart index e8c964a..a099321 100644 --- a/network_tools/example/port_scan.dart +++ b/network_tools/example/port_scan.dart @@ -10,10 +10,10 @@ void main() { ); }); final _log = Logger('port_scan'); - const String ip = '192.168.1.1'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + const String address = '192.168.1.1'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); // [New] Scan for a single open port in a subnet // You can set [firstSubnet] and scan will start from this host in the network. @@ -33,7 +33,7 @@ void main() { final OpenPort deviceWithOpenPort = activeHost.openPort[0]; if (deviceWithOpenPort.isOpen) { _log.fine( - 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.ip}', + 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.address}', ); } }, diff --git a/network_tools/lib/src/host_scanner.dart b/network_tools/lib/src/host_scanner.dart index 7adda1f..5e8f247 100644 --- a/network_tools/lib/src/host_scanner.dart +++ b/network_tools/lib/src/host_scanner.dart @@ -12,7 +12,7 @@ class HostScanner { /// Set maxHost to higher value if you are not getting results. /// It won't firstSubnet again unless previous scan is completed due to heavy /// resource consumption. - /// [resultsInIpAscendingOrder] = false will return results faster but not in + /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. static Stream getAllPingableDevices( String subnet, { @@ -20,7 +20,7 @@ class HostScanner { int lastSubnet = 254, int timeoutInSeconds = 1, ProgressCallback? progressCallback, - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { final int maxEnd = getMaxHost(subnet); if (firstSubnet > lastSubnet || @@ -47,7 +47,7 @@ class HostScanner { ); } - if (!resultsInIpAscendingOrder) { + if (!resultsInAddressAscendingOrder) { yield* activeHostsController.stream; } @@ -79,7 +79,7 @@ class HostScanner { final Duration? time = response.time; if (time != null) { final ActiveHost tempActiveHost = - ActiveHost.buildWithIp(ip: host, pingData: pingData); + ActiveHost.buildWithAddress(address: host, pingData: pingData); activeHostsController.add(tempActiveHost); return tempActiveHost; } @@ -89,7 +89,7 @@ class HostScanner { } /// Scans for all hosts that have the specific port that was given. - /// [resultsInIpAscendingOrder] = false will return results faster but not in + /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. static Stream scanDevicesForSinglePort( String subnet, @@ -98,7 +98,7 @@ class HostScanner { int lastSubnet = 254, Duration timeout = const Duration(milliseconds: 2000), ProgressCallback? progressCallback, - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { final int maxEnd = getMaxHost(subnet); if (firstSubnet > lastSubnet || @@ -117,7 +117,7 @@ class HostScanner { final host = '$subnet.$i'; activeHostOpenPortList.add( PortScanner.connectToPort( - ip: host, + address: host, port: port, timeout: timeout, activeHostsController: activeHostsController, @@ -125,7 +125,7 @@ class HostScanner { ); } - if (!resultsInIpAscendingOrder) { + if (!resultsInAddressAscendingOrder) { yield* activeHostsController.stream; } diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 8570d59..8bc45a2 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -27,7 +27,7 @@ class MdnsScanner { final List>> activeHostListsFuture = []; for (final String srvRecord in srvRecordListToSearchIn) { - activeHostListsFuture.add(_findingMdnsWithIp(srvRecord)); + activeHostListsFuture.add(_findingMdnsWithAddress(srvRecord)); } final List activeHostList = []; @@ -40,7 +40,9 @@ class MdnsScanner { return activeHostList; } - static Future> _findingMdnsWithIp(String serviceType) async { + static Future> _findingMdnsWithAddress( + String serviceType, + ) async { final List mdnsFoundList = []; final MDnsClient client = MDnsClient(); diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index 96f02ce..882fb46 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -12,30 +12,33 @@ class ActiveHost extends Comparable { PingData? pingData, this.mdnsInfo, }) { - final String _ip = internetAddress.address; - - if (_ip.contains('.')) { - hostId = _ip.substring(_ip.lastIndexOf('.') + 1, _ip.length); - } else if (_ip.contains(':')) { - hostId = _ip.substring(_ip.lastIndexOf(':') + 1, _ip.length); + final String tempAddress = internetAddress.address; + + if (tempAddress.contains('.')) { + hostId = tempAddress.substring( + tempAddress.lastIndexOf('.') + 1, tempAddress.length); + } else if (tempAddress.contains(':')) { + hostId = tempAddress.substring( + tempAddress.lastIndexOf(':') + 1, tempAddress.length); } else { hostId = '-1'; } - pingData ??= getPingData(_ip); + pingData ??= getPingData(tempAddress); _pingData = pingData; waitingForActiveHostSetupToComplete = setHostNameAndMdns(); } - factory ActiveHost.buildWithIp({ - required String ip, + factory ActiveHost.buildWithAddress({ + required String address, List openPort = const [], PingData? pingData, MdnsInfo? mdnsInfo, }) { - final InternetAddress? internetAddressTemp = InternetAddress.tryParse(ip); + final InternetAddress? internetAddressTemp = + InternetAddress.tryParse(address); if (internetAddressTemp == null) { - throw 'Cant parse ip $ip to InternetAddress'; + throw 'Cant parse address $address to InternetAddress'; } return ActiveHost( internetAddress: internetAddressTemp, @@ -67,7 +70,7 @@ class ActiveHost extends Comparable { String deviceName = generic; PingData get pingData => _pingData; Duration? get responseTime => _pingData.response?.time; - String get ip => internetAddress.address; + String get address => internetAddress.address; /// This var let us know from out side if all the setup got completed. /// Since getting host name is async function [ActiveHost] does not contain @@ -75,11 +78,10 @@ class ActiveHost extends Comparable { late Future waitingForActiveHostSetupToComplete; @override - int get hashCode => internetAddress.address.hashCode; + int get hashCode => address.hashCode; @override - bool operator ==(dynamic o) => - o is ActiveHost && internetAddress.address == o.internetAddress.address; + bool operator ==(dynamic o) => o is ActiveHost && address == o.address; @override int compareTo(ActiveHost other) { @@ -88,7 +90,7 @@ class ActiveHost extends Comparable { @override String toString() { - return 'IP: ${internetAddress.address}, HostId: $hostId, deviceName: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; + return 'Address: $address, HostId: $hostId, deviceName: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; } static PingData getPingData(String host) { diff --git a/network_tools/lib/src/models/open_port.dart b/network_tools/lib/src/models/open_port.dart index 049f6bc..dd79289 100644 --- a/network_tools/lib/src/models/open_port.dart +++ b/network_tools/lib/src/models/open_port.dart @@ -1,4 +1,4 @@ -/// Represents open port for a target IP +/// Represents open port for a target Address class OpenPort { OpenPort(this._port, {this.isOpen = true}); diff --git a/network_tools/lib/src/port_scanner.dart b/network_tools/lib/src/port_scanner.dart index b515882..2074138 100644 --- a/network_tools/lib/src/port_scanner.dart +++ b/network_tools/lib/src/port_scanner.dart @@ -5,7 +5,7 @@ import 'package:network_tools/src/models/callbacks.dart'; import 'package:network_tools/src/models/open_port.dart'; import 'package:universal_io/io.dart'; -/// Scans open port for a target IP or domain. +/// Scans open port for a target Address or domain. class PortScanner { static const int defaultStartPort = 1; static const int defaultEndPort = 1024; @@ -50,10 +50,10 @@ class PortScanner { final List address = await InternetAddress.lookup(target, type: InternetAddressType.IPv4); if (address.isNotEmpty) { - final String hostIP = address[0].address; + final String hostAddress = address[0].address; return connectToPort( activeHostsController: StreamController(), - ip: hostIP, + address: hostAddress, port: port, timeout: timeout, ); @@ -65,19 +65,19 @@ class PortScanner { /// Scans ports only listed in [portList] for a [target]. Progress can be /// retrieved by [progressCallback] /// Tries connecting ports before until [timeout] reached. - /// [resultsInIpAscendingOrder] = false will return results faster but not in + /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. static Stream customDiscover( String target, { List portList = commonPorts, ProgressCallback? progressCallback, Duration timeout = const Duration(milliseconds: 2000), - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { final List address = await InternetAddress.lookup(target, type: InternetAddressType.IPv4); if (address.isNotEmpty) { - final String hostIP = address[0].address; + final String hostAddress = address[0].address; final List> openPortList = []; final StreamController activeHostsController = StreamController(); @@ -86,7 +86,7 @@ class PortScanner { if (portList[k] >= 0 && portList[k] <= 65535) { openPortList.add( connectToPort( - ip: hostIP, + address: hostAddress, port: portList[k], timeout: timeout, activeHostsController: activeHostsController, @@ -95,7 +95,7 @@ class PortScanner { } } - if (!resultsInIpAscendingOrder) { + if (!resultsInAddressAscendingOrder) { yield* activeHostsController.stream; } @@ -124,7 +124,7 @@ class PortScanner { int endPort = defaultEndPort, ProgressCallback? progressCallback, Duration timeout = const Duration(milliseconds: 2000), - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { if (startPort < 0 || endPort < 0 || @@ -146,21 +146,21 @@ class PortScanner { portList: portList, progressCallback: progressCallback, timeout: timeout, - resultsInIpAscendingOrder: resultsInIpAscendingOrder, + resultsInAddressAscendingOrder: resultsInAddressAscendingOrder, ); } static Future connectToPort({ - required String ip, + required String address, required int port, required Duration timeout, required StreamController activeHostsController, }) async { try { - final Socket s = await Socket.connect(ip, port, timeout: timeout); + final Socket s = await Socket.connect(address, port, timeout: timeout); s.destroy(); - final ActiveHost activeHost = - ActiveHost.buildWithIp(ip: ip, openPort: [OpenPort(port)]); + final ActiveHost activeHost = ActiveHost.buildWithAddress( + address: address, openPort: [OpenPort(port)]); activeHostsController.add(activeHost); return activeHost; From 68ac3d35da76e8557226fe698d14ae4dcca6e490 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Thu, 28 Jul 2022 20:21:50 +0300 Subject: [PATCH 28/36] Changed app version and changelog to version 3.0.0 as we did braking changed by changed methods name. --- network_tools/CHANGELOG.md | 9 +++++++-- network_tools/pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/network_tools/CHANGELOG.md b/network_tools/CHANGELOG.md index 70cc00f..d60f1d9 100644 --- a/network_tools/CHANGELOG.md +++ b/network_tools/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log -## 2.2.0 +## 3.0.0 + +**Breaking change** Change most of the methods names + * HostScanner.discover To HostScanner.getAllPingableDevices + * HostScanner.discoverPort to HostScanner.scanDevicesForSinglePort + * PortScanner.discover to PortScanner.scanPortsForSingleDevice Ip field in ActiveHost is now InternetAddress type instead of string which improve handling of IPv6. @@ -14,7 +19,7 @@ Added partly support for searching mdns devices. ## 2.0.0 -**Breaking change**. Bump minimum dart version to 2.17.0. +**Breaking change** Bump minimum dart version to 2.17.0. Updated dart_ping package version to 7.0.1. diff --git a/network_tools/pubspec.yaml b/network_tools/pubspec.yaml index 633ae1d..a0c2567 100644 --- a/network_tools/pubspec.yaml +++ b/network_tools/pubspec.yaml @@ -1,6 +1,6 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 2.2.0 +version: 3.0.0 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools/tree/main/network_tools From 30bd2d523a0e96d8c6ee980ff84801bb6a439b3e Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Thu, 28 Jul 2022 20:24:47 +0300 Subject: [PATCH 29/36] Solved some analysis warnings --- network_tools/example/host_scan.dart | 8 ++++---- network_tools/example/port_scan.dart | 14 +++++++------- network_tools/lib/src/models/active_host.dart | 8 ++++++-- network_tools/lib/src/port_scanner.dart | 4 +++- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/network_tools/example/host_scan.dart b/network_tools/example/host_scan.dart index 73deebe..0849f88 100644 --- a/network_tools/example/host_scan.dart +++ b/network_tools/example/host_scan.dart @@ -10,7 +10,7 @@ void main() { ); }); - final _log = Logger('host_scan'); + final log = Logger('host_scan'); const String address = '192.168.1.1'; // or You can also get address using network_info_plus package // final String? address = await (NetworkInfo().getWifiIP()); @@ -23,7 +23,7 @@ void main() { // firstSubnet: 1, // lastSubnet: 254, progressCallback: (progress) { - _log.finer('Progress for host discovery : $progress'); + log.finer('Progress for host discovery : $progress'); }, ); @@ -31,10 +31,10 @@ void main() { (ActiveHost host) { //Same host can be emitted multiple times //Use Set instead of List - _log.fine('Found device: $host'); + log.fine('Found device: $host'); }, onDone: () { - _log.fine('Scan completed'); + log.fine('Scan completed'); }, ); // Don't forget to cancel the stream when not in use. } diff --git a/network_tools/example/port_scan.dart b/network_tools/example/port_scan.dart index a099321..436bdd1 100644 --- a/network_tools/example/port_scan.dart +++ b/network_tools/example/port_scan.dart @@ -9,7 +9,7 @@ void main() { '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}', ); }); - final _log = Logger('port_scan'); + final log = Logger('port_scan'); const String address = '192.168.1.1'; // or You can also get address using network_info_plus package // final String? address = await (NetworkInfo().getWifiIP()); @@ -24,7 +24,7 @@ void main() { // firstSubnet: 1, // lastSubnet: 254, progressCallback: (progress) { - _log.finer('Progress for port discovery on host : $progress'); + log.finer('Progress for port discovery on host : $progress'); }, ); @@ -32,13 +32,13 @@ void main() { (activeHost) { final OpenPort deviceWithOpenPort = activeHost.openPort[0]; if (deviceWithOpenPort.isOpen) { - _log.fine( + log.fine( 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.address}', ); } }, onDone: () { - _log.fine('Port Scan completed'); + log.fine('Port Scan completed'); }, ); // Don't forget to cancel the stream when not in use. @@ -49,18 +49,18 @@ void main() { // startPort: 1, endPort: 9400, progressCallback: (progress) { - _log.finer('Progress for port discovery : $progress'); + log.finer('Progress for port discovery : $progress'); }, ).listen( (activeHost) { final OpenPort deviceWithOpenPort = activeHost.openPort[0]; if (deviceWithOpenPort.isOpen) { - _log.fine('Found open port: ${deviceWithOpenPort.port}'); + log.fine('Found open port: ${deviceWithOpenPort.port}'); } }, onDone: () { - _log.fine('Port Scan from 1 to 9400 completed'); + log.fine('Port Scan from 1 to 9400 completed'); }, ); } diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index 882fb46..2385ee3 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -16,10 +16,14 @@ class ActiveHost extends Comparable { if (tempAddress.contains('.')) { hostId = tempAddress.substring( - tempAddress.lastIndexOf('.') + 1, tempAddress.length); + tempAddress.lastIndexOf('.') + 1, + tempAddress.length, + ); } else if (tempAddress.contains(':')) { hostId = tempAddress.substring( - tempAddress.lastIndexOf(':') + 1, tempAddress.length); + tempAddress.lastIndexOf(':') + 1, + tempAddress.length, + ); } else { hostId = '-1'; } diff --git a/network_tools/lib/src/port_scanner.dart b/network_tools/lib/src/port_scanner.dart index 2074138..6583384 100644 --- a/network_tools/lib/src/port_scanner.dart +++ b/network_tools/lib/src/port_scanner.dart @@ -160,7 +160,9 @@ class PortScanner { final Socket s = await Socket.connect(address, port, timeout: timeout); s.destroy(); final ActiveHost activeHost = ActiveHost.buildWithAddress( - address: address, openPort: [OpenPort(port)]); + address: address, + openPort: [OpenPort(port)], + ); activeHostsController.add(activeHost); return activeHost; From d6f9505642e1773eaa7afb52ddcba20e0f4e7094 Mon Sep 17 00:00:00 2001 From: Guy Luz Date: Thu, 28 Jul 2022 20:55:59 +0300 Subject: [PATCH 30/36] Fix issue #40 and #3 (#41) * Updated dependencies * Added comments to each dependency * Decided to update min dart version to 2.17.0 (even though pub get didn't show any errors) because it is the min version in dart_ping 7.0.0 * Reverted min dart version back to 2.12.0 as it is not mandatory * Updated min dart version to 2.17.0. * Added a function to find some of the mdns devices on the network * Added todo part for searchMdnsDevices and more srv record. * Inserting the name from the mdns into _make var in ActiveHost * More srv records. * More srv records. * Added mdns scanner to example and Changelog. Changed network_tool version to 2.1.0 * Remove Future from main function in example folder * Made searching for mdns process better for Linux if avahi-browse or mdns-scan is installed on it. * Removing print * Added small comment for future mac implementation. * Small fix to srv results as avahi command does not return all of them. * Added a lot entry's to the tcpSrvRecords list, added udpSrvRecordList. * Added the udp list to the search. Small fix for multiple devices with the same mDNS name different address. * Made mdns_scanner accessible to users of the package. * Fix for #3. Improved pub.dev score. Change method names to be more precise. * Each ActiveHost object will automatically get host name when waitingForActiveHostSetupToComplete is done, fix for #3. * Fix for #44 * Updated package version to 2.2.0, updated changelog for the new version .Updated lint to 1.10.0. * Changed ip to address * Changed app version and changelog to version 3.0.0 as we did braking changed by changed methods name. * Solved some analysis warnings --- README.md | 10 +- network_tools/CHANGELOG.md | 15 ++- network_tools/README.md | 10 +- network_tools/example/host_scan.dart | 18 ++-- network_tools/example/mdns_scan.dart | 4 +- network_tools/example/port_scan.dart | 29 ++--- network_tools/lib/src/host_scanner.dart | 20 ++-- .../lib/src/mdns_scanner/mdns_scanner.dart | 13 +-- network_tools/lib/src/models/active_host.dart | 100 ++++++++++++++---- network_tools/lib/src/models/mdns_info.dart | 1 + network_tools/lib/src/models/open_port.dart | 2 +- network_tools/lib/src/port_scanner.dart | 31 +++--- network_tools/pubspec.yaml | 4 +- 13 files changed, 166 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index ada7426..72a4ae7 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,10 @@ import 'package:network_tools/network_tools.dart'; ### Host Scanner ```dart - String ip = '192.168.1.12'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + String address = '192.168.1.12'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); final stream = HostScanner.discover(subnet, firstSubnet: 1, lastSubnet: 50, progressCallback: (progress) { print('Progress for host discovery : $progress'); @@ -72,7 +72,7 @@ import 'package:network_tools/network_tools.dart'; for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; print( - 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); } ``` diff --git a/network_tools/CHANGELOG.md b/network_tools/CHANGELOG.md index c3b491e..d60f1d9 100644 --- a/network_tools/CHANGELOG.md +++ b/network_tools/CHANGELOG.md @@ -1,12 +1,25 @@ # Change Log +## 3.0.0 + +**Breaking change** Change most of the methods names + * HostScanner.discover To HostScanner.getAllPingableDevices + * HostScanner.discoverPort to HostScanner.scanDevicesForSinglePort + * PortScanner.discover to PortScanner.scanPortsForSingleDevice + +Ip field in ActiveHost is now InternetAddress type instead of string which improve handling of IPv6. + +ActiveHost now contains host name of the address if exist. + +Better naming of methods + ## 2.1.0 Added partly support for searching mdns devices. ## 2.0.0 -**Breaking change**. Bump minimum dart version to 2.17.0. +**Breaking change** Bump minimum dart version to 2.17.0. Updated dart_ping package version to 7.0.1. diff --git a/network_tools/README.md b/network_tools/README.md index ada7426..72a4ae7 100644 --- a/network_tools/README.md +++ b/network_tools/README.md @@ -26,10 +26,10 @@ import 'package:network_tools/network_tools.dart'; ### Host Scanner ```dart - String ip = '192.168.1.12'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + String address = '192.168.1.12'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); final stream = HostScanner.discover(subnet, firstSubnet: 1, lastSubnet: 50, progressCallback: (progress) { print('Progress for host discovery : $progress'); @@ -72,7 +72,7 @@ import 'package:network_tools/network_tools.dart'; for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; print( - 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); } ``` diff --git a/network_tools/example/host_scan.dart b/network_tools/example/host_scan.dart index 7f82b58..0849f88 100644 --- a/network_tools/example/host_scan.dart +++ b/network_tools/example/host_scan.dart @@ -10,20 +10,20 @@ void main() { ); }); - final _log = Logger('host_scan'); - const String ip = '192.168.1.1'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + final log = Logger('host_scan'); + const String address = '192.168.1.1'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); // You can set [firstSubnet] and scan will start from this host in the network. // Similarly set [lastSubnet] and scan will end at this host in the network. - final stream = HostScanner.discover( + final stream = HostScanner.getAllPingableDevices( subnet, // firstSubnet: 1, // lastSubnet: 254, progressCallback: (progress) { - _log.finer('Progress for host discovery : $progress'); + log.finer('Progress for host discovery : $progress'); }, ); @@ -31,10 +31,10 @@ void main() { (ActiveHost host) { //Same host can be emitted multiple times //Use Set instead of List - _log.fine('Found device: $host'); + log.fine('Found device: $host'); }, onDone: () { - _log.fine('Scan completed'); + log.fine('Scan completed'); }, ); // Don't forget to cancel the stream when not in use. } diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart index becac00..7a913c7 100644 --- a/network_tools/example/mdns_scan.dart +++ b/network_tools/example/mdns_scan.dart @@ -1,12 +1,10 @@ import 'package:network_tools/network_tools.dart'; -import 'package:network_tools/src/mdns_scanner/mdns_scanner.dart'; -import 'package:network_tools/src/models/mdns_info.dart'; Future main() async { for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; print( - 'IP: ${activeHost.ip}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', + 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); } } diff --git a/network_tools/example/port_scan.dart b/network_tools/example/port_scan.dart index 573ab07..436bdd1 100644 --- a/network_tools/example/port_scan.dart +++ b/network_tools/example/port_scan.dart @@ -9,22 +9,22 @@ void main() { '${DateFormat.Hms().format(record.time)}: ${record.level.name}: ${record.loggerName}: ${record.message}', ); }); - final _log = Logger('port_scan'); - const String ip = '192.168.1.1'; - // or You can also get ip using network_info_plus package - // final String? ip = await (NetworkInfo().getWifiIP()); - final String subnet = ip.substring(0, ip.lastIndexOf('.')); + final log = Logger('port_scan'); + const String address = '192.168.1.1'; + // or You can also get address using network_info_plus package + // final String? address = await (NetworkInfo().getWifiIP()); + final String subnet = address.substring(0, address.lastIndexOf('.')); // [New] Scan for a single open port in a subnet // You can set [firstSubnet] and scan will start from this host in the network. // Similarly set [lastSubnet] and scan will end at this host in the network. - final stream2 = HostScanner.discoverPort( + final stream2 = HostScanner.scanDevicesForSinglePort( subnet, 53, // firstSubnet: 1, // lastSubnet: 254, progressCallback: (progress) { - _log.finer('Progress for port discovery on host : $progress'); + log.finer('Progress for port discovery on host : $progress'); }, ); @@ -32,34 +32,35 @@ void main() { (activeHost) { final OpenPort deviceWithOpenPort = activeHost.openPort[0]; if (deviceWithOpenPort.isOpen) { - _log.fine( - 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.ip}'); + log.fine( + 'Found open port: ${deviceWithOpenPort.port} on ${activeHost.address}', + ); } }, onDone: () { - _log.fine('Port Scan completed'); + log.fine('Port Scan completed'); }, ); // Don't forget to cancel the stream when not in use. const String target = '192.168.1.1'; - PortScanner.discover( + PortScanner.scanPortsForSingleDevice( target, // Scan will start from this port. // startPort: 1, endPort: 9400, progressCallback: (progress) { - _log.finer('Progress for port discovery : $progress'); + log.finer('Progress for port discovery : $progress'); }, ).listen( (activeHost) { final OpenPort deviceWithOpenPort = activeHost.openPort[0]; if (deviceWithOpenPort.isOpen) { - _log.fine('Found open port : ${deviceWithOpenPort.port}'); + log.fine('Found open port: ${deviceWithOpenPort.port}'); } }, onDone: () { - _log.fine('Port Scan from 1 to 9400 completed'); + log.fine('Port Scan from 1 to 9400 completed'); }, ); } diff --git a/network_tools/lib/src/host_scanner.dart b/network_tools/lib/src/host_scanner.dart index 978121f..5e8f247 100644 --- a/network_tools/lib/src/host_scanner.dart +++ b/network_tools/lib/src/host_scanner.dart @@ -12,15 +12,15 @@ class HostScanner { /// Set maxHost to higher value if you are not getting results. /// It won't firstSubnet again unless previous scan is completed due to heavy /// resource consumption. - /// [resultsInIpAscendingOrder] = false will return results faster but not in + /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream discover( + static Stream getAllPingableDevices( String subnet, { int firstSubnet = 1, int lastSubnet = 254, int timeoutInSeconds = 1, ProgressCallback? progressCallback, - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { final int maxEnd = getMaxHost(subnet); if (firstSubnet > lastSubnet || @@ -47,7 +47,7 @@ class HostScanner { ); } - if (!resultsInIpAscendingOrder) { + if (!resultsInAddressAscendingOrder) { yield* activeHostsController.stream; } @@ -79,7 +79,7 @@ class HostScanner { final Duration? time = response.time; if (time != null) { final ActiveHost tempActiveHost = - ActiveHost(host, pingData: pingData); + ActiveHost.buildWithAddress(address: host, pingData: pingData); activeHostsController.add(tempActiveHost); return tempActiveHost; } @@ -89,16 +89,16 @@ class HostScanner { } /// Scans for all hosts that have the specific port that was given. - /// [resultsInIpAscendingOrder] = false will return results faster but not in + /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream discoverPort( + static Stream scanDevicesForSinglePort( String subnet, int port, { int firstSubnet = 1, int lastSubnet = 254, Duration timeout = const Duration(milliseconds: 2000), ProgressCallback? progressCallback, - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { final int maxEnd = getMaxHost(subnet); if (firstSubnet > lastSubnet || @@ -117,7 +117,7 @@ class HostScanner { final host = '$subnet.$i'; activeHostOpenPortList.add( PortScanner.connectToPort( - ip: host, + address: host, port: port, timeout: timeout, activeHostsController: activeHostsController, @@ -125,7 +125,7 @@ class HostScanner { ); } - if (!resultsInIpAscendingOrder) { + if (!resultsInAddressAscendingOrder) { yield* activeHostsController.stream; } diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index a107cc9..8bc45a2 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -4,11 +4,9 @@ import 'package:multicast_dns/multicast_dns.dart'; import 'package:network_tools/network_tools.dart'; import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list.dart'; import 'package:network_tools/src/mdns_scanner/list_of_srv_records.dart'; -import 'package:network_tools/src/models/mdns_info.dart'; class MdnsScanner { /// This method searching for all the mdns devices in the network. - /// Shows only results for IPv4. /// TODO: The implementation is **Lacking!** and will not find all the /// TODO: results that actual exist in the network!, only some of them. /// TODO: This is because missing functionality in dart @@ -29,7 +27,7 @@ class MdnsScanner { final List>> activeHostListsFuture = []; for (final String srvRecord in srvRecordListToSearchIn) { - activeHostListsFuture.add(_findingMdnsWithIp(srvRecord)); + activeHostListsFuture.add(_findingMdnsWithAddress(srvRecord)); } final List activeHostList = []; @@ -42,7 +40,9 @@ class MdnsScanner { return activeHostList; } - static Future> _findingMdnsWithIp(String serviceType) async { + static Future> _findingMdnsWithAddress( + String serviceType, + ) async { final List mdnsFoundList = []; final MDnsClient client = MDnsClient(); @@ -74,11 +74,8 @@ class MdnsScanner { // There can be multiple devices with the same name for (final InternetAddress internetAddress in internetAddressList) { - final String hostIp = internetAddress.address; - final ActiveHost tempHost = ActiveHost( - hostIp, - deviceName: foundMdns.getOnlyTheStartOfMdnsName(), + internetAddress: internetAddress, mdnsInfo: foundMdns, ); listOfActiveHost.add(tempHost); diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index d68e0de..2385ee3 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -1,32 +1,62 @@ import 'package:dart_ping/dart_ping.dart'; import 'package:network_tools/src/models/mdns_info.dart'; import 'package:network_tools/src/models/open_port.dart'; +import 'package:universal_io/io.dart'; /// ActiveHost which implements comparable /// By default sort by hostId ascending class ActiveHost extends Comparable { - ActiveHost( - this._ip, { + ActiveHost({ + required this.internetAddress, this.openPort = const [], PingData? pingData, - this.deviceName = generic, this.mdnsInfo, }) { - if (_ip.contains('.')) { - hostId = int.parse(_ip.substring(_ip.lastIndexOf('.') + 1, _ip.length)); - } else if (_ip.contains(':')) { - hostId = int.parse(_ip.substring(_ip.lastIndexOf(':') + 1, _ip.length)); + final String tempAddress = internetAddress.address; + + if (tempAddress.contains('.')) { + hostId = tempAddress.substring( + tempAddress.lastIndexOf('.') + 1, + tempAddress.length, + ); + } else if (tempAddress.contains(':')) { + hostId = tempAddress.substring( + tempAddress.lastIndexOf(':') + 1, + tempAddress.length, + ); } else { - hostId = -1; + hostId = '-1'; } - pingData ??= getPingData(_ip); + + pingData ??= getPingData(tempAddress); _pingData = pingData; + waitingForActiveHostSetupToComplete = setHostNameAndMdns(); + } + + factory ActiveHost.buildWithAddress({ + required String address, + List openPort = const [], + PingData? pingData, + MdnsInfo? mdnsInfo, + }) { + final InternetAddress? internetAddressTemp = + InternetAddress.tryParse(address); + if (internetAddressTemp == null) { + throw 'Cant parse address $address to InternetAddress'; + } + return ActiveHost( + internetAddress: internetAddressTemp, + openPort: openPort, + pingData: pingData, + mdnsInfo: mdnsInfo, + ); } static const generic = 'Generic Device'; - static const router = 'Router'; - final String _ip; - late int hostId; + InternetAddress internetAddress; + late String hostId; + String? hostName; + String? weirdHostName; late final PingData _pingData; /// Mdns information of this device @@ -35,19 +65,27 @@ class ActiveHost extends Comparable { /// List of all the open port of this device List openPort; - String get ip => _ip; - /// This device name does not following any guideline and is just some name - /// that we find for the device - final String deviceName; + /// that we can show for the device. + /// Preferably hostName, if not than mDNS name, if not than will get the + /// value of [generic]. + /// This value **can change after the object got created** since getting + /// host name of device is running async function. + String deviceName = generic; PingData get pingData => _pingData; Duration? get responseTime => _pingData.response?.time; + String get address => internetAddress.address; + + /// This var let us know from out side if all the setup got completed. + /// Since getting host name is async function [ActiveHost] does not contain + /// all of the values when the constructor completed + late Future waitingForActiveHostSetupToComplete; @override - int get hashCode => _ip.hashCode; + int get hashCode => address.hashCode; @override - bool operator ==(dynamic o) => o is ActiveHost && _ip == o._ip; + bool operator ==(dynamic o) => o is ActiveHost && address == o.address; @override int compareTo(ActiveHost other) { @@ -56,7 +94,7 @@ class ActiveHost extends Comparable { @override String toString() { - return 'IP : $_ip, HostId : $hostId, make: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; + return 'Address: $address, HostId: $hostId, deviceName: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; } static PingData getPingData(String host) { @@ -75,4 +113,28 @@ class ActiveHost extends Comparable { }); return tempPingData; } + + /// Try to find the host name of this device, if not exist host name will + /// stay null + Future setHostNameAndMdns() async { + // For some reason when internetAddress.host get called before the reverse + // there is weired value + weirdHostName = internetAddress.host; + + // In the future if mdnsInfo is null it will execute a search + // Currently the functionality is missing in dart multicast_dns package + // https://github.com/flutter/flutter/issues/96755 + + try { + internetAddress = await internetAddress.reverse(); + hostName = internetAddress.host; + deviceName = hostName!; + } catch (e) { + // Some devices does not have host name and the reverse search will just + // throw exception. + if (mdnsInfo != null) { + deviceName = mdnsInfo!.getOnlyTheStartOfMdnsName(); + } + } + } } diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart index e121aff..340859e 100644 --- a/network_tools/lib/src/models/mdns_info.dart +++ b/network_tools/lib/src/models/mdns_info.dart @@ -18,6 +18,7 @@ class MdnsInfo { /// Srv record of the dns String mdnsServiceType; + /// mDNS name without the ._tcp.local String getOnlyTheStartOfMdnsName() { return mdnsName.substring(0, mdnsName.indexOf('.')); } diff --git a/network_tools/lib/src/models/open_port.dart b/network_tools/lib/src/models/open_port.dart index 049f6bc..dd79289 100644 --- a/network_tools/lib/src/models/open_port.dart +++ b/network_tools/lib/src/models/open_port.dart @@ -1,4 +1,4 @@ -/// Represents open port for a target IP +/// Represents open port for a target Address class OpenPort { OpenPort(this._port, {this.isOpen = true}); diff --git a/network_tools/lib/src/port_scanner.dart b/network_tools/lib/src/port_scanner.dart index f389681..6583384 100644 --- a/network_tools/lib/src/port_scanner.dart +++ b/network_tools/lib/src/port_scanner.dart @@ -5,7 +5,7 @@ import 'package:network_tools/src/models/callbacks.dart'; import 'package:network_tools/src/models/open_port.dart'; import 'package:universal_io/io.dart'; -/// Scans open port for a target IP or domain. +/// Scans open port for a target Address or domain. class PortScanner { static const int defaultStartPort = 1; static const int defaultEndPort = 1024; @@ -50,10 +50,10 @@ class PortScanner { final List address = await InternetAddress.lookup(target, type: InternetAddressType.IPv4); if (address.isNotEmpty) { - final String hostIP = address[0].address; + final String hostAddress = address[0].address; return connectToPort( activeHostsController: StreamController(), - ip: hostIP, + address: hostAddress, port: port, timeout: timeout, ); @@ -65,19 +65,19 @@ class PortScanner { /// Scans ports only listed in [portList] for a [target]. Progress can be /// retrieved by [progressCallback] /// Tries connecting ports before until [timeout] reached. - /// [resultsInIpAscendingOrder] = false will return results faster but not in + /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. static Stream customDiscover( String target, { List portList = commonPorts, ProgressCallback? progressCallback, Duration timeout = const Duration(milliseconds: 2000), - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { final List address = await InternetAddress.lookup(target, type: InternetAddressType.IPv4); if (address.isNotEmpty) { - final String hostIP = address[0].address; + final String hostAddress = address[0].address; final List> openPortList = []; final StreamController activeHostsController = StreamController(); @@ -86,7 +86,7 @@ class PortScanner { if (portList[k] >= 0 && portList[k] <= 65535) { openPortList.add( connectToPort( - ip: hostIP, + address: hostAddress, port: portList[k], timeout: timeout, activeHostsController: activeHostsController, @@ -95,7 +95,7 @@ class PortScanner { } } - if (!resultsInIpAscendingOrder) { + if (!resultsInAddressAscendingOrder) { yield* activeHostsController.stream; } @@ -118,13 +118,13 @@ class PortScanner { /// Scans port from [startPort] to [endPort] of [target]. Progress can be /// retrieved by [progressCallback] /// Tries connecting ports before until [timeout] reached. - static Stream discover( + static Stream scanPortsForSingleDevice( String target, { int startPort = defaultStartPort, int endPort = defaultEndPort, ProgressCallback? progressCallback, Duration timeout = const Duration(milliseconds: 2000), - bool resultsInIpAscendingOrder = true, + bool resultsInAddressAscendingOrder = true, }) async* { if (startPort < 0 || endPort < 0 || @@ -146,20 +146,23 @@ class PortScanner { portList: portList, progressCallback: progressCallback, timeout: timeout, - resultsInIpAscendingOrder: resultsInIpAscendingOrder, + resultsInAddressAscendingOrder: resultsInAddressAscendingOrder, ); } static Future connectToPort({ - required String ip, + required String address, required int port, required Duration timeout, required StreamController activeHostsController, }) async { try { - final Socket s = await Socket.connect(ip, port, timeout: timeout); + final Socket s = await Socket.connect(address, port, timeout: timeout); s.destroy(); - final ActiveHost activeHost = ActiveHost(ip, openPort: [OpenPort(port)]); + final ActiveHost activeHost = ActiveHost.buildWithAddress( + address: address, + openPort: [OpenPort(port)], + ); activeHostsController.add(activeHost); return activeHost; diff --git a/network_tools/pubspec.yaml b/network_tools/pubspec.yaml index 12dd246..a0c2567 100644 --- a/network_tools/pubspec.yaml +++ b/network_tools/pubspec.yaml @@ -1,6 +1,6 @@ name: network_tools description: Networking Tools library which can help you discover open ports, devices on subnet and many other things. -version: 2.1.0 +version: 3.0.0 issue_tracker: https://github.com/git-elliot/network_tools/issues repository: https://github.com/git-elliot/network_tools/tree/main/network_tools @@ -23,6 +23,6 @@ dependencies: dev_dependencies: # Set of lint rules for Dart. - lint: ^1.8.2 + lint: ^1.10.0 # Writing and running Dart tests. test: ^1.21.4 From 5e7616a43e8474a3eaf4255e402630d3f6570cf4 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sat, 30 Jul 2022 23:05:48 +0300 Subject: [PATCH 31/36] Small fix for rear cases where DNS lookup crashes. --- network_tools/lib/src/mdns_scanner/mdns_scanner.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 8bc45a2..e2c053d 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -69,9 +69,13 @@ class MdnsScanner { final List listOfActiveHost = []; for (final MdnsInfo foundMdns in mdnsFoundList) { - final List internetAddressList = - await InternetAddress.lookup(foundMdns.mdnsSrvTarget); - + final List? internetAddressList; + try { + internetAddressList = + await InternetAddress.lookup(foundMdns.mdnsSrvTarget); + } catch (e) { + continue; + } // There can be multiple devices with the same name for (final InternetAddress internetAddress in internetAddressList) { final ActiveHost tempHost = ActiveHost( From 80462cb2801081cfc9746a0f987cb9dcf53c363e Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Mon, 1 Aug 2022 20:17:36 +0300 Subject: [PATCH 32/36] Added _ewelink to srv list. Added a way for users to forceUseOfSavedSrvRecordList. Searching srv list on linux will now also use avahi-browse as just using mdns-scan does not retrieve the full results. --- .../get_srv_list_by_os/srv_list_linux.dart | 114 +++++++++--------- .../src/mdns_scanner/list_of_srv_records.dart | 1 + .../lib/src/mdns_scanner/mdns_scanner.dart | 10 +- 3 files changed, 67 insertions(+), 58 deletions(-) diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart index e4c3a14..1781569 100644 --- a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart @@ -7,9 +7,7 @@ class SrvListLinux { final HashSet srvList = HashSet(); try { - // Using this command is missing some results and could make the rest of - // the program not search all needed srv types. - // srvList.addAll(await runAvahiBrowseCommand()); + srvList.addAll(await runAvahiBrowseCommand()); srvList.addAll(await runMdnsScanCommand()); } catch (e) { print('Error:\n$e'); @@ -25,39 +23,42 @@ class SrvListLinux { final List srvListAvahi = []; List resultForEachLine = []; - - await shell.run( - ''' + try { + await shell.run( + ''' timeout 2s avahi-browse --all -p ''', - ).onError((ShellException error, stackTrace) { - // The command should return error as we are killing it with the command timeout - - final String? resultStderr = error.result?.stderr.toString(); - if (resultStderr != null && - resultStderr.contains('No such file or directory')) { - print( - 'You can make the mdns process better by installing `avahi-browse`', - ); - return []; - } - final String? resultStdout = error.result?.stdout.toString(); - if (resultStdout == null) { - return []; - } - resultForEachLine = resultStdout.split('\n'); - - return []; - }); + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout + + final String? resultStderr = error.result?.stderr.toString(); + if (resultStderr != null && + resultStderr.contains('No such file or directory')) { + print( + 'You can make the mdns process better by installing `avahi-browse`', + ); + return []; + } + final String? resultStdout = error.result?.stdout.toString(); + if (resultStdout == null) { + return []; + } + resultForEachLine = resultStdout.split('\n'); - for (final String resultLine in resultForEachLine) { - final List lineSeparated = resultLine.split(';'); - if (lineSeparated.length >= 6) { - final String srvString = lineSeparated[lineSeparated.length - 2]; - if (!srvString.contains(' ')) { - srvListAvahi.add(srvString); + return []; + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split(';'); + if (lineSeparated.length >= 6) { + final String srvString = lineSeparated[lineSeparated.length - 2]; + if (!srvString.contains(' ')) { + srvListAvahi.add(srvString); + } } } + } catch (e) { + print('Error getting info from avahi-browse\n$e'); } return srvListAvahi; } @@ -70,37 +71,40 @@ timeout 2s avahi-browse --all -p final List srvListMdnsScan = []; List resultForEachLine = []; - - await shell.run( - ''' + try { + await shell.run( + ''' timeout 2s mdns-scan ''', - ).onError((ShellException error, stackTrace) { - // The command should return error as we are killing it with the command timeout + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout - final String? resultStderr = error.result?.stderr.toString(); + final String? resultStderr = error.result?.stderr.toString(); + + if (resultStderr == null || + (resultStderr.contains('No such file or directory'))) { + print( + 'You can make the mdns process better by installing `mdns-scan`', + ); + return []; + } + resultForEachLine = resultStderr.split('\n'); - if (resultStderr == null || - (resultStderr.contains('No such file or directory'))) { - print( - 'You can make the mdns process better by installing `mdns-scan`', - ); return []; - } - resultForEachLine = resultStderr.split('\n'); - - return []; - }); - - for (final String resultLine in resultForEachLine) { - final List lineSeparated = resultLine.split('.'); - if (lineSeparated.length >= 4) { - final String srvString = - '${lineSeparated[lineSeparated.length - 3]}.${lineSeparated[lineSeparated.length - 2]}'; - if (!srvString.contains(' ') && srvString != '.') { - srvListMdnsScan.add(srvString); + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split('.'); + if (lineSeparated.length >= 4) { + final String srvString = + '${lineSeparated[lineSeparated.length - 3]}.${lineSeparated[lineSeparated.length - 2]}'; + if (!srvString.contains(' ') && srvString != '.') { + srvListMdnsScan.add(srvString); + } } } + } catch (e) { + print('Error getting info from mdns-scan\n$e'); } return srvListMdnsScan; } diff --git a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart index 155e444..16dd215 100644 --- a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart +++ b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart @@ -70,6 +70,7 @@ List tcpSrvRecordsList = [ '_zwave-js-server._tcp', // "domain": "zwave_js" '_axis-video._tcp', // "properties": { "macaddress": "00408c*" } "properties": { "macaddress": "accc8e*" } "properties": { "macaddress": "b8a44f*" } '_androidtvremote2._tcp', + '_ewelink._tcp', ]; List udpSrvRecordsList = [ diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index e2c053d..9cd46ba 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -13,12 +13,16 @@ class MdnsScanner { /// TODO: https://github.com/flutter/flutter/issues/97210 /// TODO: In some cases we resolve this missing functionality using /// TODO: specific os tools. - static Future> searchMdnsDevices() async { + static Future> searchMdnsDevices({ + bool forceUseOfSavedSrvRecordList = false, + }) async { List srvRecordListToSearchIn; final List? srvRecordsFromOs = await SrvList.getSrvRecordList(); - if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) { + if (srvRecordsFromOs == null || + srvRecordsFromOs.isEmpty || + forceUseOfSavedSrvRecordList) { srvRecordListToSearchIn = tcpSrvRecordsList; srvRecordListToSearchIn.addAll(udpSrvRecordsList); } else { @@ -72,7 +76,7 @@ class MdnsScanner { final List? internetAddressList; try { internetAddressList = - await InternetAddress.lookup(foundMdns.mdnsSrvTarget); + await InternetAddress.lookup(foundMdns.mdnsSrvTarget); } catch (e) { continue; } From 5bcfef394afdbefab412e7ef1c040aa8ebcd2707 Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Tue, 2 Aug 2022 00:14:35 +0300 Subject: [PATCH 33/36] MdnsInfo now also saves SrvResourceRecord and PtrResourceRecord objects from multicast_dns package as it contains more info about the mdns device. --- .../lib/src/mdns_scanner/mdns_scanner.dart | 7 ++-- network_tools/lib/src/models/mdns_info.dart | 35 +++++++++++++------ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 9cd46ba..380c697 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -60,11 +60,8 @@ class MdnsScanner { ResourceRecordQuery.service(ptr.domainName), )) { final MdnsInfo mdnsFound = MdnsInfo( - mdnsName: srv.name, - mdnsPort: srv.port, - mdnsDomainName: ptr.domainName, - mdnsServiceType: serviceType, - mdnsSrvTarget: srv.target, + srvResourceRecord: srv, + ptrResourceRecord: ptr, ); mdnsFoundList.add(mdnsFound); } diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart index 340859e..5ca5946 100644 --- a/network_tools/lib/src/models/mdns_info.dart +++ b/network_tools/lib/src/models/mdns_info.dart @@ -1,22 +1,37 @@ +import 'package:multicast_dns/multicast_dns.dart'; + class MdnsInfo { MdnsInfo({ - required this.mdnsName, - required this.mdnsPort, - required this.mdnsDomainName, - required this.mdnsServiceType, - required this.mdnsSrvTarget, + required this.srvResourceRecord, + required this.ptrResourceRecord, }); /// Also can be called target - String mdnsName; - String mdnsSrvTarget; - int mdnsPort; + String get mdnsName => srvResourceRecord.name; + + String get mdnsSrvTarget => srvResourceRecord.target; + int get mdnsPort => srvResourceRecord.port; /// Also can be called bundleId - String mdnsDomainName; + String get mdnsDomainName => ptrResourceRecord.domainName; /// Srv record of the dns - String mdnsServiceType; + String get mdnsServiceType { + final List ptrNameSplit = ptrResourceRecord.name.split('.'); + String tempString = ''; + if (ptrNameSplit.isNotEmpty) { + tempString = ptrNameSplit[0]; + } + if (ptrNameSplit.length >= 2) { + tempString = '$tempString.${ptrNameSplit[1]}'; + } + + return tempString; + } + + SrvResourceRecord srvResourceRecord; + + PtrResourceRecord ptrResourceRecord; /// mDNS name without the ._tcp.local String getOnlyTheStartOfMdnsName() { From de7a961bfca731089045d8c61db27979717b839e Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Wed, 3 Aug 2022 13:08:10 +0300 Subject: [PATCH 34/36] Made the code easier to work with as developer. --- network_tools/example/host_scan.dart | 4 +- network_tools/example/mdns_scan.dart | 2 +- .../lib/src/mdns_scanner/mdns_scanner.dart | 2 +- network_tools/lib/src/models/active_host.dart | 69 ++++++++++++++----- 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/network_tools/example/host_scan.dart b/network_tools/example/host_scan.dart index 0849f88..8aa0728 100644 --- a/network_tools/example/host_scan.dart +++ b/network_tools/example/host_scan.dart @@ -28,10 +28,10 @@ void main() { ); stream.listen( - (ActiveHost host) { + (ActiveHost host) async { //Same host can be emitted multiple times //Use Set instead of List - log.fine('Found device: $host'); + log.fine('Found device: ${await host.toStringFull()}'); }, onDone: () { log.fine('Scan completed'); diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart index 7a913c7..f13ba66 100644 --- a/network_tools/example/mdns_scan.dart +++ b/network_tools/example/mdns_scan.dart @@ -2,7 +2,7 @@ import 'package:network_tools/network_tools.dart'; Future main() async { for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { - final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; + final MdnsInfo? mdnsInfo = await activeHost.mdnsInfo; print( 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 380c697..8293f45 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -81,7 +81,7 @@ class MdnsScanner { for (final InternetAddress internetAddress in internetAddressList) { final ActiveHost tempHost = ActiveHost( internetAddress: internetAddress, - mdnsInfo: foundMdns, + mdnsInfoVar: foundMdns, ); listOfActiveHost.add(tempHost); } diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index 2385ee3..efdfd24 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -10,7 +10,7 @@ class ActiveHost extends Comparable { required this.internetAddress, this.openPort = const [], PingData? pingData, - this.mdnsInfo, + MdnsInfo? mdnsInfoVar, }) { final String tempAddress = internetAddress.address; @@ -30,7 +30,20 @@ class ActiveHost extends Comparable { pingData ??= getPingData(tempAddress); _pingData = pingData; - waitingForActiveHostSetupToComplete = setHostNameAndMdns(); + + hostName = setHostInfo(); + + // For some reason when internetAddress.host get called before the reverse + // there is weired value + weirdHostName = internetAddress.host; + + if (mdnsInfoVar != null) { + mdnsInfo = Future.value(mdnsInfoVar); + } else { + mdnsInfo = setMdnsInfo(); + } + + deviceName = setDeviceName(); } factory ActiveHost.buildWithAddress({ @@ -48,19 +61,19 @@ class ActiveHost extends Comparable { internetAddress: internetAddressTemp, openPort: openPort, pingData: pingData, - mdnsInfo: mdnsInfo, + mdnsInfoVar: mdnsInfo, ); } static const generic = 'Generic Device'; InternetAddress internetAddress; late String hostId; - String? hostName; - String? weirdHostName; + late Future hostName; + late String weirdHostName; late final PingData _pingData; /// Mdns information of this device - MdnsInfo? mdnsInfo; + late Future mdnsInfo; /// List of all the open port of this device List openPort; @@ -71,16 +84,11 @@ class ActiveHost extends Comparable { /// value of [generic]. /// This value **can change after the object got created** since getting /// host name of device is running async function. - String deviceName = generic; + late Future deviceName; PingData get pingData => _pingData; Duration? get responseTime => _pingData.response?.time; String get address => internetAddress.address; - /// This var let us know from out side if all the setup got completed. - /// Since getting host name is async function [ActiveHost] does not contain - /// all of the values when the constructor completed - late Future waitingForActiveHostSetupToComplete; - @override int get hashCode => address.hashCode; @@ -94,7 +102,11 @@ class ActiveHost extends Comparable { @override String toString() { - return 'Address: $address, HostId: $hostId, deviceName: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; + return 'Address: $address, HostId: $hostId, Time: ${responseTime?.inMilliseconds}ms'; + } + + Future toStringFull() async { + return 'Address: $address, HostId: $hostId Time: ${responseTime?.inMilliseconds}ms, DeviceName: ${await deviceName}, HostName: ${await hostName}, MdnsInfo: ${await mdnsInfo}'; } static PingData getPingData(String host) { @@ -116,7 +128,7 @@ class ActiveHost extends Comparable { /// Try to find the host name of this device, if not exist host name will /// stay null - Future setHostNameAndMdns() async { + Future setHostInfo() async { // For some reason when internetAddress.host get called before the reverse // there is weired value weirdHostName = internetAddress.host; @@ -127,14 +139,33 @@ class ActiveHost extends Comparable { try { internetAddress = await internetAddress.reverse(); - hostName = internetAddress.host; - deviceName = hostName!; + return internetAddress.host; } catch (e) { // Some devices does not have host name and the reverse search will just // throw exception. - if (mdnsInfo != null) { - deviceName = mdnsInfo!.getOnlyTheStartOfMdnsName(); - } } + return null; + } + + /// Try to find the mdns name of this device, if not exist mdns name will + /// be null + /// TODO: search mdns name for each device + Future setMdnsInfo() async { + return null; + } + + /// Set some kind of device name. + /// Will try couple of names, if all are null will just return [generic] + Future setDeviceName() async { + final String? hostNameTemp = await hostName; + + if (hostNameTemp != null) { + return hostNameTemp; + } + final MdnsInfo? mdnsTemp = await mdnsInfo; + if (mdnsTemp != null) { + return mdnsTemp.getOnlyTheStartOfMdnsName(); + } + return generic; } } From 584f8ff5dc0566876300b7261b9e2b9113797998 Mon Sep 17 00:00:00 2001 From: Guy Luz Date: Sat, 6 Aug 2022 13:02:29 +0300 Subject: [PATCH 35/36] Fix for rear cases where DNS lookup crashes. (#46) * Updated dependencies * Added comments to each dependency * Decided to update min dart version to 2.17.0 (even though pub get didn't show any errors) because it is the min version in dart_ping 7.0.0 * Reverted min dart version back to 2.12.0 as it is not mandatory * Updated min dart version to 2.17.0. * Added a function to find some of the mdns devices on the network * Added todo part for searchMdnsDevices and more srv record. * Inserting the name from the mdns into _make var in ActiveHost * More srv records. * More srv records. * Added mdns scanner to example and Changelog. Changed network_tool version to 2.1.0 * Remove Future from main function in example folder * Made searching for mdns process better for Linux if avahi-browse or mdns-scan is installed on it. * Removing print * Added small comment for future mac implementation. * Small fix to srv results as avahi command does not return all of them. * Added a lot entry's to the tcpSrvRecords list, added udpSrvRecordList. * Added the udp list to the search. Small fix for multiple devices with the same mDNS name different address. * Made mdns_scanner accessible to users of the package. * Fix for #3. Improved pub.dev score. Change method names to be more precise. * Each ActiveHost object will automatically get host name when waitingForActiveHostSetupToComplete is done, fix for #3. * Fix for #44 * Updated package version to 2.2.0, updated changelog for the new version .Updated lint to 1.10.0. * Changed ip to address * Changed app version and changelog to version 3.0.0 as we did braking changed by changed methods name. * Solved some analysis warnings * Small fix for rear cases where DNS lookup crashes. * Added _ewelink to srv list. Added a way for users to forceUseOfSavedSrvRecordList. Searching srv list on linux will now also use avahi-browse as just using mdns-scan does not retrieve the full results. * MdnsInfo now also saves SrvResourceRecord and PtrResourceRecord objects from multicast_dns package as it contains more info about the mdns device. * Made the code easier to work with as developer. --- network_tools/example/host_scan.dart | 4 +- network_tools/example/mdns_scan.dart | 2 +- .../get_srv_list_by_os/srv_list_linux.dart | 114 +++++++++--------- .../src/mdns_scanner/list_of_srv_records.dart | 1 + .../lib/src/mdns_scanner/mdns_scanner.dart | 27 +++-- network_tools/lib/src/models/active_host.dart | 69 ++++++++--- network_tools/lib/src/models/mdns_info.dart | 35 ++++-- 7 files changed, 154 insertions(+), 98 deletions(-) diff --git a/network_tools/example/host_scan.dart b/network_tools/example/host_scan.dart index 0849f88..8aa0728 100644 --- a/network_tools/example/host_scan.dart +++ b/network_tools/example/host_scan.dart @@ -28,10 +28,10 @@ void main() { ); stream.listen( - (ActiveHost host) { + (ActiveHost host) async { //Same host can be emitted multiple times //Use Set instead of List - log.fine('Found device: $host'); + log.fine('Found device: ${await host.toStringFull()}'); }, onDone: () { log.fine('Scan completed'); diff --git a/network_tools/example/mdns_scan.dart b/network_tools/example/mdns_scan.dart index 7a913c7..f13ba66 100644 --- a/network_tools/example/mdns_scan.dart +++ b/network_tools/example/mdns_scan.dart @@ -2,7 +2,7 @@ import 'package:network_tools/network_tools.dart'; Future main() async { for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { - final MdnsInfo? mdnsInfo = activeHost.mdnsInfo; + final MdnsInfo? mdnsInfo = await activeHost.mdnsInfo; print( 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}', ); diff --git a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart index e4c3a14..1781569 100644 --- a/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart +++ b/network_tools/lib/src/mdns_scanner/get_srv_list_by_os/srv_list_linux.dart @@ -7,9 +7,7 @@ class SrvListLinux { final HashSet srvList = HashSet(); try { - // Using this command is missing some results and could make the rest of - // the program not search all needed srv types. - // srvList.addAll(await runAvahiBrowseCommand()); + srvList.addAll(await runAvahiBrowseCommand()); srvList.addAll(await runMdnsScanCommand()); } catch (e) { print('Error:\n$e'); @@ -25,39 +23,42 @@ class SrvListLinux { final List srvListAvahi = []; List resultForEachLine = []; - - await shell.run( - ''' + try { + await shell.run( + ''' timeout 2s avahi-browse --all -p ''', - ).onError((ShellException error, stackTrace) { - // The command should return error as we are killing it with the command timeout - - final String? resultStderr = error.result?.stderr.toString(); - if (resultStderr != null && - resultStderr.contains('No such file or directory')) { - print( - 'You can make the mdns process better by installing `avahi-browse`', - ); - return []; - } - final String? resultStdout = error.result?.stdout.toString(); - if (resultStdout == null) { - return []; - } - resultForEachLine = resultStdout.split('\n'); - - return []; - }); + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout + + final String? resultStderr = error.result?.stderr.toString(); + if (resultStderr != null && + resultStderr.contains('No such file or directory')) { + print( + 'You can make the mdns process better by installing `avahi-browse`', + ); + return []; + } + final String? resultStdout = error.result?.stdout.toString(); + if (resultStdout == null) { + return []; + } + resultForEachLine = resultStdout.split('\n'); - for (final String resultLine in resultForEachLine) { - final List lineSeparated = resultLine.split(';'); - if (lineSeparated.length >= 6) { - final String srvString = lineSeparated[lineSeparated.length - 2]; - if (!srvString.contains(' ')) { - srvListAvahi.add(srvString); + return []; + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split(';'); + if (lineSeparated.length >= 6) { + final String srvString = lineSeparated[lineSeparated.length - 2]; + if (!srvString.contains(' ')) { + srvListAvahi.add(srvString); + } } } + } catch (e) { + print('Error getting info from avahi-browse\n$e'); } return srvListAvahi; } @@ -70,37 +71,40 @@ timeout 2s avahi-browse --all -p final List srvListMdnsScan = []; List resultForEachLine = []; - - await shell.run( - ''' + try { + await shell.run( + ''' timeout 2s mdns-scan ''', - ).onError((ShellException error, stackTrace) { - // The command should return error as we are killing it with the command timeout + ).onError((ShellException error, stackTrace) { + // The command should return error as we are killing it with the command timeout - final String? resultStderr = error.result?.stderr.toString(); + final String? resultStderr = error.result?.stderr.toString(); + + if (resultStderr == null || + (resultStderr.contains('No such file or directory'))) { + print( + 'You can make the mdns process better by installing `mdns-scan`', + ); + return []; + } + resultForEachLine = resultStderr.split('\n'); - if (resultStderr == null || - (resultStderr.contains('No such file or directory'))) { - print( - 'You can make the mdns process better by installing `mdns-scan`', - ); return []; - } - resultForEachLine = resultStderr.split('\n'); - - return []; - }); - - for (final String resultLine in resultForEachLine) { - final List lineSeparated = resultLine.split('.'); - if (lineSeparated.length >= 4) { - final String srvString = - '${lineSeparated[lineSeparated.length - 3]}.${lineSeparated[lineSeparated.length - 2]}'; - if (!srvString.contains(' ') && srvString != '.') { - srvListMdnsScan.add(srvString); + }); + + for (final String resultLine in resultForEachLine) { + final List lineSeparated = resultLine.split('.'); + if (lineSeparated.length >= 4) { + final String srvString = + '${lineSeparated[lineSeparated.length - 3]}.${lineSeparated[lineSeparated.length - 2]}'; + if (!srvString.contains(' ') && srvString != '.') { + srvListMdnsScan.add(srvString); + } } } + } catch (e) { + print('Error getting info from mdns-scan\n$e'); } return srvListMdnsScan; } diff --git a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart index 155e444..16dd215 100644 --- a/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart +++ b/network_tools/lib/src/mdns_scanner/list_of_srv_records.dart @@ -70,6 +70,7 @@ List tcpSrvRecordsList = [ '_zwave-js-server._tcp', // "domain": "zwave_js" '_axis-video._tcp', // "properties": { "macaddress": "00408c*" } "properties": { "macaddress": "accc8e*" } "properties": { "macaddress": "b8a44f*" } '_androidtvremote2._tcp', + '_ewelink._tcp', ]; List udpSrvRecordsList = [ diff --git a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart index 8bc45a2..8293f45 100644 --- a/network_tools/lib/src/mdns_scanner/mdns_scanner.dart +++ b/network_tools/lib/src/mdns_scanner/mdns_scanner.dart @@ -13,12 +13,16 @@ class MdnsScanner { /// TODO: https://github.com/flutter/flutter/issues/97210 /// TODO: In some cases we resolve this missing functionality using /// TODO: specific os tools. - static Future> searchMdnsDevices() async { + static Future> searchMdnsDevices({ + bool forceUseOfSavedSrvRecordList = false, + }) async { List srvRecordListToSearchIn; final List? srvRecordsFromOs = await SrvList.getSrvRecordList(); - if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) { + if (srvRecordsFromOs == null || + srvRecordsFromOs.isEmpty || + forceUseOfSavedSrvRecordList) { srvRecordListToSearchIn = tcpSrvRecordsList; srvRecordListToSearchIn.addAll(udpSrvRecordsList); } else { @@ -56,11 +60,8 @@ class MdnsScanner { ResourceRecordQuery.service(ptr.domainName), )) { final MdnsInfo mdnsFound = MdnsInfo( - mdnsName: srv.name, - mdnsPort: srv.port, - mdnsDomainName: ptr.domainName, - mdnsServiceType: serviceType, - mdnsSrvTarget: srv.target, + srvResourceRecord: srv, + ptrResourceRecord: ptr, ); mdnsFoundList.add(mdnsFound); } @@ -69,14 +70,18 @@ class MdnsScanner { final List listOfActiveHost = []; for (final MdnsInfo foundMdns in mdnsFoundList) { - final List internetAddressList = - await InternetAddress.lookup(foundMdns.mdnsSrvTarget); - + final List? internetAddressList; + try { + internetAddressList = + await InternetAddress.lookup(foundMdns.mdnsSrvTarget); + } catch (e) { + continue; + } // There can be multiple devices with the same name for (final InternetAddress internetAddress in internetAddressList) { final ActiveHost tempHost = ActiveHost( internetAddress: internetAddress, - mdnsInfo: foundMdns, + mdnsInfoVar: foundMdns, ); listOfActiveHost.add(tempHost); } diff --git a/network_tools/lib/src/models/active_host.dart b/network_tools/lib/src/models/active_host.dart index 2385ee3..efdfd24 100644 --- a/network_tools/lib/src/models/active_host.dart +++ b/network_tools/lib/src/models/active_host.dart @@ -10,7 +10,7 @@ class ActiveHost extends Comparable { required this.internetAddress, this.openPort = const [], PingData? pingData, - this.mdnsInfo, + MdnsInfo? mdnsInfoVar, }) { final String tempAddress = internetAddress.address; @@ -30,7 +30,20 @@ class ActiveHost extends Comparable { pingData ??= getPingData(tempAddress); _pingData = pingData; - waitingForActiveHostSetupToComplete = setHostNameAndMdns(); + + hostName = setHostInfo(); + + // For some reason when internetAddress.host get called before the reverse + // there is weired value + weirdHostName = internetAddress.host; + + if (mdnsInfoVar != null) { + mdnsInfo = Future.value(mdnsInfoVar); + } else { + mdnsInfo = setMdnsInfo(); + } + + deviceName = setDeviceName(); } factory ActiveHost.buildWithAddress({ @@ -48,19 +61,19 @@ class ActiveHost extends Comparable { internetAddress: internetAddressTemp, openPort: openPort, pingData: pingData, - mdnsInfo: mdnsInfo, + mdnsInfoVar: mdnsInfo, ); } static const generic = 'Generic Device'; InternetAddress internetAddress; late String hostId; - String? hostName; - String? weirdHostName; + late Future hostName; + late String weirdHostName; late final PingData _pingData; /// Mdns information of this device - MdnsInfo? mdnsInfo; + late Future mdnsInfo; /// List of all the open port of this device List openPort; @@ -71,16 +84,11 @@ class ActiveHost extends Comparable { /// value of [generic]. /// This value **can change after the object got created** since getting /// host name of device is running async function. - String deviceName = generic; + late Future deviceName; PingData get pingData => _pingData; Duration? get responseTime => _pingData.response?.time; String get address => internetAddress.address; - /// This var let us know from out side if all the setup got completed. - /// Since getting host name is async function [ActiveHost] does not contain - /// all of the values when the constructor completed - late Future waitingForActiveHostSetupToComplete; - @override int get hashCode => address.hashCode; @@ -94,7 +102,11 @@ class ActiveHost extends Comparable { @override String toString() { - return 'Address: $address, HostId: $hostId, deviceName: $deviceName, Time: ${responseTime?.inMilliseconds}ms'; + return 'Address: $address, HostId: $hostId, Time: ${responseTime?.inMilliseconds}ms'; + } + + Future toStringFull() async { + return 'Address: $address, HostId: $hostId Time: ${responseTime?.inMilliseconds}ms, DeviceName: ${await deviceName}, HostName: ${await hostName}, MdnsInfo: ${await mdnsInfo}'; } static PingData getPingData(String host) { @@ -116,7 +128,7 @@ class ActiveHost extends Comparable { /// Try to find the host name of this device, if not exist host name will /// stay null - Future setHostNameAndMdns() async { + Future setHostInfo() async { // For some reason when internetAddress.host get called before the reverse // there is weired value weirdHostName = internetAddress.host; @@ -127,14 +139,33 @@ class ActiveHost extends Comparable { try { internetAddress = await internetAddress.reverse(); - hostName = internetAddress.host; - deviceName = hostName!; + return internetAddress.host; } catch (e) { // Some devices does not have host name and the reverse search will just // throw exception. - if (mdnsInfo != null) { - deviceName = mdnsInfo!.getOnlyTheStartOfMdnsName(); - } } + return null; + } + + /// Try to find the mdns name of this device, if not exist mdns name will + /// be null + /// TODO: search mdns name for each device + Future setMdnsInfo() async { + return null; + } + + /// Set some kind of device name. + /// Will try couple of names, if all are null will just return [generic] + Future setDeviceName() async { + final String? hostNameTemp = await hostName; + + if (hostNameTemp != null) { + return hostNameTemp; + } + final MdnsInfo? mdnsTemp = await mdnsInfo; + if (mdnsTemp != null) { + return mdnsTemp.getOnlyTheStartOfMdnsName(); + } + return generic; } } diff --git a/network_tools/lib/src/models/mdns_info.dart b/network_tools/lib/src/models/mdns_info.dart index 340859e..5ca5946 100644 --- a/network_tools/lib/src/models/mdns_info.dart +++ b/network_tools/lib/src/models/mdns_info.dart @@ -1,22 +1,37 @@ +import 'package:multicast_dns/multicast_dns.dart'; + class MdnsInfo { MdnsInfo({ - required this.mdnsName, - required this.mdnsPort, - required this.mdnsDomainName, - required this.mdnsServiceType, - required this.mdnsSrvTarget, + required this.srvResourceRecord, + required this.ptrResourceRecord, }); /// Also can be called target - String mdnsName; - String mdnsSrvTarget; - int mdnsPort; + String get mdnsName => srvResourceRecord.name; + + String get mdnsSrvTarget => srvResourceRecord.target; + int get mdnsPort => srvResourceRecord.port; /// Also can be called bundleId - String mdnsDomainName; + String get mdnsDomainName => ptrResourceRecord.domainName; /// Srv record of the dns - String mdnsServiceType; + String get mdnsServiceType { + final List ptrNameSplit = ptrResourceRecord.name.split('.'); + String tempString = ''; + if (ptrNameSplit.isNotEmpty) { + tempString = ptrNameSplit[0]; + } + if (ptrNameSplit.length >= 2) { + tempString = '$tempString.${ptrNameSplit[1]}'; + } + + return tempString; + } + + SrvResourceRecord srvResourceRecord; + + PtrResourceRecord ptrResourceRecord; /// mDNS name without the ._tcp.local String getOnlyTheStartOfMdnsName() { From e2d41b2f92c59ffdee75528effaf9df1ee93d0ef Mon Sep 17 00:00:00 2001 From: guyluz11 Date: Sat, 6 Aug 2022 13:27:15 +0300 Subject: [PATCH 36/36] Small format changes --- network_tools/lib/src/host_scanner.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/network_tools/lib/src/host_scanner.dart b/network_tools/lib/src/host_scanner.dart index eda9bd2..6a93eaa 100644 --- a/network_tools/lib/src/host_scanner.dart +++ b/network_tools/lib/src/host_scanner.dart @@ -4,7 +4,6 @@ import 'dart:math'; import 'package:dart_ping/dart_ping.dart'; import 'package:network_tools/src/models/active_host.dart'; import 'package:network_tools/src/models/callbacks.dart'; -import 'package:network_tools/src/models/open_port.dart'; import 'package:network_tools/src/port_scanner.dart'; /// Scans for all hosts in a subnet. @@ -144,7 +143,6 @@ class HostScanner { } } - static const classASubnets = 16777216; static const classBSubnets = 65536; static const classCSubnets = 256;