epp

package module
v0.0.0-...-3d0e729 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2019 License: MIT Imports: 21 Imported by: 0

README

EPP Go - Extensible Provisioning Protocol Server and Client

This is an implementation of how to handle EPP requests concurrently, both as a client and as a server. The main focus lays implementing types that may be used both as a client and as a server. These types should be easy to use and support all the allowed ways of setting up name spaces, attributes and tags. With the types implemented the initial focus will be to ensure a complete server implementation may be created. Since this is registry specific there will probably only be minor helpers and wrappers.

NOTE

This is a work in progress and a long way from completed. This repository is created to allow collaborations and inspire other people. This probject is a private project and an experiment to work with XSD files and XML with Go.

Types

A big motivation behind this project is to define all the available EPP types and even some extensions. This is so that even if you don't use this server or client you should be able to use the types to marshal or unmarshal your XML to your desired system.

There are a lot of knowns problems with this, especially since EPP is so heavily dependent on namespaces. This issue in the golang/go project summarize the most common issues with namespaces, aliases and attributes.

The way this is handled in this project is to first define all types as an outer tag for each part with the RFC namespace defined. The code then uses go-libxml to figure out where the namespaces should be, adds an alias and xmlns tag and then uses the aliases on all the child elements.

Sadly, this does not solve the issue that the XML should be able to be unmarshalled to the defined types despite the namespace or alias. To handle this a codegen binary is bundled in this project which can generate a copy of all types without the namespace.

Example usage and installment.

$ go install ./cmd/type-generator/...
$ type-generator
Generated file: contact_auto_generated.go
Generated file: domain_auto_generated.go
Generated file: host_auto_generated.go
...

To generate XML to be used for a client, use the specified type for this.

domainInfo := types.DomainInfoType{
    Info: types.DomainInfo{
        Name: types.DomainInfoName{
            Name:  "example.se",
            Hosts: types.DomainHostsAll,
        },
    },
}

bytes, err := Encode(
    domainInfo,
    ClientXMLAttributes(),
)

if err != nil {
    panic(err)
}

The above code will generate the following XML.

<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <info>
      <domain:info xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xmlns="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name hosts="all">example.se</domain:name>
      </domain:info>
    </info>
  </command>
</epp>

To unmarshal already created XML no matter the namespace or alias, use the auto genrated types. The XML listed above could be unmarshaled like this.

request := DomainInfoTypeIn{}

if err := xml.Unmarshal(inData, &request); err != nil {
    panic(err)
}

fmt.Println(request.Info.Name.Name) // Prints `example.se`

Client

To quickly get up and running and support testing of the server the repository contains a set of real world examples of EPP commands foudn in xml/commands.

Inside the example folder there's a client utilizing a few of the types and all of the read/writering confirming to EPP RFC. This client reads from STDIN so it's just to copy and paste any of the example XML file contents to test changes.

References

XSD files

All XSD schemas can be found att IANA web page. XSD files from this repository linked below.

EPP RFC
TLD specific (.SE)

Development and testing

XML files are linted with xmllint.

To validate XML libxml2 (bindings for Go) is used. This package requires you to install the libxml2 C libraries.

Installation macOS

Since macOS 10.14 brew won't link packages and libraries bundlede with macOS. This includes libxml2 and it's header files.

$ brew install libxml2

$ PKG_CONFIG_PATH="/usr/local/opt/libxml2/lib/pkgconfig" \
    go get github.com/lestrrat-go/libxml2/...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClientXMLAttributes

func ClientXMLAttributes() []xml.Attr

ClientXMLAttributes defines the default attributes in the client request.

func CreateErrorResponse

func CreateErrorResponse(code ResultCode, reason string) types.Response

CreateErrorResponse will create a response with a given code, message and value which may be marshalled to XML and pass to WriteMessage to write a proper EPP response to the socket.

func Encode

func Encode(data interface{}, xmlAttributes []xml.Attr) ([]byte, error)

Encode will take a type that can be marshalled to XML, add the EPP staring tag for all registered namespaces and return the XML as a byte slice.

func ReadMessage

func ReadMessage(conn net.Conn) ([]byte, error)

ReadMessage reads one full message from r.

func ServerXMLAttributes

func ServerXMLAttributes() []xml.Attr

ServerXMLAttributes defines the default attributes from the server response.

func WriteMessage

func WriteMessage(conn net.Conn, data []byte) error

WriteMessage writes data to w with the correct header.

Types

type Client

type Client struct {
	// TLSConfig holds the TLS configuration that will be used when connecting
	// to an EPP server.
	TLSConfig *tls.Config
	// contains filtered or unexported fields
}

Client represents an EPP client.

func (*Client) Connect

func (c *Client) Connect(server string) ([]byte, error)

Connect will connect to the server passed as argument.

func (*Client) Login

func (c *Client) Login(username, password string) ([]byte, error)

Login will perform a login to an EPP server.

func (*Client) Send

func (c *Client) Send(data []byte) ([]byte, error)

Send will send data to the server.

type GreetFunc

type GreetFunc func(*Session) ([]byte, error)

GreetFunc represents a function handling a greeting for the EPP server.

type HandlerFunc

type HandlerFunc func(*Session, []byte) ([]byte, error)

HandlerFunc represents a function for an EPP message.

type Mux

type Mux struct {
	// contains filtered or unexported fields
}

Mux can be used to route different EPP messages to different handlers, depending on the message content.

m := Mux{}

m.AddNamespaceAlias("urn:ietf:params:xml:ns:domain-1.0", "domain")

m.AddHandler("hello", handleHello)
m.AddHandler("command/login", handleLogin)
m.AddHandler("command/check/urn:ietf:params:xml:ns:contact-1.0", handleCheckContact)
m.AddHandler("command/check/domain", handleCheckDomain)

func NewMux

func NewMux() *Mux

NewMux will create and return a new Mux.

func (*Mux) AddHandler

func (m *Mux) AddHandler(path string, handler HandlerFunc)

AddHandler will add a handler for the specified route. Routes are defined almost like xpath.

func (*Mux) AddNamespaceAlias

func (m *Mux) AddNamespaceAlias(ns, alias string)

AddNamespaceAlias will add an alias for the specified namespace. After the alias is added it can be used in routing. Multiple namespaces can be added to the same alias.

m.AddNamespaceAlias("urn:ietf:params:xml:ns:contact-1.0", "host-and-contact")
m.AddNamespaceAlias("urn:ietf:params:xml:ns:host-1.0", "host-and-contact")

func (*Mux) Handle

func (m *Mux) Handle(s *Session, d []byte) ([]byte, error)

Handle will handle an incoming message and route it to the correct handler. Pass the function to Server to use the Mux.

type ResultCode

type ResultCode int

ResultCode represents a result code from the EPP server.

const (
	EppOk                         ResultCode = 1000
	EppOkPending                  ResultCode = 1001
	EppOkNoMessages               ResultCode = 1300
	EppOkMessages                 ResultCode = 1301
	EppOkBye                      ResultCode = 1500
	EppUnknownCommand             ResultCode = 2000
	EppSyntaxError                ResultCode = 2001
	EppUseError                   ResultCode = 2002
	EppMissingParam               ResultCode = 2003
	EppParamRangeError            ResultCode = 2004
	EppParamSyntaxError           ResultCode = 2005
	EppUnimplementedVersion       ResultCode = 2100
	EppUnimplementedCommand       ResultCode = 2101
	EppUnimplementedOption        ResultCode = 2102
	EppUnimplementedExtension     ResultCode = 2103
	EppBillingFailure             ResultCode = 2104
	EppNotRenewable               ResultCode = 2105
	EppNotTransferrable           ResultCode = 2106
	EppAuthenticationError        ResultCode = 2200
	EppAuthorisationError         ResultCode = 2201
	EppInvalidAuthInfo            ResultCode = 2202
	EppObjectPendingTransfer      ResultCode = 2300
	EppObjectNotPendingTransfer   ResultCode = 2301
	EppObjectExists               ResultCode = 2302
	EppObjectDoesNotExist         ResultCode = 2303
	EppStatusProhibitsOp          ResultCode = 2304
	EppAssocProhibitsOp           ResultCode = 2305
	EppParamPolicyError           ResultCode = 2306
	EppUnimplementedObjectService ResultCode = 2307
	EppDataMgmtPolicyViolation    ResultCode = 2308
	EppCommandFailed              ResultCode = 2400
	EppCommandFailedBye           ResultCode = 2500
	EppAuthFailedBye              ResultCode = 2501
	EppSessionLimitExceededBye    ResultCode = 2502
)

EPP constant types represents EPP result codes. For reference, see RFC5730 section 3, "Result Codes".

func (ResultCode) Code

func (rs ResultCode) Code() int

Code returns the integer code for the result code.

func (ResultCode) IsBye

func (rs ResultCode) IsBye() bool

IsBye returns true if the result code is a connection management result code which should terminate the connection.

func (ResultCode) Message

func (rs ResultCode) Message() string

Message returns the message to be embedded along the code.

type Server

type Server struct {
	// Addr is the address to use when listening to incomming TCP connections.
	// This should be set to ':700' to access incomming traffic on any interface
	// for the default EPP port 700.
	Addr string

	// OnStarteds holds a list of functions that will be executed after the
	// server has been started.
	OnStarteds []func()

	// SessionConfig holds the configuration to use for eachsession created.
	SessionConfig SessionConfig

	// TLSConfig is the server TLS config with configuration such as
	// certificates, client auth etcetera.
	TLSConfig *tls.Config

	// Sessions will contain all the currently active sessions.
	Sessions map[string]*Session
	// contains filtered or unexported fields
}

Server represents the server handling requests.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe will start the epp server.

func (*Server) Serve

func (s *Server) Serve(l *net.TCPListener) error

Serve will serve connections by listening on l.

func (*Server) Stop

func (s *Server) Stop()

Stop will close the channel making no new regquests being processed and then drain all ongoing requests til they're done.

type Session

type Session struct {
	// ConnectionState holds the state of the TLS connection initiated while
	// doing the handshake with the server.
	ConnectionState func() tls.ConnectionState

	// SessionID is a unique ID to use to identify a specific session.
	SessionID string

	// Se configurables details in SessionConfig
	IdleTimeout    time.Duration
	SessionTimeout time.Duration
	// contains filtered or unexported fields
}

Session is an active connection to the EPP server.

func NewSession

func NewSession(conn *tls.Conn, cfg SessionConfig) *Session

NewSession will create a new Session.

func (*Session) Close

func (s *Session) Close() error

Close will tell the session to close.

type SessionConfig

type SessionConfig struct {
	// IdleTimeout is the maximum timeout to idle on the server before being
	// disconnected. Each time traffic is sent to the server the idle ticker is
	// reset and a new duration of IdleTimeout is allowed.
	IdleTimeout time.Duration

	// SessionTimeout is the max duration allowed for a single session. If a
	// client has been connected when this limit is reach it will be
	// disconnedted after the current command being processed has finished.
	SessionTimeout time.Duration

	// greeting holds the function that will generate the XML printed while
	// greeting clients connection to the server.
	Greeting GreetFunc

	// handler holds a function that will receive each request to the server.
	Handler HandlerFunc

	// validator is a type that implements the validator interface. The
	// validator interface should be able to validate XML against an XSD schema
	// (or any other way). If the validator is a non nil value all incomming
	// *and* outgoing data will be passed through the validator. Type
	// implementing this interface using libxml2 bindings is available in the
	// library.
	Validator Validator

	// OnCommands is a list of functions that will be executed on each command.
	// This is the place to put external code to handle after each command.
	OnCommands []func(sess *Session)
}

SessionConfig represent the configuration passed to each new session being created.

type Validator

type Validator interface {
	Validate(xml []byte) error
	Free()
}

Validator represents the interface to validate XML.

type XMLValidator

type XMLValidator struct {
	Schema *xsd.Schema
}

XMLValidator represents a validator holding the XSD schema to calidate against.

func NewValidator

func NewValidator(rootXSD string) (*XMLValidator, error)

NewValidator creates a new validator.

func (*XMLValidator) Free

func (v *XMLValidator) Free()

Free frees the XSD C struct.

func (*XMLValidator) Validate

func (v *XMLValidator) Validate(xml []byte) error

Validate will validate XML towards the XSD schema.

Directories

Path Synopsis
cmd
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL