├── .gitignore ├── .travis.yml ├── DOCUMENTATION.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── build ├── lan.js └── lan.min.js ├── demo.html ├── examples └── dashboard.html ├── package.json ├── spec ├── host_probe_spec.js ├── host_scan_spec.js └── utils_spec.js └── src ├── db.js ├── device_scan.js ├── host_scan.js ├── ip_discovery.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /DOCUMENTATION.md: -------------------------------------------------------------------------------- 1 | lan-js 2 | === 3 | 4 | `lan-js` is a Javascript library for probing (cross-domain) hosts on your LAN from a browser. `lan-js` operates in two stages: 5 | 6 | 1. `HostScan`: An initial scan of the desired address range is performed with `WebSockets` (and `Image` fallbacks for older browsers). Alive hosts are identified via timing differences when a connection is attempted. 7 | 8 | 2. `DeviceScan`: A secondary scan for known device fingerprints accessible via HTTP. A small example database is provided in `src/db.js`, 9 | 10 | #### lan.HostScan 11 | 12 | The `lan.HostScan` class handles running a single scan over an array of hosts. 13 | 14 | var scan = new lan.HostScan(['192.168.0.1', '192.168.0.2']); 15 | scan.start({ 16 | stream: function(address, state, deltat) { 17 | // called while the scan is running anytime we discover a new alive host 18 | console.log("Host at "+address+" is "+state); 19 | }, 20 | complete: function(results) { 21 | // called at the end of the scan 22 | console.log("Complete!"); 23 | } 24 | }); 25 | 26 | #### lan.DeviceScan 27 | 28 | The `lan.DeviceScan` class handles running a scan to fingerprint specific devices on your network. It first performs a `lan.TcpScan` to find alive hosts, and then tries to identify them by sending a catalog of requests for known images, stylesheets, and Javascript files that can be read by a cross-domain website. 29 | 30 | lan.DeviceScan.start(['192.168.0.1', '192.168.0.2', '192.168.1.1', '10.0.0.1'], { 31 | found: function(address, fingerprint) { 32 | console.log("["+address+"] Found device: "+fingerprint); 33 | }, 34 | complete: function(results) { 35 | console.log("Scan complete.") 36 | }, 37 | hostup: function(address) { 38 | console.log("Host up: "+address); 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | // The order of these files is very important! 3 | // They will be concatenated in order, so make sure dependencies match position. 4 | var SRC_FILES = [ 5 | 'src/utils.js', 6 | 'src/host_scan.js', 7 | 'src/device_scan.js', 8 | 'src/ip_discovery.js', 9 | 'src/db.js' 10 | ]; 11 | 12 | grunt.loadNpmTasks('grunt-contrib-compress'); 13 | 14 | // Project configuration. 15 | grunt.initConfig({ 16 | pkg: grunt.file.readJSON('package.json'), 17 | jshint: { 18 | all: ['Gruntfile.js', 'src/*.js', 'spec/*.js'] 19 | }, 20 | concat: { 21 | dist: { 22 | src: SRC_FILES, 23 | dest: 'build/lan.js', 24 | } 25 | }, 26 | uglify: { 27 | options: { 28 | compress: {}, 29 | mangle: {}, 30 | banner: '/*! <%= pkg.name %>@<%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' 31 | }, 32 | build: { 33 | src: 'build/lan.js', 34 | dest: 'build/lan.min.js' 35 | } 36 | }, 37 | jasmine: { 38 | pivotal: { 39 | src: SRC_FILES, 40 | options: { 41 | specs: 'spec/**.js' 42 | } 43 | } 44 | }, 45 | watch: { 46 | scripts: { 47 | files: ['spec/*.js', 'src/*.js'], 48 | tasks: ['jshint', 'jasmine'], 49 | options: { 50 | spawn: false, 51 | } 52 | } 53 | } 54 | }); 55 | 56 | grunt.loadNpmTasks('grunt-contrib-jasmine'); 57 | grunt.loadNpmTasks('grunt-contrib-jshint'); 58 | grunt.loadNpmTasks('grunt-contrib-concat'); 59 | grunt.loadNpmTasks('grunt-contrib-uglify'); 60 | grunt.loadNpmTasks('grunt-contrib-watch'); 61 | grunt.registerTask('default', ['jshint', 'jasmine', 'concat', 'uglify']); 62 | }; 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Source: http://www.metasploit.com/ 3 | 4 | Files: * 5 | Copyright: 2006-2014, Rapid7, Inc. 6 | License: BSD-3-clause 7 | 8 | # lan-js is provided under the 3-clause BSD license provided 9 | # at the end of this file. 10 | # 11 | # The copyright on this package is held by Rapid7, Inc. 12 | # 13 | # This license does not apply to third-party components detailed below. 14 | # 15 | # Last updated: 2014-Sep-19 16 | 17 | License: BSD-3-clause 18 | Redistribution and use in source and binary forms, with or without modification, 19 | are permitted provided that the following conditions are met: 20 | . 21 | * Redistributions of source code must retain the above copyright notice, 22 | this list of conditions and the following disclaimer. 23 | . 24 | * Redistributions in binary form must reproduce the above copyright notice, 25 | this list of conditions and the following disclaimer in the documentation 26 | and/or other materials provided with the distribution. 27 | . 28 | * Neither the name of Rapid7, Inc. nor the names of its contributors 29 | may be used to endorse or promote products derived from this software 30 | without specific prior written permission. 31 | . 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 33 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 34 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 36 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 37 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 38 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 39 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lan-js [](https://travis-ci.org/jvennix-r7/lan-js) 2 | === 3 | 4 | Probe LAN devices from a web browser. 5 | 6 | #### Documentation 7 | 8 | See [DOCUMENTATION.md](./DOCUMENTATION.md). 9 | 10 | #### Sample code: 11 | 12 | Scan the following devices on your network, and print any device matches 13 | 14 | lan.DeviceScan.start(['192.168.0.1', '192.168.0.2', '192.168.1.1', '10.0.0.1'], { 15 | found: function(address, fingerprint) { 16 | console.log("["+address+"] Found device: "+fingerprint); 17 | }, 18 | complete: function(results) { 19 | console.log("Scan complete.") 20 | }, 21 | hostup: function(address) { 22 | console.log("Host up: "+address); 23 | } 24 | }); 25 | 26 | #### Fingerprints 27 | 28 | The `DeviceScan` class is in charge of scanning for responsive hosts and then looking for fingerprintable images, scripts, or stylesheets served by an HTTP service on that host. 29 | 30 | A fingerprint is a set of criteria for matching a device. There are three types of fingerprints: images, scripts, and stylesheets. 31 | 32 | // image fingerprint 33 | { 34 | type: 'image', 35 | url: '/epsonlogo.gif', 36 | width: 79, 37 | height: 28 38 | } 39 | 40 | // style 41 | { 42 | type: 'css', 43 | url: '/style.css', 44 | html: '
', 45 | id: 'x', 46 | styles: { color: 'red' } 47 | } 48 | 49 | // script 50 | { 51 | type: 'js', 52 | url: '/script.js', 53 | expression: 'LINKSYS_VERSION === 1' 54 | } 55 | 56 | #### Development environment: 57 | 58 | 1. First install [node](http://nodejs.org/). 59 | 2. Install the grunt plugin and run `npm install` in the project root: 60 | 61 | $ sudo npm i -g grunt-cli 62 | $ cd ~/Projects/lan.js/ 63 | $ npm install 64 | 65 | #### Compiling 66 | 67 | To compile, from the project root run: 68 | 69 | grunt 70 | 71 | To have grunt "watch" your filesystem and recompile on change, do: 72 | 73 | grunt compile:watch 74 | 75 | #### Running specs: 76 | 77 | This project includes a number of specs. To run them, simply: 78 | 79 | grunt spec 80 | 81 | To have grunt "watch" your filesystem and run specs on change, do: 82 | 83 | grunt spec:watch 84 | 85 | #### License 86 | 87 | `lan-js` is released under the [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause). 88 | 89 | #### Copyright 90 | 91 | 2006-2015, Rapid7, Inc. 92 | -------------------------------------------------------------------------------- /build/lan.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Small collection of shims and global functions. 3 | */ 4 | (function() { 5 | 6 | // really hard to live without this 7 | var merge = function(_this, hash) { 8 | for (var k in hash) { _this[k] = hash[k]; } 9 | return _this; 10 | }; 11 | 12 | // normalize #forEach() implementation, for my sanity. 13 | var each = function(_this, cb) { 14 | for (var i = 0; i < _this.length; i++) cb(_this[i], i); 15 | }; 16 | 17 | // list some useful constants 18 | var constants = { 19 | // set #style of any DOMElement to this to hide 20 | HIDDEN_STYLE: 'position:fixed;top:-500px;left:-500px;visibility:hidden;' 21 | }; 22 | 23 | /* 24 | * Creates and returns an