├── CNAME ├── README.md ├── index.html └── js ├── detectAddress.js ├── lanScan.js └── script.js /CNAME: -------------------------------------------------------------------------------- 1 | lan.neerajaggarwal.com -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lan-scan 2 | 3 | A website that will detect a local IP address and run a local network scan. It returns a downloadable JSON with the results. 4 | 5 | ## Usage 6 | 7 | Visit [https://lan.neerajaggarwal.com](https://lan.neerajaggarwal.com) in your browser to see a working demonstration. 8 | 9 | Opening the website will automatically run the scan. A JSON should be downloadable within 10 seconds, which will contain all the successful responses. 10 | 11 | **JSON Format** 12 | 13 | ```json 14 | [ 15 | { 16 | "address": "IP Address", 17 | "response": "success", 18 | "data": "data" 19 | } 20 | ] 21 | ``` 22 | 23 | ### Browser Support 24 | 25 | | [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | 26 | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 27 | | No | Yes | Yes | No | Yes | 28 | 29 | ### Anonymized IP 30 | 31 | An experimental feature of Chromium is to automatically anonymize local IPs exposed by WebRTC. To be able to retrieve the local IP address, you must disable this feature. 32 | 33 | Go to [`chrome://flags/#enable-webrtc-hide-local-ips-with-mdns`](chrome://flags/#enable-webrtc-hide-local-ips-with-mdns) in your Chrome browser to disable. 34 | 35 | Screen Shot 2019-10-07 at 5 38 47 PM 36 | 37 | ## How It Works 38 | 39 | ### Detecting Local IP 40 | 41 | The auto detection for the local IP is based on [webrtc-ip](https://github.com/n3a9/webrtc-ip). For more information about how it works, refer to the README. 42 | 43 | ### Local Network Scanning 44 | 45 | Once the beginning address and ports are set, the scanner will iterate through all IP address variations by changing the last octet, ranging from 0 to 255. 46 | 47 | For each address, an asynchronous AJAX will be made to each port . The callback will then determine whether the request timed out, or if there was an error, and append it to the CSV. Unfortunately, it is not possible to determine the different errors from the request (such as `401` or `404`) due to security enforcements from the browser. 48 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lan-scan 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 42 | 43 | 44 | 45 |

lan-scan

46 |

A website that will detect your local IP address and run a local network scan. Check out the code at Github.

48 | 49 |

Results

50 |

Currently running!

51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /js/detectAddress.js: -------------------------------------------------------------------------------- 1 | findLocalAddress = () => { 2 | let RTCPeerConnection = 3 | window.RTCPeerConnection || 4 | window.mozRTCPeerConnection || 5 | window.webkitRTCPeerConnection; 6 | 7 | if (!RTCPeerConnection) { 8 | RTCPeerConnection = 9 | iframe.contentWindow.RTCPeerConnection || 10 | iframe.contentWindow.mozRTCPeerConnection || 11 | iframe.contentWindow.webkitRTCPeerConnection; 12 | } 13 | 14 | const servers = { 15 | iceServers: [{ urls: iceServer }], 16 | }; 17 | 18 | const rtc = new RTCPeerConnection(servers); 19 | rtc.createDataChannel("rtc"); 20 | 21 | parseCandidate = (candidate) => { 22 | detectLocal(candidate); 23 | const match = ipRegex.public.exec(candidate); 24 | if (match && match[0].match(ipRegex.local)) address = match[0]; 25 | }; 26 | 27 | detectLocal = (candidate) => { 28 | const tempAddress = candidate.split(" ")[4]; 29 | const type = candidate.split(" ")[7]; 30 | if (type === "host" && isAnonymized(tempAddress)) address = tempAddress; 31 | }; 32 | 33 | rtc.onicecandidate = (ice) => { 34 | if (ice.candidate) parseCandidate(ice.candidate.candidate); 35 | }; 36 | 37 | rtc.createOffer( 38 | (result) => { 39 | rtc.setLocalDescription(result); 40 | const lines = rtc.localDescription.sdp.split("\n"); 41 | lines.forEach((line) => { 42 | if (~line.indexOf("a=candidate") || ~line.indexOf("c=")) 43 | parseCandidate(line); 44 | }); 45 | }, 46 | () => {} 47 | ); 48 | }; 49 | 50 | isAnonymized = (address) => { 51 | return address && address.includes(".local"); 52 | }; 53 | -------------------------------------------------------------------------------- /js/lanScan.js: -------------------------------------------------------------------------------- 1 | const ports = [80, 8000, 8080, 5000, 8008]; 2 | let scanResults = []; 3 | let json = ""; 4 | 5 | runScan = () => { 6 | findLocalAddress(); 7 | setTimeout(function () { 8 | scanLocal(address, ports); 9 | }, 1000); 10 | }; 11 | 12 | scanLocal = async (address, ports) => { 13 | if (isAnonymized(address)) { 14 | document.body.removeChild(document.getElementById("loading")); 15 | document.body.appendChild(anonMessage); 16 | return; 17 | } 18 | 19 | const index = address.lastIndexOf("."); 20 | if (index == -1) { 21 | document.body.removeChild(document.getElementById("loading")); 22 | document.body.appendChild(badAddressMessage); 23 | return; 24 | } 25 | 26 | beginningAddress = address.slice(0, index + 1); 27 | for (let port of ports) scanPort(beginningAddress, ports); 28 | 29 | setTimeout(function () { 30 | const encodedUri = 31 | "data:application/json;charset=utf-8," + 32 | encodeURIComponent(JSON.stringify(scanResults)); 33 | 34 | downloadElement.href = encodedUri; 35 | document.body.removeChild(document.getElementById("loading")); 36 | document.body.appendChild(downloadElement); 37 | }, 10000); 38 | }; 39 | 40 | scanPort = (beginningAddress, port) => { 41 | for (let octet = 0; octet <= 255; octet++) { 42 | const newAddress = 43 | "http://" + beginningAddress + octet.toString() + ":" + port; 44 | $.ajax({ 45 | crossDomain: true, 46 | url: newAddress, 47 | async: true, 48 | success: function (data) { 49 | scanResults.push({ 50 | address: newAddress, 51 | response: "response", 52 | data: data, 53 | }); 54 | }, 55 | error: function (jqXHR, textStatus, errorThrown) {}, 56 | timeout: 1.5 * 1000, 57 | }); 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /js/script.js: -------------------------------------------------------------------------------- 1 | const iceServer = "stun:stun.l.google.com:19302?transport=udp"; 2 | 3 | const ipRegex = { 4 | local: /^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/, 5 | public: /([0-9]{1,3}(\.[0-9]{1,3}){3}|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))($|\s)/, 6 | }; 7 | 8 | let anonMessage = document.createElement("p"); 9 | anonMessage.innerHTML = 10 | "Note: Your IP address is anonymized! To fix, go to chrome://flags/#enable-webrtc-hide-local-ips-with-mdns in your browser and disable."; 11 | 12 | let badAddressMessage = document.createElement("p"); 13 | badAddressMessage.textContent = "Unable to determine IP address!"; 14 | 15 | const today = new Date().toISOString().substring(0, 10); 16 | let downloadElement = document.createElement("a"); 17 | downloadElement.textContent = "Download Scan Results"; 18 | downloadElement.download = `scan-results-${today}.json`; 19 | 20 | runScan(); 21 | --------------------------------------------------------------------------------