IPv6 Capability Test Script
<?php
header('Content-type: text/javascript');
echo "
// GPLv3
// $Id: ipprototest.js 27701 2011-01-26 15:21:50Z eaben $
// 2011 Hacked on by Byron Ellacott, APNIC
// 2011 Hacked on by George Michaelson, APNIC
// Written by Emile Aben, RIPE NCC
// Code inspired by Sander Steffann's IPv6test at http://v6test.max.nl/
(function() {
var __ipprototest;
IPProtoTest = function (opts) {
if ( this instanceof IPProtoTest ) {
this._version = '10a';
this._done = false;
this.userId = '6';
this.timeout = 10000; // 10 seconds
this.noCheckInterval = 86400000; // 1 day
this.domainSuffix = 'potaroo.net';
this.testSet = ['ipv6only','dualstack','ipv4only'];
this.testSetLen = this.testSet.length; // shortcut
this.randomize = false; // disable shuffling
this.dotunnels = false; // disable tunnel testing
this.domore = true; // disable tunnel testing
this.dov6literal = true; // disable tunnel testing
this.dov6dns = true; // disable tunnel testing
this.docookies = true; // enable cookie time testing
this.sampling = 1; // sampling frequency. 1 == disable
// eg 2 == 50% 20 == 5% 100 == 1%
this._testsComplete = 0;
this._now = new Date(); // keep track of init-time
this._testTime = this._now.getTime();
this._cookieExpire = new Date(this._testTime + this.noCheckInterval );
this._testId = Math.floor(Math.random()*Math.pow(2,31));
this._result = {};
// sets this._cookie_last_run etc. vars
// and set results from previous run (if available)
this.parseCookies();
//TODO compare the testset to set tested in cookies?
// override defaults
if ( opts instanceof Object) {
for ( prop in opts ) {
//safeguard is now done in the IPProtoTest(opt) call at the end of this file
this[prop] = opts[prop];
}
if ( this.dov6dns ) {
this.testSet.push('rd.t6');
}
if ( this.dov6literal ) {
this.testSet.push('v6lit');
}
if ( this.dotunnels ) {
this.testSet.push('v6stf');
this.testSet.push('v6ter');
}
if ( this.domore ) {
this.testSet.push('rd.td');
this.testSet.push('r6.td');
}
this.testSetLen = this.testSet.length;
if ( this.randomize ) { this.shuffle( this.testSet ); }
}
// make object accessible for callbacks
__ipprototest = this;
// determine if tests need to be done
if ( !this.docookies || !this._cookie_last_run ) {
if ( this.sampling > 1 && Math.random() > 1/this.sampling ) {
// not running test, but setting the cookie
if (this.docookies) this.setCookie('__ipprototest_last_run',this._testTime);
return this;
} else {
this.startTest();
}
}
return this;
} else
return new IPProtoTest(opts);
};
// public functions
IPProtoTest.prototype.doGAQ=function() {
var _gaq = window._gaq || []; // assuming google default
if (this.GAQ instanceof Object) { // .. but allow override
_gaq = this.GAQ;
}
//TODO document this
var ipv4 = this._result.r4td ? 'yes' : 'no';
var ipv6 = this._result.r6td ? 'yes' : 'no';
var dual = this._result.rdtd ? 'yes' : 'no';
if (this.dov6dns) {
var v6dns = this._result.rdt6 ? 'yes' : 'no';
}
if (this.dov6literal) {
var v6lit = this._result.v6lit ? 'yes' : 'no';
}
if (this.dotunnels) {
var v6stf = this._result.v6stf ? 'yes' : 'no';
var v6ter = this._result.v6ter ? 'yes' : 'no';
}
var summary = ((ipv4 == 'yes' ? 1 : 0) +
(ipv6 == 'yes' ? 2 : 0) +
(dual == 'yes' ? 4 : 0));
if (this.dov6dns) {
summary += ((v6dns == 'yes' ? 8 : 0));
}
if (this.dov6literal) {
summary += ((v6lit == 'yes' ? 16 : 0));
}
if (this.dotunnels) {
summary += ((v6stf == 'yes' ? 32 : 0) +
(v6ter == 'yes' ? 64 : 0));
}
// Normalize v4val to 0 if the v4 test fails.
// Normalize all other test times to relative to v4, if v4 worked
// If a test fails, set to zero.
// If v4 failed, set all tests to zero.
// This ensures zero cases, and no v4 do not contribute to avg times
var v4val = this._result.r4td ? this._result.r4td : 0;
var v6val = this._result.r6td ? (this._result.r4td ? (this._result.r6td - v4val) : 0) : 0;
var duval = this._result.rdtd ? (this._result.r4td ? (this._result.rdtd - v4val) : 0) : 0;
if (this.dov6dns) {
var dnval = this._result.v6dns ? (this._result.r4td ? (this._result.v6dns - v4val) : 0) : 0;
}
if (this.dov6literal) {
var lival = this._result.v6lit ? (this._result.r4td ? (this._result.v6lit - v4val) : 0) : 0;
}
if (this.dotunnels) {
var stval = this._result.v6stf ? (this._result.r4td ? (this._result.v6stf - v4val) : 0) : 0;
var teval = this._result.v6ter ? (this._result.r4td ? (this._result.v6ter - v4val) : 0) : 0;
}
if (this.domore) {
var stval = this._result.rd.td ? (this._result.r4td ? (this._result.td.td - v4val) : 0) : 0;
var teval = this._result.r6.td ? (this._result.r4td ? (this._result.r6.td - v4val) : 0) : 0;
}
_gaq.push(['_trackEvent', 'ipprototest', 'ipv4:' + ipv4, 'Tested', 0]);
_gaq.push(['_trackEvent', 'ipprototest', 'ipv6:' + ipv6, 'Tested', v6val]);
_gaq.push(['_trackEvent', 'ipprototest', 'dual:' + dual, 'Tested', duval]);
if (this.dov6dns) {
_gaq.push(['_trackEvent', 'ipprototest', 'v6lit:' + v6lit, 'Tested', lival]);
}
if (this.dov6literal) {
_gaq.push(['_trackEvent', 'ipprototest', 'v6dns:' + v6dns, 'Tested', dnval]);
}
if (this.dotunnels) {
_gaq.push(['_trackEvent', 'ipprototest', 'v6stf:' + v6stf, 'Tested', stval]);
_gaq.push(['_trackEvent', 'ipprototest', 'v6ter:' + v6ter, 'Tested', teval]);
}
// push summary line, this users testset.
_gaq.push(['_trackEvent', 'ipprototest', 'summary:' + summary]);
};
IPProtoTest.prototype.onFinishInit=function() {
if ( this.GAQ ) { // do Google analytics
this.doGAQ();
}
};
IPProtoTest.prototype.finishTest=function() {
// cancel the timeout
clearTimeout( __ipprototest._timeoutEvent );
if (! __ipprototest._done ) {
// report back results
var pfx = __ipprototest.getTestPfx();
for (var t_idx in __ipprototest.testSet) {
var test = __ipprototest.testSet[t_idx];
test = test.replace(/\./g,'');
pfx += [
'z',
test ,
'-' ,
__ipprototest._result[ test ] ?
__ipprototest._result[ test ] :
'null',
'.'
].join('');
}
var imgURL = [
'http://',
pfx,
'results.',
__ipprototest.domainSuffix,
'/1x1.png?',
pfx
].join('');
var req=document.createElement('img');
req.src = imgURL; // loads it
if(__ipprototest.docookies) __ipprototest.setCookie('__ipprototest_last_run', __ipprototest._testTime);
// do all the stuff that needs to be done when
// results are in
__ipprototest.onFinishInit();
__ipprototest._done = true;
// if there is a callback function, invoke it
if ( __ipprototest.callback instanceof Function ) __ipprototest.callback(__ipprototest._result);
}
};
IPProtoTest.prototype.getTestPfx = function() {
return [
't', this.timeout, '.',
'u', this._testTime , '.',
's', this._testId , '.',
'i', this.userId , '.',
'v', this._version , '.'
].join('');
};
IPProtoTest.prototype.startTest = function() {
var testPfx = this.getTestPfx();
var testPath='/1x1.png?'+testPfx;
for(var i=0;i<this.testSetLen;i++) {
var subId = this.testSet[i];
this._result[subId.replace(/\./g,'')] = false;
if (subId == 'v6lit') {
this.httpFetchImg(
'http://[2401:2000:6660::f003]'+testPath+subId,
'__ipprototest_'+subId.replace(/\./g,'') );
} else if (subId == 'v6stf') {
this.httpFetchImg(
'http://[2401:2000:6660::f00a]'+testPath+subId,
'__ipprototest_'+subId.replace(/\./g,'') );
} else if (subId == 'v6ter') {
this.httpFetchImg(
'http://[2401:2000:6660::f00b]'+testPath+subId,
'__ipprototest_'+subId.replace(/\./g,'') );
} else {
this.httpFetchImg(
'http://'+testPfx+subId+'.'+this.domainSuffix+testPath+subId,
'__ipprototest_'+subId.replace(/\./g,'') );
}
}
this._timeoutEvent = setTimeout( this.finishTest, this.timeout );
};
// Fisher-Yates Shuffle
IPProtoTest.prototype.shuffle=function( list ) {
var i = list.length;
if ( ! i ) return false;
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tmp_i = list[i];
var tmp_j = list[j];
list[i] = tmp_j;
list[j] = tmp_i;
}
return true;
};
// cookie stuff
IPProtoTest.prototype.setCookie=function(key,value) {
document.cookie = key+'='+value+';expires='+this._cookieExpire.toUTCString()+';path=/';
};
IPProtoTest.prototype.parseCookies=function() {
var _all = document.cookie.split(';');
for(var i=0, len=_all.length;i<len;i++) {
var _tmp =_all[i].split('=');
var ckName=_tmp[0].replace(/^\s+|\s+$/g,'');
var res_match;
if(ckName=='__ipprototest_last_run'){
this._cookie_last_run = parseInt(unescape(_tmp[1].replace(/^\s+|\s+$/g,'')),10);
}
}
};
function __ipprototest_onload(el) {
// note to self : this = the img element, not the proto
this._duration = new Date().getTime() - this._start;
__ipprototest._testsComplete++;
var res_match = this.name.match(/^__ipprototest_(\w+)$/);
if ( res_match[1] ) { // codes like 'rdtd'
__ipprototest._result[res_match[1]] = this._duration;
}
if (__ipprototest._testsComplete >= __ipprototest.testSetLen) {
__ipprototest.finishTest();
}
}
// inspired by gih_ajax-function by Geoff Huston, George Michaelson, Byron Ellacott (APNIC)
IPProtoTest.prototype.httpFetchImg=function( url, name ) {
var req=document.createElement('img');
req.name = name;
req._start = new Date().getTime();
req.onload = __ipprototest_onload;
req.src = url;
};
})();
// initialize variables and structs to avoid null ref bugs
var ipproto_user = ipproto_user || 'anon';
var ipproto_opts = ipproto_opts || {};
// if we have been correctly initialized for google analytics setup by the user...
// the set of externally defined variables we will accept
// userID takes the ipproto_user variable by default,
// or the value passed in array externally if provided
// defaults shown below.
var opts = {
'docookies' : true, // test based on noCheckInterval in cookie
'dov6dns' : true, // test v6 dns to a dual-stack URL
'dov6literal' : true, // test a v6 literal URL
'dotunnels' : false, // test for 6to4 and teredo tunnels
'domore' : true, // test for v6 using alt server
'randomize' : false, // by default, sorted test order
'noCheckInterval' : 86400000, // interval to test on, if docoookies is true
'sampling' : 1, // 1/sampling eg sampling=4 1/4th tested
'userId' : ipproto_user, // what to log in the collector website as
'callback' : function (results){}, // prototype function to receive callback of results
'GAQ' : false // hook into google analytics
};
if ( ipproto_opts instanceof Object ) {
// for the list we know, if its in the externally set object, map it in.
for ( prop in opts ) {
if (prop in ipproto_opts) { opts[prop] = ipproto_opts[prop]; }
}
}
var ippt = IPProtoTest(opts);
";
?>