DataTables filter by ip address

DataTables filter by ip address

I had to make a custom filter for ip address which accepted cidr notation (e.g /24). While there was the function to sort by ip at the time when i was doing it, a filter by ip address that accepted cidr or subnet masks function didn’t seem to have been implemented. I couldn’t find any publicly available solution online either, so i took some time to implement it. The solution is in php but can be easily ported to javascript/html if you wish

To get it to work on your own code, you will have to modify the 2 variables

var ipColNum = 0; // column number of your ip address

var tableId = “#results”; // table id that you want to attach datatables to

<!--jquery-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<!--datatables-->
<link rel='stylesheet' type='text/css' href='//cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css'/>
<script type='text/javascript' src='//cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js'></script>


<table id="results">
  <thead>
    <tr>
      <th>Ip Address</th>
      <th>Name</th>
      <th>Country</th>
    </tr>
  </thead>
  
  <tbody>
    <tr>
      <td>192.168.0.1</td>
      <td>abc</td>
      <td>abc country</td>
    </tr>
    <tr>
      <td>122.20.21.133</td>
      <td>xyz</td>
      <td>xyz country</td>
    </tr>
    <tr>
      <td>192.168.0.10</td>
      <td>john</td>
      <td>john country</td>
    </tr>
    <tr>
      <td>192.168.1.1</td>
      <td>sally</td>
      <td>sally country</td>
    </tr>
  </tbody>
</table>


<script>
    var table = null;
    var ipColNum = 0; // set the column number for the ip address
    var tableId = "#results";
    
    function getIpRangeFromAddressAndNetmask(str) {
      var part = str.split("/"); // part[0] = base address, part[1] = netmask
      var ipaddress = part[0].split('.');
      var netmaskblocks = ["0","0","0","0"];
      if(!/\d+\.\d+\.\d+\.\d+/.test(part[1])) {
        // part[1] has to be between 0 and 32
        netmaskblocks = ("1".repeat(parseInt(part[1], 10)) + "0".repeat(32-parseInt(part[1], 10))).match(/.{1,8}/g);
        netmaskblocks = netmaskblocks.map(function(el) { return parseInt(el, 2); });
      } else {
        // xxx.xxx.xxx.xxx
        netmaskblocks = part[1].split('.').map(function(el) { return parseInt(el, 10) });
      }
      var invertedNetmaskblocks = netmaskblocks.map(function(el) { return el ^ 255; });
      var baseAddress = ipaddress.map(function(block, idx) { return block & netmaskblocks[idx]; });
      var broadcastaddress = ipaddress.map(function(block, idx) { return block | invertedNetmaskblocks[idx]; });
      return [baseAddress.join('.'), broadcastaddress.join('.')];
    }

  function ip2long(IP) {
    var i = 0;
    IP = IP.match( /^([1-9]\d*|0[0-7]*|0x[\da-f]+)(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?$/i );
    if (!IP) { return false; }
    IP[0] = 0;
    for (i = 1; i < 5; i += 1) {
      IP[0] += !!((IP[i] || '').length);
      IP[i] = parseInt(IP[i]) || 0;
    }
    IP.push(256, 256, 256, 256);
    IP[4 + IP[0]] *= Math.pow(256, 4 - IP[0]);
    if (IP[1] >= IP[5] || IP[2] >= IP[6] || IP[3] >= IP[7] || IP[4] >= IP[8]) { return false; }
    return IP[1] * (IP[0] === 1 || 16777216) + IP[2] * (IP[0] <= 2 || 65536) + IP[3] * (IP[0] <= 3 || 256) + IP[4] * 1;
  }

//https://www.jqueryscript.net/demo/DataTables-Jquery-Table-Plugin/examples/plug-ins/range_filtering.html
var ipFilter = function(searchValue) {
    $.fn.dataTable.ext.search.push(
        function( settings, data, dataIndex ) {
            console.log("srchValue" + searchValue);
            var ipRange = searchValue;
            var colIpAddr = data[0]; // use data for the age column
     				var range = getIpRangeFromAddressAndNetmask(ipRange);
            var min = ip2long(range[0]);
            var max = ip2long(range[1]);

            //console.log(ipRange);
            //console.log("min : " + min + " max : " + max);
            //console.log("chk : " + colIpAddr);

            var longIpAddr = ip2long(colIpAddr);
            
            if( longIpAddr >= min && longIpAddr <= max ) {
                return true;
            }
            return false;
        }
    );

    table.draw();
    $.fn.dataTable.ext.search.pop();
};

 

$(document).ready( function () {
    table = $(tableId).DataTable({
        responsive: true
    });

    if( !table ) {
        console.log("Failed to initialize DataTable()");
    } else {
   
        // Change filter algorithm when cidr notation detected
        $('.dataTables_filter input').unbind().keyup(function() 
        {
            var value = $(this).val();
            if (value.length==0) {
                table.search('').draw();
                return;
            }

            // Must have the format xxx.xxx.xxx.xxx/0-32 
            // Does not match any string without a '/<number>' at the back.
            if( /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))$/.test(value) ) {
                // We need to reset the table first, otherwise our filter won't work 
                // probably because it detects e.g 192.168.0.1/32 -> 192.168.0.1, 192.168.0.1/ , 192.168.0.1/3, 192.168.0.1/32. The earlier 2 has to results.
       
                table.search('').draw();
                ipFilter(value);
            } else {
                table.search(value).draw();
            }
        });
        
    }
} );


</script>

 

See it in action over at the JsFiddle : here¬†or below .You can test it out by putting a search value of “192.168.0.0/23” or any others of your choice

Enjoyed the content ? Share it with your friends !

Python pingsweep script

Python pingsweep script

This python pingsweep script basically does a ping sweep over a specified ip range (with cidr notation) and generates the output in a .txt file . it should work on both python2+ and python3+

Output will give the following fields

  • ip address
  • reverse nslookup for domain name
  • get title of website if any
  • get http code

It currently is only able to do /24 scans (256 ips).If i have time in the future i will work on it to accept any ip range, and hopefully make it multi-threaded so that scans don’t take too low.

The code may be outdated. So best to refer to github link below

# ping sweep
# firstly, we ping to see if the server at ip is alive
# secondly, we test to see if it responds to http request(80)

import subprocess
import os
import urllib.request
import socket


def log_ping(file_name, msg):
    with open(file_name, "a") as ipFile:
        ipFile.write(msg + "\n")

def http_ping(ip):
    try:
        response = urllib.request.urlopen("http://" + ip).getcode()
        return response
    except:
        return 0
def rdns_lookup(ip):
    try:
        return socket.gethostbyaddr(ip)
    except socket.error:
        return "<couldnt get domain name>"
    
def get_html_title(ip):
    webpage = urllib.request.urlopen("http://" + ip).read()
    html = str(webpage)
    if "<title>" in html: #sometimes the document doesnt have a title tag
        title = html.split('<title>')[1].split('</title>')[0]
        return title
    return "<cant parse title>"
    
    
ip = input("Enter a /24 in the format e.g 10.21.32. : ")	
if ip.count('.') != 3:
    input("IP Format is wrong. Please restart and try again ")
    quit()
        
file_name = ip + "0.txt"
log_ping(file_name, "The format is as follow - <ip address>, <active>, <http response code>, <html title>")
    
with open(os.devnull, "wb") as limbo:
    for n in range(0, 256):
        scan_ip = ip + str(n) 
        result=subprocess.Popen(["ping", "-n", "1", "-w", "200", scan_ip],
        stdout=limbo, stderr=limbo).wait()
        if result:
            msg = scan_ip + " inactive"
            print(msg)
            log_ping(file_name, msg)
        else:
            response = http_ping(scan_ip)
            title = ""
            if response == 200:
                title = get_html_title(scan_ip)
                    
            domain = rdns_lookup(scan_ip)
            
            msg = scan_ip + "({0})".format(domain) + " active, " + str(response) + " , " + title
            print(msg)
            log_ping(file_name, msg)

Github link : here

 

 

Enjoyed the content ? Share it with your friends !