UNPKG

@webwriter/network

Version:

Visualization of network topologies. Can represent different kinds of networks.

644 lines (527 loc) 20.9 kB
import { EventObject } from 'cytoscape'; import { NetworkComponent } from '..'; import { Ipv4Address } from '../adressing/Ipv4Address'; import { Ipv6Address } from '../adressing/Ipv6Address'; import { MacAddress } from '../adressing/MacAddress'; import { AccessPoint, Bridge, Hub, Repeater, Router, Switch } from '../components/physicalNodes/Connector'; import { Host } from '../components/physicalNodes/Host'; import { iconToDataURI, biPcDisplayHorizontal, biPhone } from '../styles/icons'; import { ConnectionType } from '../components/physicalNodes/PhysicalNode'; import { GraphEdge } from '../components/GraphEdge'; import { EdgeController } from '../event-handlers/edge-controller'; import { SubnettingController } from '../event-handlers/subnetting-controller'; import { eventNames } from 'process'; import { GraphNodeFactory } from '../event-handlers/component-manipulation'; import { Net } from '../components/logicalNodes/Net'; import { Frame, Packet } from '../components/logicalNodes/DataNode'; export type Component = { id: string; name: string; type: string; x: number; y: number; color: string; ports: Port[]; portLinks: string[]; defaultGateway?: string[]; }; type Port = { name: string; type: string; mac: string; ip4?: string; ip6?: string; }; export type Connection = { id: string; from: string; to: string; inPort: number; outPort: number; color: string; }; export type Network = { id: string; components: string[]; gateways: string[]; name: string; netmask: string; bitmask: number; address: string; currentDefaultGateway?: string; x: number; y: number; color: string; }; export function load(this: NetworkComponent) { const components = this.components; const connections = this.connections; const networks = this.networks; components.forEach((c) => { console.log('load', c); let component: any; let portNames: Map<number, string> = new Map(); let portConnectionTypes: Map<number, ConnectionType> = new Map(); let portMacs: Map<number, MacAddress> = new Map(); let portIpv4s: Map<number, Ipv4Address> = new Map(); let portIpv6s: Map<number, Ipv6Address> = new Map(); c.ports.forEach((p, index) => { portNames.set(index + 1, p.name); portConnectionTypes.set(index + 1, p.type as ConnectionType); portMacs.set(index + 1, MacAddress.validateAddress(p.mac, this.macDatabase)); portIpv4s.set(index + 1, Ipv4Address.validateAddress(p.ip4 || '', this.ipv4Database)); portIpv6s.set(index + 1, Ipv6Address.validateAddress(p.ip6 || '', this.ipv6Database)); }); switch (c.type) { //layer 1 case 'repeater': component = new Repeater(c.color, portConnectionTypes, c.name); break; case 'hub': component = new Hub(c.color, c.ports.length, c.name); break; //layer 2 case 'switch': component = new Switch(c.color, c.ports.length, portMacs, c.name); break; case 'bridge': component = new Bridge(c.color, portConnectionTypes, portMacs, c.name); break; case 'accesspoint': component = new AccessPoint(c.color, c.ports.length, portMacs, c.name); break; //layer 3 case 'router': component = new Router( c.color, c.ports.length, portNames, portConnectionTypes, portMacs, portIpv4s, portIpv6s, c.name ); break; //host case 'computer': component = new Host( c.color, iconToDataURI(biPcDisplayHorizontal), c.ports.length, portNames, portConnectionTypes, portMacs, portIpv4s, portIpv6s, c.name ); break; case 'mobile': component = new Host( c.color, iconToDataURI(biPhone), c.ports.length, portNames, portConnectionTypes, portMacs, portIpv4s, portIpv6s, c.name ); break; } component.id = c.id; console.log('component', component); if (component.layer >= 2) { c.ports .map((p: Port) => MacAddress.validateAddress(p.mac, this.macDatabase)) .forEach((mac) => { MacAddress.addAddressToDatabase(mac, this.macDatabase, component.id); }); } if (component.layer >= 3) { c.ports .map((p: Port) => Ipv4Address.validateAddress(p.ip4 || '', this.ipv4Database)) .forEach((ip4) => { console.log('ip4', ip4); Ipv4Address.addAddressToDatabase(ip4, this.ipv4Database, component.id); }); c.ports .map((p: Port) => Ipv6Address.validateAddress(p.ip6 || '', this.ipv6Database)) .forEach((ip6) => { Ipv6Address.addAddressToDatabase(ip6, this.ipv6Database, component.id); }); } if (c.defaultGateway) { component.defaultGateway = c.defaultGateway; } this._graph.add({ group: 'nodes', data: component, position: { x: c.x, y: c.y }, classes: component.cssClass, }); }); connections.forEach((c) => { const to = this._graph.$id(c.to); const from = this._graph.$id(c.from); const edge = EdgeController.newUnconfiguredEdge(this, from.data(), to.data()); edge.data.id = c.id; console.log('edge', edge, c); const addedEdge = this._graph.add(edge); if (c.inPort && c.outPort) { // const newData = GraphEdge.addPorts(addedEdge.data(), c.inPort, c.outPort); const newData = GraphEdge.addPorts(addedEdge.data(), c.inPort, c.outPort); if (newData != null) { addedEdge.removeClass('unconfigured-edge'); addedEdge.addClass(newData.cssClass); } //set new format-display for this connection if no error appears this.subnettingController.setUpGateway( this._graph.$('#' + from.id), this._graph.$('#' + to.id), c.inPort, this.ipv4Database ); this.subnettingController.setUpGateway( this._graph.$('#' + to.id), this._graph.$('#' + from.id), c.outPort, this.ipv4Database ); } }); networks.forEach((n) => { console.log('network', n); let netid: string = n.address; let netmask: string = n.netmask; let bitmask: number = n.bitmask; let color: string = n.color; let newNet = Net.createNet(color, netid, netmask, bitmask, this.ipv4Database, this); newNet.id = n.id; let net: any; if (newNet != null) { net = this._graph.add({ group: 'nodes', data: newNet, position: { x: n.x, y: n.y }, classes: newNet.cssClass, }); } else { return; } n.components.forEach((c) => { const component = this._graph.$id(c); component.move({ parent: net.id(), }); this.subnettingController.onDragInACompound(component, net, this.ipv4Database); }); if (n.currentDefaultGateway) { const gateway = this._graph.$id(n.currentDefaultGateway); if (!gateway.data()) return; const connection = this.connections.find( (c) => c.to === n.currentDefaultGateway || c.from === n.currentDefaultGateway ); if (!connection) return; const port = connection.from === n.currentDefaultGateway ? connection.inPort : connection.outPort; net.data('currentDefaultGateway', [n.currentDefaultGateway, port]); } }); networks.forEach((n) => { const net = this._graph.$id(n.id); if (n.gateways.length > 0) { n.gateways.forEach((g) => { const gateway = this._graph.$id(g); if (!gateway.data()) return; const nets = gateway.data('nets') || []; nets.push(net.data()); gateway.data('nets', nets); //add net to gateway node gateway.data('cssClass').push('gateway-node'); gateway.toggleClass('gateway-node', true); const connection = this.connections.find( (c) => (c.to === g && n.components.includes(c.from)) || (c.from === g && n.components.includes(c.to)) ); if (!connection) { net.data('gateways').set(gateway.id(), null); // add gateway to the net, with undefined port return; } else { const port = connection.from === g ? connection.inPort : connection.outPort; if (port === 0) return; const connectedComponent = this._graph.$id(connection.to === g ? connection.from : connection.to); console.log('gateway', n, connection, port); net.data('gateways').set(gateway.id(), port); // add gateway to the net, with port this.subnettingController.setUpGateway(gateway, connectedComponent, port, this.ipv4Database); } }); } }); } export function setupListeners(this: NetworkComponent) { console.log('setupListeners'); this._graph.on('add', (event: EventObject) => { // console.log('add', event.target.data()); if (this.mode === 'simulate') return; if (event.target.data() instanceof Packet || event.target.data() instanceof Frame) return; if (event.target.isNode() && event.target.data().constructor.name === '_Net') { handleNetworkAdd.bind(this)(event); return; } if (event.target.isNode() && event.target.data().name) { handleNodeAdd.bind(this)(event); return; } if (event.target.isEdge()) { handleEdgeAdd.bind(this)(event); return; } }); this._graph.on('remove', (event: EventObject) => { if (this.mode === 'simulate') return; // console.log('remove', event); if (event.target.data() instanceof Packet || event.target.data() instanceof Frame) return; if (event.target.isNode() && event.target.data().constructor.name === '_Net') { handleNetworkRemove.bind(this)(event); return; } if (event.target.isNode() && event.target.data().name) { handleNodeRemove.bind(this)(event); } if (event.target.isEdge()) { handleEdgeRemove.bind(this)(event); } }); this._graph.on('data', (event: EventObject) => { if (this.mode === 'simulate') return; // console.log('data', event.target.data()); if (event.target.data() instanceof Packet || event.target.data() instanceof Frame) return; if (event.target.isNode() && event.target.data().constructor.name === '_Net') { handleNetworkDataChange.bind(this)(event); return; } if (event.target.isNode() && event.target.data().name) { handleNodeDataChange.bind(this)(event); return; } if (event.target.isEdge()) { handleEdgeDataChange.bind(this)(event); return; } }); this._graph.on('move', (event: EventObject) => { if (this.mode === 'simulate') return; if (event.target.data() instanceof Packet || event.target.data() instanceof Frame) return; const data = event.target.data(); this.networks.forEach((n) => { if (n.components.includes(data.id)) { n.components.splice(n.components.indexOf(data.id), 1); } }); if (data.parent) { const netId = data.parent; const network = this.networks.find((n) => n.id === netId); if (network) { network.components.push(data.id); } } this.networks = [...this.networks]; console.log('move', event.target.data()); }); this._graph.on('dragfree', (event: EventObject) => { if (this.mode === 'simulate') return; const target = event.target; const data = target.data(); const position = target.position(); if (target.isNode() && data.constructor.name === '_Net') { const network = this.networks.find((n) => n.id === data.id); if (!network) return; network.x = position.x; network.y = position.y; this.networks[this.networks.indexOf(network)] = network; this.networks = [...this.networks]; return; } if (target.isNode() && data.name) { const component = this.components.find((c) => c.id === data.id); if (!component) return; component.x = position.x; component.y = position.y; this.components[this.components.indexOf(component)] = component; this.components = [...this.components]; return; } }); } function handleNodeAdd(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); const position = target.position(); console.log('Add Node', target, data, position); let type = data.constructor.name.toLowerCase(); if (type[0] === '_') type = type.slice(1); console.log('type', type); if (type === 'host') { type = data.backgroundPath === iconToDataURI(biPcDisplayHorizontal) ? 'computer' : 'mobile'; } const portData: Map<string, Map<string, any>> = data.portData; const portLinksData: Map<string, string> = data.portLinkMapping; const ports: Port[] = []; const portLinks: string[] = []; portData.forEach((port, _) => { const p: Port = { name: port.get('Name') || 'port', type: port.get('Connection Type') || 'ethernet', mac: (port.get('MAC') as MacAddress)?.address || '00:00:00:00:00:00', ip4: (port.get('IPv4') as Ipv4Address)?.address, ip6: (port.get('IPv6') as Ipv6Address)?.address, }; ports.push(p); }); portLinksData.forEach((link, _) => { portLinks.push(link || ''); }); const c: Component = { id: data.id, name: data.name, color: data.color, type: type, x: position.x, y: position.y, ports: ports, portLinks: portLinks, }; this.components.push(c); this.components = [...this.components]; } function handleEdgeAdd(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); if (!data.from || !data.to) return; this.connections.push({ id: data.id, from: data.source, to: data.target, inPort: 0, outPort: 0, color: data.color, }); this.connections = [...this.connections]; console.log('Add Edge', target, data); } function handleNetworkAdd(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); const position = target.position(); this.networks.push({ id: data.id, components: [], gateways: [], name: data.name, netmask: data.netmask, bitmask: data.bitmask, address: data.networkAddress?.address, color: data.color, x: position.x, y: position.y, }); this.networks = [...this.networks]; console.log('Add Network', target, data, position); } function handleNodeRemove(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); const c = this.components.find((c) => c.id === data.id); if (!c) return; this.components.splice(this.components.indexOf(c), 1); this.components = [...this.components]; this.networks.forEach((n) => { if (n.components.includes(data.id)) { n.components.splice(n.components.indexOf(data.id), 1); } }); this.networks = [...this.networks]; } function handleEdgeRemove(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); const c = this.connections.find((c) => c.from === data.source && c.to === data.target); if (!c) return; this.connections.splice(this.connections.indexOf(c), 1); this.connections = [...this.connections]; } function handleNetworkRemove(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); const c = this.networks.find((c) => c.id === data.id); if (!c) return; this.networks.splice(this.networks.indexOf(c), 1); this.networks = [...this.networks]; this.networks.forEach((n) => { if (n.components.includes(data.id)) { n.components.splice(n.components.indexOf(data.id), 1); } }); this.networks = [...this.networks]; } function handleNodeDataChange(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); const nodeIndex = this.components.findIndex((c) => c.id === data.id); if (nodeIndex === -1) return; this.components[nodeIndex].name = data.name; this.components[nodeIndex].color = data.color; const portData: Map<string, Map<string, any>> = data.portData; const portLinksData: Map<string, string> = data.portLinkMapping; const ports: Port[] = []; const portLinks: string[] = []; portData.forEach((port, _) => { const p: Port = { name: port.get('Name') || 'port', type: port.get('Connection Type') || 'ethernet', mac: (port.get('MAC') as MacAddress).address || '00:00:00:00:00:00', ip4: (port.get('IPv4') as Ipv4Address)?.address, ip6: (port.get('IPv6') as Ipv6Address)?.address, }; ports.push(p); }); portLinksData.forEach((link, _) => { portLinks.push(link || ''); }); this.components[nodeIndex].ports = ports; this.components[nodeIndex].portLinks = portLinks; this.components[nodeIndex].defaultGateway = data.defaultGateway; this.components = [...this.components]; console.log('Node Data Change', target, data); } function handleEdgeDataChange(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); const edgeIndex = this.connections.findIndex((c) => c.id === data.id); if (edgeIndex === -1) return; this.connections[edgeIndex].inPort = data.inPort; this.connections[edgeIndex].outPort = data.outPort; this.connections[edgeIndex].color = data.color; this.connections = [...this.connections]; console.log('Edge Data Change', target, data); } function handleNetworkDataChange(this: NetworkComponent, event: EventObject) { const target = event.target; const data = target.data(); console.log('Network Data Change', target, data); const networkIndex = this.networks.findIndex((c) => c.id === data.id); if (networkIndex === -1) return; this.networks[networkIndex].name = data.name; this.networks[networkIndex].color = data.color; this.networks[networkIndex].address = data.networkAddress?.address; this.networks[networkIndex].netmask = data.netmask; this.networks[networkIndex].bitmask = data.bitmask; let gateways: string[] = []; data.gateways.forEach((v: any, k: any) => { gateways.push(k); }); this.networks[networkIndex].gateways = gateways; this.networks[networkIndex].currentDefaultGateway = data.currentDefaultGateway ? data.currentDefaultGateway[0] : null; this.networks = [...this.networks]; }