#!/usr/bin/env python3

import os
import socket
import requests 
import pprint
import random
import time
import subprocess

SCRIPT_VERSION = "v0.8"
SERVICEURL = "https://services01.htl-braunau.at/raspiSearch/raspi_update.php"

GROUP = "LVIS"
EXPECTED_UPDATE_INTERVALL = 1
ENTRY_LIFETIME = 1440
SECRETTOKEN = ""
ifaceFilterList = ()  # leer = alle erlaubten werden verwendet

pp = pprint.PrettyPrinter(indent=4)

ALLOWED_PREFIXES = ("eth", "en")  # nur echte Interfaces (z.. eth0, enp0s3)


def is_valid_ipv4_address(address):
    try:
        socket.inet_pton(socket.AF_INET, address)
    except AttributeError:
        try:
            socket.inet_aton(address)
        except socket.error:
            return False
        return address.count('.') == 3
    except socket.error:
        return False
    return True

def is_valid_ipv6_address(address):
    try:
        socket.inet_pton(socket.AF_INET6, address)
    except socket.error:
        return False
    return True

def get_ipv4_address(ifName):
    try:
        result = subprocess.run(["ip", "-4", "addr", "show", ifName], stdout=subprocess.PIPE, text=True)
        lines = result.stdout.splitlines()
        for line in lines:
            line = line.strip()
            if line.startswith("inet "):
                ip = line.split()[1].split('/')[0]
                if is_valid_ipv4_address(ip):
                    return ip
    except Exception:
        pass
    return ""

def get_ipv6_address(ifName):
    try:
        result = subprocess.run(["ip", "-6", "addr", "show", ifName], stdout=subprocess.PIPE, text=True)
        lines = result.stdout.splitlines()
        for line in lines:
            line = line.strip()
            if line.startswith("inet6 "):
                ip = line.split()[1].split('/')[0]
                if is_valid_ipv6_address(ip):
                    return ip
    except Exception:
        pass
    return ""

def get_interface_info(ifName):
    ifInfo = {}
    rootPath = "/sys/class/net/" + ifName + "/"

    ifInfo["ifName"] = ifName

    with open(rootPath + "address") as f:
        macAdress = f.read().strip()
    ifInfo["mac"] = macAdress   

    with open(rootPath + "operstate") as f:
        operstate = f.read().strip()
    ifInfo["operstate"] = operstate     

    ipv4Address = get_ipv4_address(ifName) 
    ifInfo["ipv4"] = ipv4Address

    ipv6Address = get_ipv6_address(ifName) 
    ifInfo["ipv6"] = ipv6Address 

    ifInfo["isPhysDev"] = os.path.islink(rootPath + "device")

    return ifInfo

def createHostInfo():
    hostInfo = {}
    hostInfo["hostname"] = socket.gethostname()
    hostInfo["interfaces"] = []

    ifList = os.listdir('/sys/class/net/')

    for ifName in ifList:
        if not ifName.startswith(ALLOWED_PREFIXES):
            continue

        rootPath = "/sys/class/net/" + ifName
        if not os.path.isdir(rootPath):
            continue

        try:
            ifInfo = get_interface_info(ifName)
            hostInfo["interfaces"].append(ifInfo)
        except Exception as e:
            print(f"Error processing interface {ifName}: {e}")

    return hostInfo

def filterInterfaces(hostInfo):
    if len(ifaceFilterList) == 0: 
        return hostInfo

    newHostInfoList = []
    for ifInfo in hostInfo["interfaces"]: 
        if ifInfo["ifName"] in ifaceFilterList:
            newHostInfoList.append(ifInfo)
    
    hostInfo["interfaces"] = newHostInfoList
    return hostInfo

def sendToServer(hostInfo):
    timeDelay = random.randrange(0, 5000) / 1000
    time.sleep(timeDelay)
    print("Waiting: {:.2f} sec".format(timeDelay))
    
    for ifInfo in hostInfo["interfaces"]: 
        PARAMS = {
            'mac': ifInfo["mac"],
            'ip': ifInfo["ipv4"],
            'hostname': hostInfo["hostname"],
            'iface': ifInfo["ifName"],
            'group': GROUP,
            'updateIntervall': EXPECTED_UPDATE_INTERVALL,
            'entryLifetime': ENTRY_LIFETIME,
            'secretToken': SECRETTOKEN,
            "scriptVersion": SCRIPT_VERSION
        }

        if ifInfo["operstate"].lower() == "up" and ifInfo["ipv4"]:   # and ifInfo["isPhysDev"]:
            print("Interface: {} sended ...............".format(ifInfo["ifName"]))
            try:
                r = requests.get(url=SERVICEURL, params=PARAMS)
            except Exception as e:
                print(f"Error sending to server: {e}")
        else:
            print("Interface: {} skipped".format(ifInfo["ifName"]))
            print(f" - operstate: {ifInfo['operstate']}")
            print(f" - ipv4: {ifInfo['ipv4']}")
            print(f" - isPhysDev: {ifInfo['isPhysDev']}")

###########################################################

hostInfo = createHostInfo()
hostInfo = filterInterfaces(hostInfo)
sendToServer(hostInfo)

#pp.pprint(hostInfo)
