UNPKG

npeerlink

Version:

p2p tap pair to interlink vm and container networks

201 lines (146 loc) 5.65 kB
// peerlink class // Copyright (c) 2015 Tom Zhou<iwebpp@gmail.com> 'use strict' var TCP = require('net'); ///var UDT = require('udt'); var TLS = require('tls'); ///var UDTS = require('udts'); var http = require('http'); var https = require('https'); ///var httpp = require('httpp'); ///var httpps = require('httpps'); var tuntap = require('tuntap'); var express = require('express'); var util = require('util'); var URL = require('url'); var eventEmitter = require('events').EventEmitter; var debug = require('debug')('peerlink'); var PeerLink = module.exports = function(options) { var self = this; if (! (this instanceof PeerLink)) return new PeerLink(options); // super constructor eventEmitter.call(this, options); // properties this.options = options || {}; // peerlink pairs this.linkpairs = []; // [{mdev, pdev}, {mdev1, pdev1},...] this.localdevs = {}; // {'mdev': pdev} this.remotedevs = {}; // {'pdev': mdev} this.localbridges = {}; // {'mdev': mbridge} this.remotebridges = {}; // {'pdev': pbridge} // peerlink remote server url this.peerserver = (options && options.peerserver) || 'http://localhost:8686'; // peerlink local server daemon }; util.inherits(PeerLink, eventEmitter); // export http CONNECT handler PeerLink.exportHttpTunnel = function (req, socket, head){ var devs = req.url.split(':'); var pdevname = devs[0]; // peer tap device name var pbrgname = devs[1]; // peer bridge devie name, TBD... debug('tap tunnel proxy, connect to peer tap: ' + pdevname); // 1. // create peer tap device var ptap = new tuntap.Tap('/dev/net/tun'); ptap.setname(pdevname); // MUST resume it ptap.resume(); // 2. // pipe peer tap device socket.write('HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node-Proxy\r\n' + '\r\n'); ptap.pipe(socket).pipe(ptap); ptap.on('error', function(e){ console.error("tap tunnel proxy, ignore ptap error: " + e); ///self.emit('error', "tap tunnel proxy, ptap error: " + e); ///socket.end(); }); socket.on('error', function(e){ console.error("tap tunnel proxy, ignore socket error: " + e); ///self.emit('error', "tap tunnel proxy, socket error: " + e); ///ptap.end(); }); // 3. // link peer tap to bridge // TBD... }; /// REST API router PeerLink.exportRestApi = function() { var router = express.router(); return router; }; // Methods /// @description - setup peerlink tunnel with mdev and pdev to peerlink server /// @param options - tap device names /// @param fn - callback PeerLink.prototype.interLink = function(options, fn) { var self = this; // check params if (!(options && options.mdevname && options.pdevname)) { console.error('invalid params '+options); ///self.emit('error', 'interLink invalid params '+options); return fn('invalid params'); } var mdevname = options.mdevname; var pdevname = options.pdevname; // 1. // create local tap device var mtap = new tuntap.Tap('/dev/net/tun'); mtap.setname(mdevname); // MUST resume it mtap.resume(); // 2. // create http CONNECT tunnel to remote server var urlobj = URL.parse(self.peerserver, true, true); var protocol = urlobj.protocol; var dstip = urlobj.hostname; var dstport = urlobj.port || ((protocol === 'https') ? 443 : 80); // 2.1 // setup tunnel to target by make CONNECT request var roptions = { port: dstport, hostname: dstip, method: 'CONNECT', path: pdevname, // peer tap device name to setup agent: false, }; var rreq = (protocol === 'https') ? https.request(roptions) : http.request(roptions); rreq.end(); debug('tap tunnel proxy, connect to %s:%d', dstip, dstport); rreq.on('connect', function(rres, rsocket, rhead) { // 3. // pipe local tap device to http tunnel to remote server debug('tap tunnel proxy, got connected'); mtap.pipe(rsocket).pipe(mtap); rsocket.on('error', function(e) { console.error("tap tunnel proxy, ignore socket error: " + e); ///self.emit('error', "tap tunnel proxy, socket error: " + e); ///mtap.end(); }); mtap.on('error', function(e) { console.error("tap tunnel proxy, ignore mtap error: " + e); ///self.emit('error', "tap tunnel proxy, mtap error: " + e); ///rsocket.end(); }); }); rreq.on('error', function(e) { console.error("tap tunnel proxy, CONNECT request error: " + e); ///self.emit('error', "tap tunnel proxy, CONNECT request error: " + e); mtap.end(); }); // pass tap device back fn(null, {name: mdevname, dev: mtap}); }; /// link local device to bridge PeerLink.prototype.localLinkToBridge = function(options, fn) { }; /// link remote device to bridge PeerLink.prototype.remoteLinkToBridge = function(options, fn) { }; /// create local bridge PeerLink.prototype.createLocalBridge = function(options) { }; /// create remote bridge PeerLink.prototype.createRemoteBridge = function(options) { };