Compare commits
	
		
			2 Commits
		
	
	
		
			bd8b57efd1
			...
			bc93b942ee
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					bc93b942ee | ||
| 
						 | 
					c3934acb30 | 
@ -89,6 +89,8 @@ Options
 | 
				
			|||||||
+time=<seconds>             Sets the timeout for a query in seconds.
 | 
					+time=<seconds>             Sets the timeout for a query in seconds.
 | 
				
			||||||
+norecurse                  Set `ra` flag to 0. Do not perform recursion.
 | 
					+norecurse                  Set `ra` flag to 0. Do not perform recursion.
 | 
				
			||||||
+aaonly                     Set `aa` flag to 1. Do not respond with non-authoritative responses.
 | 
					+aaonly                     Set `aa` flag to 1. Do not respond with non-authoritative responses.
 | 
				
			||||||
 | 
					+notcp                      Disable TCP server (default in v1.2)
 | 
				
			||||||
 | 
					+tcp                        Enable TCP server (default in v1.3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--debug                     verbose output
 | 
					--debug                     verbose output
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										103
									
								
								bin/digd.js
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								bin/digd.js
									
									
									
									
									
								
							@ -5,9 +5,7 @@
 | 
				
			|||||||
var cli = require('cli');
 | 
					var cli = require('cli');
 | 
				
			||||||
var pkg = require('../package.json');
 | 
					var pkg = require('../package.json');
 | 
				
			||||||
var dig = require('dig.js/dns-request');
 | 
					var dig = require('dig.js/dns-request');
 | 
				
			||||||
var dgram = require('dgram');
 | 
					 | 
				
			||||||
var dnsjs = require('dns-suite');
 | 
					var dnsjs = require('dns-suite');
 | 
				
			||||||
var crypto = require('crypto');
 | 
					 | 
				
			||||||
var common = require('dig.js/common');
 | 
					var common = require('dig.js/common');
 | 
				
			||||||
var defaultNameservers = require('dns').getServers();
 | 
					var defaultNameservers = require('dns').getServers();
 | 
				
			||||||
var hexdump;
 | 
					var hexdump;
 | 
				
			||||||
@ -49,8 +47,32 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
      cli.norecurse = true;
 | 
					      cli.norecurse = true;
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (arg === '+notcp') {
 | 
				
			||||||
 | 
					      if (cli.notcp) {
 | 
				
			||||||
 | 
					        console.error("'+notcp' was specified more than once");
 | 
				
			||||||
 | 
					        process.exit(1);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      cli.notcp = true;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (arg === '+tcp') {
 | 
				
			||||||
 | 
					      if (cli.tcp) {
 | 
				
			||||||
 | 
					        console.error("'+tcp' was specified more than once");
 | 
				
			||||||
 | 
					        process.exit(1);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      cli.tcp = true;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!cli.tcp) {
 | 
				
			||||||
 | 
					    if (!cli.notcp) {
 | 
				
			||||||
 | 
					      console.info("[WARNING] Set '+notcp' to disable tcp connections. The default behavior changes to +tcp in v1.3");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (cli.mdns) {
 | 
					  if (cli.mdns) {
 | 
				
			||||||
    if (!cli.type) {
 | 
					    if (!cli.type) {
 | 
				
			||||||
      cli.type = cli.t = 'PTR';
 | 
					      cli.type = cli.t = 'PTR';
 | 
				
			||||||
@ -73,32 +95,10 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var handlers = {};
 | 
					  var dnsd = {};
 | 
				
			||||||
  var server = dgram.createSocket({
 | 
					  dnsd.onMessage = function (nb, cb) {
 | 
				
			||||||
    type: cli.udp6 ? 'udp6' : 'udp4'
 | 
					    var byteOffset = nb._dnsByteOffset || nb.byteOffset;
 | 
				
			||||||
  , reuseAddr: true
 | 
					    var queryAb = nb.buffer.slice(byteOffset, byteOffset + nb.byteLength);
 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  server.bind({
 | 
					 | 
				
			||||||
    port: cli.port
 | 
					 | 
				
			||||||
  , address: cli.address
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handlers.onError = function (err) {
 | 
					 | 
				
			||||||
    if ('EACCES' === err.code) {
 | 
					 | 
				
			||||||
      console.error("");
 | 
					 | 
				
			||||||
      console.error("EACCES: Couldn't bind to port. You probably need to use sudo, authbind, or setcap.");
 | 
					 | 
				
			||||||
      console.error("");
 | 
					 | 
				
			||||||
      process.exit(123);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    console.error("error:", err.stack);
 | 
					 | 
				
			||||||
    server.close();
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handlers.onMessage = function (nb, rinfo) {
 | 
					 | 
				
			||||||
    console.log('[DEBUG] got a message');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var queryAb = nb.buffer.slice(nb.byteOffset, nb.byteOffset + nb.byteLength);
 | 
					 | 
				
			||||||
    var query;
 | 
					    var query;
 | 
				
			||||||
    var count;
 | 
					    var count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -215,12 +215,11 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
        console.error("Could not write empty DNS response");
 | 
					        console.error("Could not write empty DNS response");
 | 
				
			||||||
        console.error(e);
 | 
					        console.error(e);
 | 
				
			||||||
        console.error(emptyResp);
 | 
					        console.error(emptyResp);
 | 
				
			||||||
 | 
					        cb(e, null, '[DEV] response sent (empty)');
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      server.send(newAb, rinfo.port, rinfo.address, function () {
 | 
					      cb(null, newAb, '[DEV] response sent (empty)');
 | 
				
			||||||
        console.log('[DEV] response sent (empty)', rinfo.port, rinfo.address);
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function sendResponse(newPacket) {
 | 
					    function sendResponse(newPacket) {
 | 
				
			||||||
@ -232,12 +231,11 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
        console.error("Could not write DNS response from local");
 | 
					        console.error("Could not write DNS response from local");
 | 
				
			||||||
        console.error(e);
 | 
					        console.error(e);
 | 
				
			||||||
        console.error(newPacket);
 | 
					        console.error(newPacket);
 | 
				
			||||||
 | 
					        cb(e, null, '[DEV] response sent (local query)');
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      server.send(newAb, rinfo.port, rinfo.address, function () {
 | 
					      cb(null, newAb, '[DEV] response sent (local query)');
 | 
				
			||||||
        console.log('[DEV] response sent (local query)', rinfo.port, rinfo.address);
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function recurse() {
 | 
					    function recurse() {
 | 
				
			||||||
@ -290,12 +288,11 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
            } catch(e) {
 | 
					            } catch(e) {
 | 
				
			||||||
              console.error("Could not write DNS response");
 | 
					              console.error("Could not write DNS response");
 | 
				
			||||||
              console.error(newResponse);
 | 
					              console.error(newResponse);
 | 
				
			||||||
 | 
					              cb(e, null, '[DEV] response sent');
 | 
				
			||||||
              return;
 | 
					              return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            server.send(newAb, rinfo.port, rinfo.address, function () {
 | 
					            cb(null, newAb, '[DEV] response sent');
 | 
				
			||||||
              console.log('[DEV] response sent', rinfo.port, rinfo.address);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -335,7 +332,8 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
              console.log('request sent to', res.nameserver);
 | 
					              console.log('request sent to', res.nameserver);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            */
 | 
					            */
 | 
				
			||||||
            console.log('[DEV] query sent (recurse)', rinfo.port, rinfo.address);
 | 
					            //console.log('[DEV] query sent (recurse)', rinfo.port, rinfo.address);
 | 
				
			||||||
 | 
					            //dnsd.onSent('[DEV] query sent (recurse)');
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        , onTimeout: function (res) {
 | 
					        , onTimeout: function (res) {
 | 
				
			||||||
            console.log(";; [" + q.name + "] connection timed out; no servers could be reached");
 | 
					            console.log(";; [" + q.name + "] connection timed out; no servers could be reached");
 | 
				
			||||||
@ -393,32 +391,24 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    require('../lib/digd.js').query(engine, query, respondWithResults);
 | 
					    require('../lib/digd.js').query(engine, query, respondWithResults);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handlers.onListening = function () {
 | 
					  cli.defaultNameservers = defaultNameservers;
 | 
				
			||||||
    /*jshint validthis:true*/
 | 
					  require('../lib/udpd.js').create(cli, dnsd).on('listening', function () {
 | 
				
			||||||
    var server = this;
 | 
					 | 
				
			||||||
    cli.chosenNameserver = cli.nameserver;
 | 
					    cli.chosenNameserver = cli.nameserver;
 | 
				
			||||||
    var index;
 | 
					    var index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!cli.chosenNameserver) {
 | 
					    if (!cli.chosenNameserver) {
 | 
				
			||||||
      index = crypto.randomBytes(2).readUInt16BE(0) % defaultNameservers.length;
 | 
					      index = require('crypto').randomBytes(2).readUInt16BE(0) % cli.defaultNameservers.length;
 | 
				
			||||||
      cli.chosenNameserver = defaultNameservers[index];
 | 
					      cli.chosenNameserver = cli.defaultNameservers[index];
 | 
				
			||||||
      if (cli.debug) {
 | 
					      if (cli.debug) {
 | 
				
			||||||
        console.log('index, defaultNameservers', index, defaultNameservers);
 | 
					        console.log('index, defaultNameservers', index, cli.defaultNameservers);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
    if (cli.mdns || '224.0.0.251' === cli.nameserver) {
 | 
					  if (cli.tcp /* TODO v1.3 !cli.notcp */) {
 | 
				
			||||||
      server.setBroadcast(true);
 | 
					    require('../lib/tcpd.js').create(cli, dnsd);
 | 
				
			||||||
      server.addMembership(cli.nameserver);
 | 
					  }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    console.log('');
 | 
					 | 
				
			||||||
    console.log('Bound and Listening:');
 | 
					 | 
				
			||||||
    console.log(server.address().address + '#' + server.address().port + ' (' + server.type + ')');
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log('');
 | 
					  console.log('');
 | 
				
			||||||
  if (!cli.nocmd) {
 | 
					  if (!cli.nocmd) {
 | 
				
			||||||
@ -426,7 +416,4 @@ cli.main(function (args, cli) {
 | 
				
			|||||||
    console.log(';; global options: +cmd');
 | 
					    console.log(';; global options: +cmd');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  server.on('error', handlers.onError);
 | 
					 | 
				
			||||||
  server.on('message', handlers.onMessage);
 | 
					 | 
				
			||||||
  server.on('listening', handlers.onListening);
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										70
									
								
								lib/tcpd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								lib/tcpd.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.create = function (cli, dnsd) {
 | 
				
			||||||
 | 
					  function runTcp() {
 | 
				
			||||||
 | 
					    var tcpServer = require('net').createServer({ }, function (c) {
 | 
				
			||||||
 | 
					      c.on('error', function (err) {
 | 
				
			||||||
 | 
					        console.warn("TCP Connection Error:");
 | 
				
			||||||
 | 
					        console.warn(err);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      c.on('data', function (nb) {
 | 
				
			||||||
 | 
					        //console.log('TCP data.length:', nb.length);
 | 
				
			||||||
 | 
					        //console.log(nb.toString('hex'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // DNS packets include a 2-byte length header
 | 
				
			||||||
 | 
					        var count = nb.length;
 | 
				
			||||||
 | 
					        var length = nb[0] << 8;
 | 
				
			||||||
 | 
					        length = length | nb[1];
 | 
				
			||||||
 | 
					        count -= 2;
 | 
				
			||||||
 | 
					        // TODO slice?
 | 
				
			||||||
 | 
					        nb._dnsByteOffset = nb.byteOffset + 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (length !== count) {
 | 
				
			||||||
 | 
					          console.error("Handling TCP packets > 512 bytes not implemented.");
 | 
				
			||||||
 | 
					          c.end();
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TODO pad two bytes for lengths
 | 
				
			||||||
 | 
					        dnsd.onMessage(nb, function (err, newAb, dbgmsg) {
 | 
				
			||||||
 | 
					          var lenbuf = Buffer.from([ newAb.length >> 8, newAb.length & 255 ]);
 | 
				
			||||||
 | 
					          // TODO XXX generate legit error packet
 | 
				
			||||||
 | 
					          if (err) { console.error("Error", err); c.end(); return; }
 | 
				
			||||||
 | 
					          console.log('TCP ' + dbgmsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          c.write(lenbuf);
 | 
				
			||||||
 | 
					          c.end(newAb);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      c.on('end', function () {
 | 
				
			||||||
 | 
					        console.log('TCP client disconnected from server');
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tcpServer.on('error', function (err) {
 | 
				
			||||||
 | 
					      if ('EADDRINUSE' === err.code) {
 | 
				
			||||||
 | 
					        console.error("Port '" + cli.port + "' is already in use.");
 | 
				
			||||||
 | 
					        tcpServer.close();
 | 
				
			||||||
 | 
					        process.exit(0);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if ('EACCES' === err.code) {
 | 
				
			||||||
 | 
					        console.error("Could not bind on port '" + cli.port + "': EACCESS (you probably need root permissions)");
 | 
				
			||||||
 | 
					        tcpServer.close();
 | 
				
			||||||
 | 
					        process.exit(0);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      console.error("TCP Server Error:");
 | 
				
			||||||
 | 
					      console.error(err);
 | 
				
			||||||
 | 
					      tcpServer.close(function () {
 | 
				
			||||||
 | 
					        setTimeout(runTcp, 1000);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tcpServer.listen(cli.port, function () {
 | 
				
			||||||
 | 
					      console.log('TCP Server bound');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return tcpServer;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return runTcp();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										58
									
								
								lib/udpd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								lib/udpd.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.create = function (cli, dnsd) {
 | 
				
			||||||
 | 
					  var server = require('dgram').createSocket({
 | 
				
			||||||
 | 
					    type: cli.udp6 ? 'udp6' : 'udp4'
 | 
				
			||||||
 | 
					  , reuseAddr: true
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  server.bind({
 | 
				
			||||||
 | 
					    port: cli.port
 | 
				
			||||||
 | 
					  , address: cli.address
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var handlers = {};
 | 
				
			||||||
 | 
					  handlers.onError = function (err) {
 | 
				
			||||||
 | 
					    if ('EACCES' === err.code) {
 | 
				
			||||||
 | 
					      console.error("");
 | 
				
			||||||
 | 
					      console.error("EACCES: Couldn't bind to port. You probably need to use sudo, authbind, or setcap.");
 | 
				
			||||||
 | 
					      console.error("");
 | 
				
			||||||
 | 
					      process.exit(123);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    console.error("error:", err.stack);
 | 
				
			||||||
 | 
					    server.close();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handlers.onMessage = function (nb, rinfo) {
 | 
				
			||||||
 | 
					    //console.log('[DEBUG] got a UDP message', nb.length);
 | 
				
			||||||
 | 
					    //console.log(nb.toString('hex'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dnsd.onMessage(nb, function (err, newAb, dbgmsg) {
 | 
				
			||||||
 | 
					      // TODO send legit error message
 | 
				
			||||||
 | 
					      if (err) { server.send(Buffer.from([0x00])); return; }
 | 
				
			||||||
 | 
					      server.send(newAb, rinfo.port, rinfo.address, function () {
 | 
				
			||||||
 | 
					        console.log(dbgmsg, rinfo.port, rinfo.address);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handlers.onListening = function () {
 | 
				
			||||||
 | 
					    /*jshint validthis:true*/
 | 
				
			||||||
 | 
					    var server = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cli.mdns || '224.0.0.251' === cli.nameserver) {
 | 
				
			||||||
 | 
					      server.setBroadcast(true);
 | 
				
			||||||
 | 
					      server.addMembership(cli.nameserver);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    console.log('');
 | 
				
			||||||
 | 
					    console.log('Bound and Listening:');
 | 
				
			||||||
 | 
					    console.log(server.address().address + '#' + server.address().port + ' (' + server.type + ')');
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  server.on('error', handlers.onError);
 | 
				
			||||||
 | 
					  server.on('message', handlers.onMessage);
 | 
				
			||||||
 | 
					  server.on('listening', handlers.onListening);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return server;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "digd.js",
 | 
					  "name": "digd.js",
 | 
				
			||||||
  "version": "1.2.0",
 | 
					  "version": "1.2.1",
 | 
				
			||||||
  "description": "A lightweight DNS / mDNS daemon (server) for creating and capturing DNS and mDNS query and response packets to disk as binary and/or JSON. Options are similar to the Unix dig command.",
 | 
					  "description": "A lightweight DNS / mDNS daemon (server) for creating and capturing DNS and mDNS query and response packets to disk as binary and/or JSON. Options are similar to the Unix dig command.",
 | 
				
			||||||
  "main": "bin/digd.js",
 | 
					  "main": "bin/digd.js",
 | 
				
			||||||
  "homepage": "https://git.coolaj86.com/coolaj86/digd.js",
 | 
					  "homepage": "https://git.coolaj86.com/coolaj86/digd.js",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user