Your IP : 216.73.216.247


Current Path : /opt/cpanel/
Upload File :
Current File : //opt/cpanel/newlist.py

#!/usr/bin/env python3
"""
List every domain and its expiry date from ZARC using the coza:listDomains
EPP extension.

If the registry returns an error (e.g. result code 2102 or 2306) the script
will print the raw XML so you can confirm whether the extension is enabled
for your registrar account.
"""

import socket
import ssl
import struct
import uuid
import xml.etree.ElementTree as ET
from datetime import datetime

# ─── registry credentials ──────────────────────────────────────────────
EPP_HOST = "epp.zarc.net.za"
EPP_PORT = 700
EPP_USER = "enetworks"
EPP_PASS = "36ancerg9a2"
# If client-cert auth is required, set paths here (otherwise leave None)
CLIENT_CERT = None
CLIENT_KEY  = None

# ─── helpers ────────────────────────────────────────────────────────────
def frame(xml: str) -> bytes:
    data = xml.encode("utf-8")
    return struct.pack("!I", len(data) + 4) + data


def recv_frame(sock: ssl.SSLSocket) -> str:
    header = sock.recv(4)
    if not header:
        raise ConnectionError("socket closed while reading header")
    (length,) = struct.unpack("!I", header)
    payload = b""
    while len(payload) < length - 4:
        chunk = sock.recv(length - 4 - len(payload))
        if not chunk:
            raise ConnectionError("socket closed while reading payload")
        payload += chunk
    return payload.decode()


def login_xml() -> str:
    return f"""<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <login>
      <clID>{EPP_USER}</clID>
      <pw>{EPP_PASS}</pw>
      <options><version>1.0</version><lang>en</lang></options>
      <svcs>
        <objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
        <objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
        <svcExtension>
          <extURI>http://co.za/epp/extensions/cozadomain-1-0</extURI>
        </svcExtension>
      </svcs>
    </login>
    <clTRID>{uuid.uuid4()}</clTRID>
  </command>
</epp>"""


def list_domains_xml() -> str:
    return f"""<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <info/>
    <extension>
      <coza:list xmlns:coza="http://co.za/epp/extensions/cozadomain-1-0">
        <coza:listDomains/>
      </coza:list>
    </extension>
    <clTRID>{uuid.uuid4()}</clTRID>
  </command>
</epp>"""


def parse_domains(xml: str):
    ns = {"coza": "http://co.za/epp/extensions/cozadomain-1-0"}
    root = ET.fromstring(xml)
    for d in root.findall(".//coza:domain", ns):
        name = d.findtext("coza:name", "", ns)
        exp  = d.findtext("coza:expiryDate", "", ns)
        if exp:
            try:
                exp = datetime.fromisoformat(exp.replace("Z", "+00:00")).strftime("%Y-%m-%d")
            except ValueError:
                pass
        yield name, exp


# ─── main flow ──────────────────────────────────────────────────────────
def main():
    ctx = ssl.create_default_context()
    if CLIENT_CERT and CLIENT_KEY:
        ctx.load_cert_chain(certfile=CLIENT_CERT, keyfile=CLIENT_KEY)

    with socket.create_connection((EPP_HOST, EPP_PORT)) as tcp:
        with ctx.wrap_socket(tcp, server_hostname=EPP_HOST) as epp:
            print("[+] TLS connected")

            # 1) greeting ------------------------------------------------
            _ = recv_frame(epp)
            print("[i] Greeting received")

            # 2) login ---------------------------------------------------
            epp.sendall(frame(login_xml()))
            login_resp = recv_frame(epp).lstrip()  # trim leading whitespace
            if '<result code="1000"' in login_resp:
                print("[+] Login successful")
            else:
                print("[!] Login failed or unexpected response:")
                print(login_resp)
                return

            # 3) list domains -------------------------------------------
            epp.sendall(frame(list_domains_xml()))
            list_resp = recv_frame(epp)

            domains = list(parse_domains(list_resp))
            if not domains:
                print("[!] No <coza:domain> elements returned.")
                print("Raw XML so you can check the <result> code:\n")
                print(list_resp)
                return

            # 4) pretty output ------------------------------------------
            colw = max(len(d[0]) for d in domains) + 2
            print(f"\n{'Domain':<{colw}}Expiry")
            print("-" * (colw + 12))
            for name, exp in sorted(domains):
                print(f"{name:<{colw}}{exp}")
            print(f"\nTotal domains: {len(domains)}")

if __name__ == "__main__":
    main()