#!/usr/bin/env python3
import netifaces
import netaddr
import socket
import subprocess
import sys
import argparse
import urllib.request
from cdclib import getid, getmodel, getserial

def fetchpage(ip):
    response = "Error"
    url = 'http://{}'.format(ip)
    req = urllib.request.Request(url)
    try:
        response = urllib.request.urlopen(req).read().decode('utf-8')
    except urllib.error.HTTPError as e:
        if e.code == 404:
            print('{}: 404 Page not found'.format(ip))
        elif e.code == 403:
            print('{}: 403 Access denied'.format(ip))
        elif e.code == 401:
            print('{}: 401 Unauthorized'.format(ip))
        else:
            print('{}: Unknown HTTP error: {}'.format(ip,e.code))
        pass
    except urllib.error.URLError as e:
        print('{}: HTTP Misc Error Occurred {}'.format(ip,e.reason))
        pass
    except UnicodeDecodeError as e:
        print('{}: Decode Error Occurred {}'.format(ip,e.reason))
        pass
    except:
        print("Unexpected error:", sys.exc_info()[0])
        pass
    return response

def fetchhostname(ip):
    response = "Hostname Error"
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(1)
    try:
        s.connect((ip, 4242))
        msg = b'hostname'
        s.send(msg)
        while True:
            part = s.recv(1024)
            received += part
            if not part:
                break
            response = json.loads(received.decode())
    except socket.error as e:
        print(ip, e)
        pass
    finally:
        s.close()
    return response
 
def scansingle(ip,port):
    remoteServerIP  = socket.gethostbyname(str(ip))
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(.1)
    result = sock.connect_ex((remoteServerIP, port))
    sock.close()
    if result == 0:
        return("Port {}:      Open".format(port))
    else:
        return

def main():
    ifaces = netifaces.interfaces()
    myiface = 'eth0'
    addrs = netifaces.ifaddresses(myiface)
    ipinfo = addrs[socket.AF_INET][0]
    address = ipinfo['addr']
    netmask = ipinfo['netmask']
    cidr = netaddr.IPNetwork('%s/%s' % (address, netmask))
    network = cidr.network
    broadcast = cidr.broadcast

    parser = argparse.ArgumentParser(description='Display Engine Discovery Tools')
    parser.add_argument('-amt', action='store_true', help='Search for Intel AMT Engines')
    parser.add_argument('-apc', action='store_true', help='Search for APC PDUs')
    parser.add_argument('-de', action='store_true', help='Search for Display Engines')
    parser.add_argument('-nec', action='store_true', help='Search for NEC Monitors')
    args = parser.parse_args()
    if not any([args.amt, args.apc, args.de, args.nec]):
        parser.print_help()
        quit()
    if args.nec:
        displaylistforpdcommsconfig = []
        displaylistforcdcconfig = ''
        displaylistno = 1
        print('Scanning {} {} for NEC Displays'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                port1 = scansingle(ip,80)
                port2 = scansingle(ip,7142)
                if port1 and port2:
                    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    s.connect((str(ip), 7142))
                    displayid = getid(s)
                    displaymodel = getmodel(displayid,s)
                    displayserial = getserial(displayid,s)
                    print('{}: *** Found NEC Display: Model: {} ID: {} Serial: {} ***'.format(ip,displaymodel,displayid,displayserial))
                    displaylistforcdcconfig += ('IP%d=%s\n' % (displaylistno,ip))
#                    print('IP%d=%s' % (displaylistno,ip))
                    displaylistforpdcommsconfig.append([displaylistno,ip])
                    displaylistno += 1
        print('\nFor CDC Config:')
        print(displaylistforcdcconfig)
        print('For PD Comms Config:')
        print(displaylistforpdcommsconfig)
        print('\n')
    if args.apc:
        apclist = []
        apclistno = 1
        print('Scanning {} {} for APC Products'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                port1 = scansingle(ip,80)
                port2 = scansingle(ip,23)
                if port1 and port2:
                    if 'apc' in fetchpage(ip):
                        print('{}: *** APC found ***' .format(ip))
                        apclist.append([apclistno,ip])
                        apclistno += 1
    if args.amt:
        amtlist = []
        amtlistno = 1
        print('Scanning {} {} for Intel AMT Engines'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                port1 = scansingle(ip,22)
                port2 = scansingle(ip,16992)
                if port1 and port2:
                    print('{}: *** Intel AMT Engine found ***' .format(ip))
                    amtlistno += 1
    if args.de:
        delist = []
        delistno = 1
        print('Scanning {} {} for Display Engines'.format(cidr.cidr,cidr.netmask))
        for ip in netaddr.IPNetwork(cidr):
            if ip != network and ip != broadcast:
                port1 = scansingle(ip,4242)
                port2 = scansingle(ip,22)
                if port1 and port2:
                    hostname=fetchhostname(ip)
                    print('{0} {1}: *** Display Engine found ***' .format(ip,hostname))
                    delist.append([delistno,ipi,hostname])
                    delistno += 1

if __name__ == '__main__':
   main()
