Mirror: Best-effort discovery of the machine's local network using just Node.js dgram sockets
at v0.1.4 4.1 kB view raw
1#!/usr/bin/env node 2 3import type { GatewayAssignment } from './types'; 4import { 5 DEFAULT_ASSIGNMENT, 6 interfaceAssignments, 7 matchAssignment, 8} from './network'; 9import { probeDefaultRoute } from './route'; 10import { dhcpDiscover } from './dhcp'; 11import { lanNetwork } from './index'; 12 13type Mode = 'help' | 'dhcp' | 'probe' | 'fallback' | 'default'; 14 15function help() { 16 const output = [ 17 "Discover the machine's default gateway and local network IP (test utility)", 18 '', 19 'Usage', 20 ' $ lan-network', 21 ' $ lan-network --default', 22 '', 23 'Modes', 24 ' --probe Discover gateway via UDP4 socket to publicly routed address', 25 ' --dhcp Discover gateway via DHCPv4 discover broadcast', 26 ' --fallback Return highest-priority IPv4 network interface assignment', 27 ' --default Try the three above modes in order', 28 ' --help Print help output', 29 ].join('\n'); 30 console.log(output); 31} 32 33async function dhcp() { 34 const assignments = interfaceAssignments(); 35 if (!assignments.length) { 36 console.error('No available network interface assignments'); 37 process.exit(1); 38 } 39 const discoveries = await Promise.allSettled( 40 assignments.map(assignment => { 41 // For each assignment, we send a DHCPDISCOVER packet to its network mask 42 return dhcpDiscover(assignment); 43 }) 44 ); 45 let assignment: GatewayAssignment | null = null; 46 for (const discovery of discoveries) { 47 // The first discovered gateway is returned, if it matches an assignment 48 if (discovery.status === 'fulfilled' && discovery.value) { 49 const dhcpRoute = discovery.value; 50 if ((assignment = matchAssignment(assignments, dhcpRoute))) { 51 break; 52 } 53 } 54 } 55 if (assignment && assignment !== DEFAULT_ASSIGNMENT) { 56 console.log(JSON.stringify(assignment, null, 2)); 57 process.exit(0); 58 } else { 59 console.error('No DHCP router was discoverable'); 60 process.exit(1); 61 } 62} 63 64async function probe() { 65 const assignments = interfaceAssignments(); 66 if (!assignments.length) { 67 console.error('No available network interface assignments'); 68 process.exit(1); 69 } 70 try { 71 const defaultRoute = await probeDefaultRoute(); 72 const assignment = matchAssignment(assignments, defaultRoute); 73 if (assignment && assignment !== DEFAULT_ASSIGNMENT) { 74 console.log(JSON.stringify(assignment, null, 2)); 75 process.exit(0); 76 } else { 77 console.error('No default gateway or route'); 78 process.exit(1); 79 } 80 } catch (error) { 81 console.error('No default gateway or route'); 82 console.error(error); 83 process.exit(1); 84 } 85} 86 87async function fallback() { 88 const assignments = interfaceAssignments(); 89 if (!assignments.length) { 90 console.error('No available network interface assignments'); 91 process.exit(1); 92 } 93 const assignment = { ...assignments[0], gateway: null }; 94 console.log(JSON.stringify(assignment, null, 2)); 95 process.exit(0); 96} 97 98async function main() { 99 const assignment = await lanNetwork(); 100 if (assignment !== DEFAULT_ASSIGNMENT) { 101 console.log(JSON.stringify(assignment, null, 2)); 102 process.exit(0); 103 } else { 104 console.error('No default gateway, route, or DHCP router'); 105 process.exit(1); 106 } 107} 108 109function cli() { 110 let mode: Mode = 'default'; 111 parseArgs: for (let i = 1; i < process.argv.length; i++) { 112 const arg = process.argv[i].trim().toLowerCase(); 113 switch (arg) { 114 case '-h': 115 case '--help': 116 mode = 'help'; 117 break parseArgs; 118 case '-d': 119 case '--dhcp': 120 mode = 'dhcp'; 121 break; 122 case '-p': 123 case '--probe': 124 mode = 'probe'; 125 break; 126 case '-f': 127 case '--fallback': 128 mode = 'fallback'; 129 break; 130 default: 131 if (arg.startsWith('-')) throw new TypeError(`Invalid flag: ${arg}`); 132 } 133 } 134 switch (mode) { 135 case 'help': 136 return help(); 137 case 'dhcp': 138 return dhcp(); 139 case 'probe': 140 return probe(); 141 case 'fallback': 142 return fallback(); 143 case 'default': 144 return main(); 145 } 146} 147 148cli();