Browse Source

* Refactoring and documentation

master
Harish.K 6 years ago
parent
commit
e92fb5713b
  1. 8
      README.md
  2. 113
      index.js
  3. 3
      static/app.js
  4. 10
      static/index.html

8
README.md

@ -1,2 +1,10 @@
# ipv6-global-ip-demo
A simple web application to test whether your ISP provides you 2^64 ipv6 global IP or not
## Usage
* clone the repo
* run `npm install` or `yarn install`
* export environment variable `ETH_DEV` which points to ether net interface with public IPv6 address.
* Run server . Eg: `env ETH_DEV=em1 npm run server`, where em1 is the ether net interface with global IPv6 IP.
* Open [http://127.0.0.1:3553/] in the browser to access the application

113
index.js

@ -6,16 +6,17 @@
const Koa = require('koa');
const Router = require('koa-joi-router');
const util = require('util');
const {RateLimiterMemory} = require('rate-limiter-flexible');
const app = new Koa();
const router = new Router();
const Joi = Router.Joi;
const _exec = util.promisify( require('child_process').exec );
const ethDev = process.env.ETH_DEV
const {RateLimiterMemory} = require('rate-limiter-flexible');
const rateLimitOpts = {
points: 1, // 1 request for ctx.ip
duration: 1, // per 1 second
points: 5, // 1 request for ctx.ip
duration: 5, // per 1 second
};
const rateLimiter = new RateLimiterMemory( rateLimitOpts );
const MyJoi = {
@ -23,7 +24,8 @@ const MyJoi = {
return Joi.string().ip({
version: [
'ipv6'
]
],
cidr: 'forbidden'
})
},
ipv6Array: function(){
@ -41,6 +43,64 @@ async function exec( cmd ){
}
function setRateLimitHeader( ctx, rateLimitInfo ){
ctx.response.set({
"X-RateLimit-Limit": rateLimitOpts.points,
"X-RateLimit-Remaining": rateLimitInfo.remainingPoints,
"X-RateLimit-Reset": new Date(Date.now() + rateLimitInfo.msBeforeNext).toUTCString()
});
}
async function rateLimiterMiddleWare( ctx, next ){
try {
let rlInfo = await rateLimiter.consume(ctx.ip)
setRateLimitHeader( ctx, rlInfo );
await next().catch();
} catch ( rlInfo ) {
ctx.status = 429
ctx.response.set({
"Retry-After": rlInfo.msBeforeNext / 1000,
});
setRateLimitHeader( ctx, rlInfo );
ctx.body = { error: 'Too Many Requests. Please wait for some time' };
}
}
async function getIpList( ctx ){
const ips = await exec(`ip -6 a show dev ${ethDev} scope global | grep inet6 | awk '{print $2}'`)
ctx.body = { ips : ips.split('\n').filter(v => v.length ).map( v => v.slice(0, -3)) };
}
async function addIp( ctx ){
const ip = ctx.request.body.ip;
try {
await exec(`sudo ip -6 a add ${ip}/64 dev ${ethDev}`);
} catch (e) {
ctx.status = 409;
ctx.body = { error: 'Failed to assign ip'};
return;
}
// Remove ip after some time
setTimeout(function(){
exec(`sudo ip -6 a del dev ${ethDev} ${ip}/64`);
},60*1000 );
const ips = await exec(`ip -6 a show dev ${ethDev}| grep inet6.*global | awk '{print $2}'`);
ctx.body = { ips : ips.split('\n').filter(v => v.length ).map( v => v.slice(0, -3)) };
}
async function logger( ctx, next ){
const startTime = Date.now();
await next();
const requestTime = Date.now() - startTime;
console.log(`${ctx.method} ${ctx.response.status} ${ctx.ip} "${ctx.request.headers['user-agent']}" - ${requestTime}`);
}
router.route({
method: 'get',
@ -54,10 +114,7 @@ router.route({
}
}
},
handler: async (ctx) => {
const ips = await exec(`ip -6 a show dev ${ethDev} scope global | grep inet6 | awk '{print $2}'`)
ctx.body = { ips : ips.split('\n').filter(v => v.length ).map( v => v.slice(0, -3)) };
}
handler: getIpList
});
@ -77,43 +134,13 @@ router.route({
}
}
},
handler: async (ctx) => {
const ip = ctx.request.body.ip;
try {
await exec(`sudo ip -6 a add ${ip}/64 dev ${ethDev}`);
} catch (e) {
ctx.status = 409;
ctx.body = { error: 'Failed to assign ip'};
return;
}
// Remove ip after some time
setTimeout(function(){
exec(`sudo ip -6 a del dev ${ethDev} ${ip}/64`);
},60*1000 );
const ips = await exec(`ip -6 a show dev ${ethDev}| grep inet6.*global | awk '{print $2}'`);
ctx.body = { ips : ips.split('\n').filter(v => v.length ).map( v => v.slice(0, -3)) };
}
handler: addIp
});
app.use(require('koa-static')('./static'));
app.use( async ( ctx, next ) => {
try {
await rateLimiter.consume(ctx.ip)
await next();
} catch (rejRes) {
ctx.status = 429
ctx.response.set({
"Retry-After": rejRes.msBeforeNext / 1000,
"X-RateLimit-Limit": rateLimitOpts.points,
"X-RateLimit-Remaining": rejRes.remainingPoints,
"X-RateLimit-Reset": new Date(Date.now() + rejRes.msBeforeNext)
});
ctx.body = { error: 'Too Many Requests. Please wait for some time' };
}
});
app.use(router.middleware());
app.use( logger );
app.use( require('koa-static')('./static') );
app.use( rateLimiterMiddleWare );
app.use( router.middleware() );
app.listen( 3553 );

3
static/app.js

@ -46,8 +46,7 @@ var app = new Vue({
this.ips = res.ips;
})
.catch( res =>{
console.log( res );
// alert( res.error )
alert( res.error )
});
}
}

10
static/index.html

@ -5,11 +5,19 @@
<title>IPV6 global ip test</title>
</head>
<body>
<h2>What is this?</h2>
<pre>
* List of public IPv6 IP assigned to the currently running server is shown below.
* We can click on each link and verify whether that IP is globally accessible or not by visiting the link
* Optionally, we can add new public IPv6 address using the form displayed in the bottom.
* Newly added IP will only persist for one minute. It will be removed after that.
* Please note that, we are only allowed change last 64 bits of existing global ip. Otherwise it won't work
</pre>
<div id="app">
<h3>List of global IPv6 address assigned to this server</h3>
<ul id="cont-ip-list">
<li v-for="ip in ips">
<a :href="'http://[' + ip + ']:3553'">
<a target="_blank" :href="'http://[' + ip + ']:3553'">
{{ ip }}
</a>
</li>

Loading…
Cancel
Save