Net::EPP::Simple(3pm)

πŸ“¦
version 0.28 Β· 4 versions
, in debian trixie, ubuntu resolute, ubuntu stonking

πŸ’– Net::EPP::Simple πŸ’–

okay so bestie, welcome to the user contributed perl documentation for Net::EPP::Simple, section 3pm β€” yes it's a perl module manual page and yes it's about to be your new fave 🫢


✨ NAME ✨

Net::EPP::Simple β€” a simple EPP client interface for the most common jobs. it does the boring stuff so you don't have to, periodt πŸ’…


🌸 SYNOPSIS 🌸

like, here's the whole vibe in one go:

#!/usr/bin/perl
use Net::EPP::Simple;
use strict;

my $epp = Net::EPP::Simple->new(
    host => 'epp.nic.tld',
    user => 'my-id',
    pass => 'my-password',
);

my $domain = 'example.tld';

if ($epp->check_domain($domain) == 1) {
    print "Domain is available\n" ;

} else {
    my $info = $epp->domain_info($domain);
    printf("Domain was registered on %s by %s\n", $info->{crDate}, $info->{crID});

}

look at that. clean. iconic. no cap 🌈


πŸ¦‹ DESCRIPTION πŸ¦‹

This module provides a high level interface to EPP. It hides all the boilerplate of connecting, logging in, building request frames and parsing response frames behind a simple, Perlish interface.

It is based on the Net::EPP::Client module and uses Net::EPP::Frame to build request frames.

so like. it's giving "we handle the paperwork, you handle the vibes" πŸ’–

πŸŽ€ CONSTRUCTOR πŸŽ€

my $epp = Net::EPP::Simple->new(%PARAMS);

The constructor accepts the following arguments:

  • "host" β€” identifies the EPP server to connect to. like, where are we going bestie πŸ“
  • "port" β€” specifies the port, which defaults to 700.
  • "user" and "pass" β€” parameters specify authentication information. your little login moment πŸ”
  • "newPW" β€” specifies a new password that is set during login. glow up your password, slay ✨
  • "login_security" β€” the login_security parameter can be used to force the use of the Login Security Extension (see RFC 8807 https://www.rfc-editor.org/rfc/rfc8807.html). Net::EPP::Simple will automatically use this extension if the server supports it, but clients may wish to force this behaviour to prevent downgrade attacks. πŸ›‘οΈ
fr fr, downgrade attacks are not the moment. force it if you're worried.
  • "appname" β€” the appname parameter can be used to specify the value of the "<app>" element in the Login Security extension (if used). Unless specified, the name and current version of Net::EPP::Simple will be used.
  • "timeout" β€” the timeout parameter controls how long the client waits for a response from the server before returning an error. the "how long do we wait before we start spiraling" setting 😭
  • "debug" β€” if debug is set, Net::EPP::Simple will output verbose debugging information on STDERR, including all frames sent to and received from the server. it literally tells you everything, no secrets πŸ’€
  • "reconnect" β€” reconnect can be used to disable automatic reconnection (it is enabled by default). Before sending a frame to the server, Net::EPP::Simple will send a "<hello>" to check that the connection is up, if not, it will try to reconnect, aborting after the nth time, where n is the value of reconnect (the default is 3).
  • "login" β€” login can be used to disable automatic logins. If you set it to 0, you can manually log in using the $epp->_login() method. main character energy: you do it yourself πŸ’…
  • "objects" β€” objects is a reference to an array of the EPP object namespace URIs that the client requires.
  • "stdobj" β€” stdobj is a flag saying the client only requires the standard EPP contact-1.0, domain-1.0, and host-1.0 namespaces.
  • If neither objects nor stdobj is specified then the client will echo the server's object namespace list. πŸͺž
  • "extensions" β€” extensions is a reference to an array of the EPP extension namespace URIs that the client requires.
  • "stdext" β€” stdext is a flag saying the client only requires the standard EPP secDNS-1.1 DNSSEC extension namespace.
  • If neither extensions nor stdext is specified then the client will echo the server's extension namespace list. πŸͺžβœ¨
  • "lang" β€” the lang parameter can be used to specify the language. The default is "en".

The constructor will establish a connection to the server and retrieve the greeting (which is available via $epp->greeting) and then send a "<login>" request.

If the login fails, the constructor will return undef and set $Net::EPP::Simple::Error and $Net::EPP::Simple::Code.

🚨 so like, if you get undef back, check those two variables before you panic. they're the receipts.

🌈 CLIENT AND SERVER SSL OPTIONS 🌈

RFC 5730 requires that all EPP instances must be protected using mutual, strong client-server authentication. In practice, this means that both client and server must present an SSL certificate, and that they must both verify the certificate of their peer.

mutual. strong. both sides showing up with their cert. it's giving healthy relationship πŸ’–

πŸ’œ SERVER CERTIFICATE VERIFICATION πŸ’œ

Net::EPP::Simple will verify the certificate presented by a server if the verify, and either ca_file or ca_path are passed to the constructor:

my $epp = Net::EPP::Simple->new(
    host    => 'epp.nic.tld',
    user    => 'my-id',
    pass    => 'my-password',
    verify  => 1,
    ca_file => '/etc/pki/tls/certs/ca-bundle.crt',
    ca_path => '/etc/pki/tls/certs',
);

Net::EPP::Simple will fail to connect to the server if the certificate is not valid.

You can disable SSL certificate verification by omitting the verify argument or setting it to undef. This is strongly discouraged, particularly in production environments.

😭 bestie NO. do not rawdog your TLS in prod. that's not the vibe, that's a vulnerability.

You may wish to use Mozilla::CA to provide a value for the ca_file parameter.

🧚 SSL CIPHER SELECTION 🧚

You can restrict the ciphers that you will use to connect to the server by passing a ciphers parameter to the constructor. This is a colon-separated list of cipher names and aliases. See http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS for further details. As an example, the following cipher list is suggested for clients who wish to ensure high-security connections to servers:

HIGH:!ADH:!MEDIUM:!LOW:!SSLv2:!EXP
πŸ’… picky about ciphers = iconic behaviour actually

⭐ CLIENT CERTIFICATES ⭐

If you are connecting to an EPP server which requires a client certificate, you can configure Net::EPP::Simple to use one as follows:

my $epp = Net::EPP::Simple->new(
    host        => 'epp.nic.tld',
    user        => 'my-id',
    pass        => 'my-password',
    key         => '/path/to/my.key',
    cert        => '/path/to/my.crt',
    passphrase  => 'foobar123',
);

key is the filename of the private key, cert is the filename of the certificate. If the private key is encrypted, the passphrase parameter will be used to decrypt it.

πŸ”‘ key = the private key file, cert = the cert file, passphrase = the lil password that unlocks the encrypted key. keep that passphrase safe, bestie πŸ™ˆ

πŸ“ AVAILABILITY CHECKS πŸ“

You can do a simple "<check>" request for an object like so:

my $result = $epp->check_domain($domain);

my $result = $epp->check_host($host);

my $result = $epp->check_contact($contact);

Each of these methods has the same profile. They will return one of the following:

  • undef in the case of an error (check $Net::EPP::Simple::Error and $Net::EPP::Simple::Code). 😭
  • 0 if the object is already provisioned. πŸ’€
  • 1 if the object is available. πŸŽ‰ slay, it's free

πŸ¦‹ RETRIEVING OBJECT INFORMATION πŸ¦‹

ok so sometimes you just gotta ask the server things, bestie. like, "hey what's the tea on this domain" and it tells you everything. that's what the info methods are for πŸ’…

🌸 DOMAIN OBJECTS 🌸

my $info = $epp->domain_info($domain, $authInfo, $follow);

This one builds an <info> frame, yeets it at the server, and then turns the response into a cute little hash ref. It's giving "I just want to know everything about you" energy fr fr.

if there's an error, this method returns undef β€” and then you go check $Net::EPP::Simple::Error and $Net::EPP::Simple::Code to find out what went wrong 😭

If $authInfo is defined, it gets sent to the server as per RFC 5731, Section 3.1.2. no cap.

If the $follow parameter is true, then Net::EPP::Simple will also go and fetch the relevant host and contact details for a domain. so instead of just handing you back an object name or ID for the domain's registrant, contact associations, DNS servers or subordinate hosts β€” the values get replaced with the return value from the appropriate host_info() or contact_info() command. unless there was an error, in which case the original object ID is used instead. she's thorough like that πŸ’–

πŸŽ€ HOST OBJECTS πŸŽ€

my $info = $epp->host_info($host);

Builds an <info> frame, sends it, parses the response into a simple hash ref. that's the whole vibe.

on error: returns undef, and you check $Net::EPP::Simple::Error and $Net::EPP::Simple::Code. same energy as above, bestie.

πŸ’œ CONTACT OBJECTS πŸ’œ

my $info = $epp->contact_info($contact, $authInfo, $roid);

Builds an <info> frame, sends it to the server, parses the response into a simple hash ref. iconic behavior honestly.

on error: undef again, and then $Net::EPP::Simple::Error and $Net::EPP::Simple::Code are your besties.

If $authInfo is defined, it will be sent to the server as per RFC RFC 5733, Section 3.1.2. (yes it literally says "RFC RFC" in the original, we don't edit, we just ✨report✨)

If the $roid parameter to host_info() is set, then the "roid" attribute will be set on the <authInfo> element. lowkey a niche feature but she's there 🫢

⭐ DOMAIN INFORMATION ⭐

the hash ref that domain_info() hands back will usually look something like this:

{
    'contacts' => {
        'admin' => 'contact-id' 'tech' => 'contact-id' 'billing' => 'contact-id'
    },
    'registrant' => 'contact-id',
    'clID'       => 'registrar-id',
    'roid'       => 'tld-12345',
    'status'     => ['ok'],
    'authInfo'   => 'abc-12345',
    'name'       => 'example.tld',
    'trDate'     => '2011-01-18T11:08:03.0Z',
    'ns'         => ['ns0.example.com', 'ns1.example.com',],
    'crDate'     => '2011-02-16T12:06:31.0Z',
    'exDate'     => '2011-02-16T12:06:31.0Z',
    'crID'       => 'registrar-id',
    'upDate'     => '2011-08-29T04:02:12.0Z',
    hosts        => ['ns0.example.tld', 'ns1.example.tld',],
}

Members of the "contacts" hash ref may be strings β€” or, if there are multiple associations of the same type, an anonymous array of strings. so like, one admin? string. three admins? array. she adapts πŸ’…

If the server uses the Host Attribute model instead of the Host Object model, then the "ns" member will look like this:

[
    {
        name  => 'ns0.example.com',
        addrs => [
            version => 'v4',
            addr    => '10.0.0.1',
        ],
    },
    {
        name  => 'ns1.example.com',
        addrs => [
            version => 'v4',
            addr    => '10.0.0.2',
        ],
    },
]

heads up: there may be multiple members in the "addrs" section, and the "version" attribute is optional. don't come for her about it πŸŽ€

🌈 HOST INFORMATION 🌈

the hash ref returned by host_info() will usually look something like this:

{
    'crDate' => '2011-09-17T15:38:56.0Z',
    'clID'   => 'registrar-id',
    'crID'   => 'registrar-id',
    'roid'   => 'tld-12345',
    'status' => ['linked', 'serverDeleteProhibited',],
    'name'   => 'ns0.example.tld',
    'addrs'  => [
        {
            'version' => 'v4',
            'addr'    => '10.0.0.1'
        }
    ]
}

Note that hosts may have multiple addresses, and that "version" is optional. periodt. πŸ‘‘

🧚 CONTACT INFORMATION 🧚

the hash ref returned by contact_info() will usually look something like this:

{
    'id'         => 'contact-id',
    'postalInfo' => {
        'int' => {
            'name' => 'John Doe',
            'org'  => 'Example Inc.',
            'addr' => {
                'street' => ['123 Example Dr.', 'Suite 100'],
                'city'   => 'Dulles',
                'sp'     => 'VA',
                'pc'     => '20116-6503',
                'cc'     => 'US',
            }}
    },
    'clID'   => 'registrar-id',
    'roid'   => 'CNIC-HA321983',
    'status' => ['linked', 'serverDeleteProhibited'],
    'voice'  => '+1.7035555555x1234',
    'fax'    => '+1.7035555556',
    'email'  => 'jdoe@example.com',
    'crDate' => '2011-09-23T03:51:29.0Z',
    'upDate' => '1999-11-30T00:00:00.0Z'
}

There may be up to two members of the "postalInfo" hash, corresponding to the "int" and "loc" internationalised and localised types. iykyk πŸ’–


πŸ”₯ OBJECT TRANSFERS πŸ”₯

The EPP <transfer> command suppots five different operations: query, request, cancel, approve, and reject. (yes, "suppots" β€” we report, we don't correct, that's just the original's little typo moment and we love her anyway πŸ™ˆ)

Net::EPP::Simple makes these available using the following methods:

# For domain objects:

$epp->domain_transfer_query($domain);
$epp->domain_transfer_cancel($domain);
$epp->domain_transfer_request($domain, $authInfo, $period);
$epp->domain_transfer_approve($domain);
$epp->domain_transfer_reject($domain);

# For contact objects:

$epp->contact_transfer_query($contact);
$epp->contact_transfer_cancel($contact);
$epp->contact_transfer_request($contact, $authInfo);
$epp->contact_transfer_approve($contact);
$epp->contact_transfer_reject($contact);

Most of these methods will just set the value of $Net::EPP::Simple::Code and return either true or false. simple. clean. no drama.

However β€” and this is the main character moment β€” the domain_transfer_request(), domain_transfer_query(), contact_transfer_request() and contact_transfer_query() methods will return a hash ref that looks like this:

{
    'name'     => 'example.tld',
    'reID'     => 'losing-registrar',
    'acDate'   => '2011-12-04T12:24:53.0Z',
    'acID'     => 'gaining-registrar',
    'reDate'   => '2011-11-29T12:24:53.0Z',
    'trStatus' => 'pending'
}

✨ CREATING OBJECTS ✨

The following methods can be used to create a new object at the server:

$epp->create_domain($domain);
$epp->create_host($host);
$epp->create_contact($contact);

The argument for these methods is a hash ref of the same format as that returned by the info methods above. which means cloning an existing object is genuinely as easy as this:

my $info = $epp->contact_info($contact);

# set a new contact ID to avoid clashing with the existing object
$info->{id} = $new_contact;

# randomize authInfo:
$info->{authInfo} = $random_string;

$epp->create_contact($info);

ate. no crumbs. πŸ’…

Net::EPP::Simple will ignore object properties that it does not recognise, and those properties (such as server-managed status codes) that clients are not permitted to set. she's got boundaries, and honestly? valid.

🌸 CREATING NEW DOMAINS 🌸

When creating a new domain object, you may also specify a "period" key, like so:

$epp->create_domain({
    'name'       => 'example.tld',
    'period'     => 2,
    'registrant' => 'contact-id',
    'contacts'   => {
        'tech'    => 'contact-id',
        'admin'   => 'contact-id',
        'billing' => 'contact-id',
    },
    'status' => ['clientTransferProhibited',],
    'ns'     => {'ns0.example.com', 'ns1.example.com',},

    # this will be ignored if the server does not support the TTL extension
    'ttl'    => {'NS' => 3600, 'DS' => 60},
});

The "period" key is assumed to be in years rather than months. Net::EPP::Simple assumes the registry uses the host object model rather than the host attribute model. important distinction bestie, don't forget it 🫢

πŸŽ€ CREATING HOSTS πŸŽ€

$epp->create_host({
    name  => 'ns1.example.tld',
    addrs => [
        {ip => '192.0.2.1', version => 'v4'},
        {ip => '192.0.2.2',  version => 'v4'},
    ],

    # this will be ignored if the server does not support the TTL extension
    'ttl' => {
        'A'    => 3600,
        'AAAA' => 900,
    }
});

look at her go, making hosts out of thin air ✨

✨ UPDATING OBJECTS ✨

Okay so bestie, when you wanna change something that already exists on the server, these are your girls:

$epp->update_domain($domain);
$epp->update_host($host);
$epp->update_contact($contact);

All three of them work exactly the same way, same profile, same energy. And they'll hand you back one of these:

  • undef when it went wrong (so go check $Net::EPP::Simple::Error and $Net::EPP::Simple::Code, she's not gonna tell you for free).
  • 1 if the server accepted the update request. πŸŽ‰

You might also wanna peek at $Net::EPP::Simple::Code to figure out if the response code was 1000 (OK) or 1001 (action pending). Both are technically a win, they're just wearing different outfits.


🌸 UPDATING DOMAINS 🌸

Use the update_domain($info) method to update a domain name, duh.

The $info argument should look like this:

{
    name => $domain,
    chg  => {
        registrant => $new_registrant_id,
        authInfo   => $new_domain_password,

        # this will be ignored if the server does not support the TTL extension
        ttl        => {'NS' => 3600, 'DS' => 60},
    },
    add => {

        ns       => [qw/ns1.example.com ns2.example.com/],
        contacts => {
            tech    => 'contact-id',
            billing => 'contact-id',
            admin   => 'contact-id',
        },

        # Status info, simple form:
        status => [qw/ clientUpdateProhibited clientHold /],

        # Status info may be in more detailed form:
        # status => {
        #    clientUpdateProbhibited  => 'Avoid accidental change',
        #    clientHold               => 'This domain is not delegated',
        # },
    },
    rem => {
        ns       => [...],
        contacts => {
            tech    => 'old_tech_id',
            billing => 'old_billing_id',
            admin   => 'old_admin_id',
        },
        status => [qw/ clientTransferProhibited ... /],
    },
}

And literally every field except name is optional. The bare minimum is the vibe. πŸ’…


πŸŽ€ UPDATING CONTACTS πŸŽ€

Use the update_contact(info) method to update a contact object, bestie.

The $info argument should look like this:

{
    id  => $contact_id,
    add => {
        status => [qw/ clientDeleteProhibited /],

        # OR
        # status => {
        #    clientDeleteProhibited  => 'Avoid accidental removal',
        # },
    },
    rem => {
        status => [qw/ clientUpdateProhibited /],
    },
    chg => {
        postalInfo => {
            int => {
                name => 'John Doe',
                org  => 'Example Inc.',
                addr => {
                    street => ['123 Example Dr.', 'Suite 100'],
                    city   => 'Dulles',
                    sp     => 'VA',
                    pc     => '20116-6503',
                    cc     => 'US',
                },
            },
        },
        voice    => '+1.7035555555x1234',
        fax      => '+1.7035555556',
        email    => 'jdoe@example.com',
        authInfo => 'new-contact-password',
    },
}

And again β€” every single field except id is optional. πŸ‘‘


πŸ¦‹ UPDATING HOSTS πŸ¦‹

Use the update_host($info) method to update a host object, obviously.

The $info argument should look like this:

{
    name => 'ns1.example.com',
    add  => {
        status => [qw/ clientDeleteProhibited /],

        # OR
        # status => {
        #    clientDeleteProhibited  => 'Avoid accidental removal',
        # },

        addrs => [{ip => '123.45.67.89', version => 'v4'}, {ip => '98.76.54.32', version => 'v4'},],
    },
    rem => {
        status => [qw/ clientUpdateProhibited /],
        addrs  => [{ip => '1.2.3.4', version => 'v4'}, {ip => '5.6.7.8', version => 'v4'},],
    },
    chg => {
        name => 'ns2.example.com',
        # this will be ignored if the server does not support the TTL extension
        ttl    => {NS => 3600, DS => 60},
    },
}

Every field except name is optional, periodt. ✨


πŸ’€ DELETING OBJECTS πŸ’€

When it's time to let her go, these are the methods:

$epp->delete_domain($domain);
$epp->delete_host($host);
$epp->delete_contact($contact);

Same deal as the updates β€” identical profile across all three. They return one of:

  • undef if something went wrong (again, go read $Net::EPP::Simple::Error and $Net::EPP::Simple::Code, they know what happened).
  • 1 if the server accepted the deletion request.

And yes, you may wanna check $Net::EPP::Simple::Code to see whether the response code was 1000 (OK) or 1001 (action pending). Same two codes, same "it's fine either way" energy.


πŸ”₯ DOMAIN RENEWAL πŸ”₯

You can extend the validity period of a domain object by issuing a renew_domain() command. Glow-up for your domain, honestly.

 my $result = $epp->renew_domain({
     name         => 'example.com',
     cur_exp_date => '2011-02-05',  # current expiration date
     period       => 2,             # prolongation period in years
 });

Return value is 1 on success and undef on error. And when it is an error, $Net::EPP::Simple::Error is holding the appropriate error message for you, like a bestie holding your bag. 🫢


🌈 MISCELLANEOUS METHODS 🌈

my $greeting = $epp->greeting;

This one returns a Net::EPP::Frame::Greeting object representing the greeting the server sent back. It's giving introduction, it's giving hello. πŸ‘‹

$epp->ping;

This checks that the connection is actually up by sending a <hello> to the server. Returns false if no response comes back. If she ghosts you, that's a no.


πŸ‘‘ OVERRIDDEN METHODS FROM Net::EPP::Client πŸ‘‘

Net::EPP::Simple overrides a few methods it inherited from Net::EPP::Client. Here's the rundown:

⭐ request()

Net::EPP::Simple overrides this method so it can automatically populate the <clTRID> element with a unique string. Then it passes the frame right back up to Net::EPP::Client. Teamwork, no cap.

⭐ get_frame()

Net::EPP::Simple overrides this method so it can catch timeouts and network errors. If one of those happens, it returns undef. She's got reflexes. 😭

$bool = $epp->server_has_object($xmlns);
$bool = $epp->server_has_extension($xmlns);

Both of these methods return a true value if the object/extension identified by $xmlns was present in the server's greeting.

$authenticated = $epp->authenticated;

Returns a boolean telling you whether Net::EPP::Simple has successfully authenticated with the server. iykyk. βœ…


πŸ“ PACKAGE VARIABLES πŸ“

πŸ’œ $Net::EPP::Simple::Error

This variable contains an english text message explaining the last error to occur. That could be because invalid parameters got passed to a method, a network error happened, or the server sent back an error response. She's the narrator of your worst moments.

πŸ’œ $Net::EPP::Simple::Message

This variable contains the text content of the <msg> element in the response frame for the last transaction. Like, the actual words the server said. πŸ“©

πŸ’œ $Net::EPP::Simple::Code

This variable contains the integer result code the server returned for the last transaction. A successful transaction will always return an error code of 1999 or lower, and an unsuccessful transaction will be 2011 or more. If there's an internal client error β€” invalid parameters passed to a method, or a network error β€” then this gets set to 2400 (COMMAND_FAILED). See Net::EPP::ResponseCodes for more information about these codes.

Heads up bestie: those numbers are not a vibe, they're a whole diagnostic system. 1999-and-under means good, 2011-and-over means bad, 2400 means it's on us, not the server. πŸ’€

This module is (c) 2008 - 2023 CentralNic Ltd and 2024 Gavin Brown. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


And that's the whole page, bestie!! πŸŽ€ This little masterpiece lives in perl v5.40.1 and was dated 2025-04-19 β€” so yeah, she's current, she's maintained, she ate. Go register something iconic. πŸ’…βœ¨

πŸ“¦ where this page comes from