def dnsRecord(
    conn,
    name: str,
    data: str,
    dnstype: Literal["A", "AAAA", "CNAME", "MX", "PTR", "SRV", "TXT"] = "A",
    zone: str = "CurrentDomain",
    ttl: int = 300,
    preference: int = 10,
    port: int = None,
    priority: int = 10,
    weight: int = 60,
    forest: bool = False,
):
    """
    This function adds a new DNS record into an AD environment.

    :param name: name of the dnsNode object (hostname) which will contain the new record
    :param data: DNS record data, for most record types this will be the destination hostname or IP address, for TXT records this can be used for text
    :param dnstype: DNS record type
    :param zone: DNS zone
    :param ttl: DNS record TTL, time in seconds the record stays in DNS caches, must be low if you want to propagate record updates quickly
    :param preference: DNS MX record preference, must be lower than the concurrent records to be chosen
    :param port: listening port of the service in a DNS SRV record
    :param priority: priority of a DNS SRV record against concurrent, must be lower to be chosen, if identical to others, highest weight will be chosen
    :param weight: weight of a DNS SRV record against concurrent, must be higher with the lowest priority to be chosen
    :param forest: if set, registers dns record in forest instead of domain
    """
    # DNS_RPC_RECORD - section 2.2.2.2.5
    # RANK_ZONE - The record comes from an authoritative zone
    rank = 0xF0

    naming_context = "," + conn.ldap.domainNC
    if zone == "CurrentDomain":
        zone = ""
        for label in naming_context.split(",DC="):
            if label:
                zone += "." + label
        if forest:
            zone = "_msdcs" + zone
        else:
            # Removes first dot
            zone = zone[1:]

    # TODO: take into account custom ForestDnsZones and DomainDnsZones partition name ?
    if forest:
        zone_type = "ForestDnsZones"
    else:
        zone_type = "DomainDnsZones"

    zone_dn = f"DC={zone},CN=MicrosoftDNS,DC={zone_type}{naming_context}"
    record_dn = None

    serial = None
    new_dnsrecord_list = None
    ldap_filter = f"(|(name=@)(name={name}))"
    for entry in conn.ldap.bloodysearch(
        zone_dn,
        ldap_filter=ldap_filter,
        search_scope=Scope.SUBTREE,
        attr=["name", "dnsRecord"],
        raw=True,
    ):
        if entry["name"][0] == b"@":
            for raw_record in entry["dnsRecord"]:
                dns_record = dns.Record(raw_record).toDict()
                if dns_record.get("Type") == "SOA":
                    serial = dns_record["Data"]["SerialNo"]
                    break
        else:
            record_dn = entry["distinguishedName"]
            new_dnsrecord_list = entry["dnsRecord"]

    if not serial:
        raise BloodyError(f"No '@' entry found in '{zone_dn}' with '{ldap_filter}'")
    new_dnsrecord = dns.Record()
    new_dnsrecord.fromDict(
        data, dnstype, ttl, rank, serial, preference, port, priority, weight
    )

    if not record_dn:
        record_dn = f"DC={name},{zone_dn}"
        record_attr = {
            "objectClass": ["top", "dnsNode"],
            "dnsRecord": new_dnsrecord.getData(),
            "dNSTombstoned": False,
        }
        conn.ldap.bloodyadd(record_dn, attributes=record_attr)
        LOG.info(f"[+] {name} has been successfully added")
        return

    new_dnsrecord_list.append(new_dnsrecord.getData())
    print(new_dnsrecord_list)
    conn.ldap.bloodymodify(
        record_dn, {"dnsRecord": [(Change.REPLACE.value, new_dnsrecord_list)]}
    )
    LOG.info(f"[+] {name} has been successfully updated")

    This function adds a new DNS record into an AD environment.

    :param name: name of the dnsNode object (hostname) which will contain the new record
    :param data: DNS record data, for most record types this will be the destination hostname or IP address, for TXT records this can be used for text
    :param dnstype: DNS record type
    :param zone: DNS zone
    :param ttl: DNS record TTL, time in seconds the record stays in DNS caches, must be low if you want to propagate record updates quickly
    :param preference: DNS MX record preference, must be lower than the concurrent records to be chosen
    :param port: listening port of the service in a DNS SRV record
    :param priority: priority of a DNS SRV record against concurrent, must be lower to be chosen, if identical to others, highest weight will be chosen
    :param weight: weight of a DNS SRV record against concurrent, must be higher with the lowest priority to be chosen
    :param forest: if set, registers dns record in forest instead of domain
    
bloodyAD/cli_modules/add.py