npeerlink
Version:
p2p tap pair to interlink vm and container networks
201 lines (146 loc) • 5.65 kB
JavaScript
// peerlink class
// Copyright (c) 2015 Tom Zhou<iwebpp@gmail.com>
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) {
};