NAME
Net::EPP::Server - A simple EPP server implementation.
VERSION
version 0.001
SYNOPSIS
use Net::EPP::Server;
use Net::EPP::ResponseCodes;
#
# these are the objects we want to support
#
my @OBJECTS = qw(domain host contact);
#
# these are the extensions we want to support
#
my @EXTENSIONS = qw(secDNS rgp loginSec allocationToken launch);
#
# You can pass any arguments supported by Net::Server::Proto::SSL, but
# by default the server will listen on localhost port 7000 using a
# self-signed certificate.
#
Net::EPP::Server->new->run(
#
# this defines callbacks that will be invoked when an EPP frame is
# received
#
handlers => {
hello => \&hello_handler,
login => \&login_handler,
check => \&check_handler,
info => \&info_handler,
create => \&create_handler,
# add more here
}
);
#
# The <hello> handler is special and just needs
# to return a hashref containing server metadata.
#
sub hello_handler {
return {
# this is the server ID and is optional, if not provided the system
# hostname will be used
svID => 'epp.example.com',
# this is optional
lang => [ qw(en fr de) ],
# these are arrayrefs of namespace URIs
objects => [
map { Net::EPP::Frame::ObjectSpec->xmlns($_) } @OBJECTS
],
extensions => [
map { Net::EPP::Frame::ObjectSpec->xmlns($_) } @EXTENSIONS
],
};
}
#
# All other handlers work the same. They are passed a hash of arguments and
# can return a simple result code, a result code and message, a
# XML::LibXML::Document object, or a result code and an array of
# XML::LibXML::Element objects.
#
sub login_handler {
my %args = @_;
my $frame = $args{'frame'};
my $clid = $frame->getElementsByTagName('clid')->item(0)->textContent;
my $pw = $frame->getElementsByTagName('pw')->item(0)->textContent;
if (!validate_credentials($clid, $pw)) {
return AUTHENTICATION_FAILED;
} else {
return OK;
}
}
INTRODUCTION
Net::EPP::Server
provides a high-level framework for developing Extensible Provisioning Protocol (EPP) servers.
It implements the TLS/TCP transport described in RFC 5734, and the EPP Server State Machine described in Section 2 of RFC 5730.
SERVER CONFIGURATION
Net::EPP::Server
inherits from Net::Server (specifically Net::Server::PreFork), and so the run()
method accepts all the parameters supported by that module, plus the following:
handlers
, which is a hashref which maps events (including EPP commands) to callback functions. See below for details.timeout
(optional), which is how long (in seconds) to wait for a client to send a command before dropping the connection. This parameter may be a decimal (e.g.3.14
) or an integer (e.g.42
). The default timeout is 30 seconds.client_ca_file
(optional), which is the location on disk of a file which can be use to validate client certificates. If this parameter is not provided, clients will not be required to use a certificate.xsd_file
(optional), which is the location on disk of an XSD file which should be used to validate all frames received from clients. This XSD file can include other XSD files using<import>
.
EVENT HANDLERS
You implement the business logic of your EPP server by specifying callbacks that are invoked for certain events. These come in two flavours: events and commands
.
frame_received
Called when a frame has been successfully parsed and validated, but before it has been processed. The input frame will be passed as the frame
argument.
response_prepared
Called when a response has been generated, but before it has been sent back to the client. The response will be passed as the response
argument, while the input frame will be passed as the frame
argument. It is not called for <hello>
and <logout>
commands.
session_closed
Net::EPP::Server
takes care of handling session management, but this event handler will be called once a <logout>
command has been successfully processed, but before the client connection has been closed. The session
argument will contain a hashref of the session (see below).
hello
The hello
event handler is called when a new client connects, or a <hello>
frame is received.
Unlike the other event handlers, this handler MUST respond with a hashref which contains the following entries:
svID
(OPTIONAL) - the server ID. If not provided, the system hostname will be used.lang
(OPTIONAL) - an arrayref containing language codes. It not provided,en
will be used as the only supported language.objects
(REQUIRED) - an arrayref of namespace URIs for
COMMAND HANDLERS
The standard EPP command repertoire is:
login
logout
poll
check
info
create
delete
renew
transfer
delete
A command handler may be specified for all of these commands except logout
, since Net::EPP::Server
handles this itself.
Since EPP allows the command repertoire to be extended (by omitting the <command>
element and using the <extension>
element only), Net::EPP::Server
also supports the other
event which will be called when processing such frames.
All command handlers receive a hash containing the following arguments:
$server
- the server.event
- the name of the command.frame
- an XML::LibXML::Document object representing the frame received from the client.session
- a hashref containing the session information.clTRID
- the value of the<clTRID>
element taken from the frame received from the client.svTRID
- a value suitable for inclusion in the<clTRID>
element of the response.
SESSION PARAMETERS
As mentioned above, the $args{session}
parameter is a hashref which contains information about the session. It contains the following:
session_id
- a unique session ID.remote_addr
- the client's remote IP address (IPv4 or IPv6).remote_port
- the client's remote port.clid
- the client ID used to log in.lang
- the language specified at login.objects
- the object URI(s) specified at login.lang
- the extension URI(s) specified at login.client_cert
- information about the client certificate (if any). This is a hashref which looks something like this:{ 'issuer' => $dnref, 'common_name' => 'example.com', 'subject' => $dnref, }
$dnref
is a hashref representing the Distinguished Name of the issuer or subject and looks like this:{ 'O' => 'Example Inc.', 'OU' => 'Registry Services', 'emailAddress' => 'registry@example.com', 'CN' => 'EPP Server Private CA', }
Other members, such as
C
(country),ST
(state/province), andL
(city) may also be present.
RETURN VALUES
Command handlers can return result information in four different ways that are explained below.
1. SIMPLE RESULT CODE
Command handlers can signal the result of a command by simply passing a single integer value. Net::EPP::ResponseCodes may be used to avoid literal integers.
Example:
sub delete_handler {
my %args = @_;
# business logic here
if ($success) {
return OK;
} else {
return COMMAND_FAILED;
}
}
Net::EPP::Server
will construct a standard EPP response frame using the result code and send it to the client.
2. RESULT CODE + MESSAGE
If the command handler returns two values, and the first is a valid result code, then the second can be a message. Example:
sub delete_handler {
my %args = @_;
# business logic here
if ($success) {
return (OK, 'object deleted');
} else {
return (COMMAND_FAILED, 'object not deleted');
}
}
Net::EPP::Server
will construct a standard EPP response frame using the result code and message, and send it to the client.
3. RESULT CODE + XML ELEMENTS
The command handler may return a result code followed by an array of between one and three XML::LibXML::Element objects, in any order, representing the <resData>
, <msgQ>
and <extension>
elements. Example:
sub delete_handler {
my %args = @_;
# business logic here
return (
OK,
$resData_element,
$msgQ_element,
$extension_element,
);
}
Net::EPP::Server
will construct a standard EPP response frame using the result code and supplied elements which will be imported and inserted into the appropriate positions, and send it to the client.
4. XML::LibXML::Document OBJECT
A return value that is a single XML::LibXML::Document object will be sent back to the client verbatim.
EXCEPTIONS
Net::EPP::Server
will catch any exceptions thrown by the command handler, will carp($@)
, and then send a 2400
result code back to the client.
UTILITY METHODS
generate_response(%args)
This method returns a XML::LibXML::Document object representing the response described by %args
, which should contain the following:
code
(OPTIONAL) - the result code. See Net::EPP::ResponseCodes. If not provided,1000
will be used.msg
- a human-readable error message. If not provided, the string"Command completed successfully."
will be used ifcode
is less than2000
, and"Command failed."
ifcode
is2000
or higher.resData
(OPTIONAL) - if defined, an empty<resData>
element will be added to the frame.clTRID
(OPTIONAL) - the client transaction ID.svTRID
(OPTIONAL) - the server's transaction ID.
Once created, it is straightforward to modify the object to add, remove or change its contents as needed.
generate_error(%args)
This method is identical to generate_response()
except the default value for the code
parameter is 2400
, indicating that the command failed for unspecified reasons.
generate_svTRID()
This method returns a unique string suitable for use in the <svTRID>
and similar elements.
parse_frame($xml)
Attempts to parse $xml
and returns a XML::LibXML::Document if successful.
is_valid($frame)
Returns a result code and optionally a message if $frame
cannot be validated against the XSD file provided in the xsd_file
parameter.
is_result_code($value)
Returns true if $value
is a recognised EPP result code.
AUTHOR
Gavin Brown <gavin.brown@icann.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2024 by Internet Corporation for Assigned Names and Number (ICANN).
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.