mirror of
https://github.com/harish2704/ipv6-global-ip-demo.git
synced 2026-09-10 07:11:08 +00:00
* Refactoring and documentation
This commit is contained in:
@@ -1,2 +1,10 @@
|
|||||||
# ipv6-global-ip-demo
|
# ipv6-global-ip-demo
|
||||||
A simple web application to test whether your ISP provides you 2^64 ipv6 global IP or not
|
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
|
||||||
|
|||||||
@@ -6,16 +6,17 @@
|
|||||||
const Koa = require('koa');
|
const Koa = require('koa');
|
||||||
const Router = require('koa-joi-router');
|
const Router = require('koa-joi-router');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
const {RateLimiterMemory} = require('rate-limiter-flexible');
|
||||||
|
|
||||||
|
|
||||||
const app = new Koa();
|
const app = new Koa();
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
const Joi = Router.Joi;
|
const Joi = Router.Joi;
|
||||||
const _exec = util.promisify( require('child_process').exec );
|
const _exec = util.promisify( require('child_process').exec );
|
||||||
const ethDev = process.env.ETH_DEV
|
const ethDev = process.env.ETH_DEV
|
||||||
const {RateLimiterMemory} = require('rate-limiter-flexible');
|
|
||||||
const rateLimitOpts = {
|
const rateLimitOpts = {
|
||||||
points: 1, // 1 request for ctx.ip
|
points: 5, // 1 request for ctx.ip
|
||||||
duration: 1, // per 1 second
|
duration: 5, // per 1 second
|
||||||
};
|
};
|
||||||
const rateLimiter = new RateLimiterMemory( rateLimitOpts );
|
const rateLimiter = new RateLimiterMemory( rateLimitOpts );
|
||||||
const MyJoi = {
|
const MyJoi = {
|
||||||
@@ -23,7 +24,8 @@ const MyJoi = {
|
|||||||
return Joi.string().ip({
|
return Joi.string().ip({
|
||||||
version: [
|
version: [
|
||||||
'ipv6'
|
'ipv6'
|
||||||
]
|
],
|
||||||
|
cidr: 'forbidden'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ipv6Array: function(){
|
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({
|
router.route({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -54,10 +114,7 @@ router.route({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (ctx) => {
|
handler: getIpList
|
||||||
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)) };
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -77,43 +134,13 @@ router.route({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (ctx) => {
|
handler: addIp
|
||||||
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)) };
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.use(require('koa-static')('./static'));
|
app.use( logger );
|
||||||
app.use( async ( ctx, next ) => {
|
app.use( require('koa-static')('./static') );
|
||||||
try {
|
app.use( rateLimiterMiddleWare );
|
||||||
await rateLimiter.consume(ctx.ip)
|
app.use( router.middleware() );
|
||||||
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.listen( 3553 );
|
app.listen( 3553 );
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -46,8 +46,7 @@ var app = new Vue({
|
|||||||
this.ips = res.ips;
|
this.ips = res.ips;
|
||||||
})
|
})
|
||||||
.catch( res =>{
|
.catch( res =>{
|
||||||
console.log( res );
|
alert( res.error )
|
||||||
// alert( res.error )
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -5,11 +5,19 @@
|
|||||||
<title>IPV6 global ip test</title>
|
<title>IPV6 global ip test</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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">
|
<div id="app">
|
||||||
<h3>List of global IPv6 address assigned to this server</h3>
|
<h3>List of global IPv6 address assigned to this server</h3>
|
||||||
<ul id="cont-ip-list">
|
<ul id="cont-ip-list">
|
||||||
<li v-for="ip in ips">
|
<li v-for="ip in ips">
|
||||||
<a :href="'http://[' + ip + ']:3553'">
|
<a target="_blank" :href="'http://[' + ip + ']:3553'">
|
||||||
{{ ip }}
|
{{ ip }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user