Skip to content

Commit

Permalink
Iit
Browse files Browse the repository at this point in the history
  • Loading branch information
chukhajyan committed Nov 2, 2017
0 parents commit 5aaa0a1
Show file tree
Hide file tree
Showing 10 changed files with 456 additions and 0 deletions.
27 changes: 27 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Copyright (c) 2017, GlobalR LLC
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the <organization>.
4. Neither the name of the GlobalR LLC nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY GlobalR LLC ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL GlobalR LLC BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Unix whois service

This service implements the WHOIS protocol as described in [RFC 3912](https://tools.ietf.org/html/rfc3912). The protocol allows to query the Registry about registrable objects.

This module translates incoming WHOIS requests into PostgreSQL query and then translates their results back to outgoing WHOIS responses.

Each response contains the link to the web whois service site which can be used to win full information about domain owners and administrative contacts.

The unix whois service allows to query even ENUM domains, although these responses do not contain the link to the web whois because the rules of information disclosure that apply to ENUM domains are different from those of common domains.

The service is built on a [Golang](https://golang.org/).

Authors:
- [Khachatur Ashotyan](mailto:khachatur.ashotyan@gmail.com)
337 changes: 337 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
// Copyright 2017 GlobalR LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// ---------------------------------------------------------
// WHOIS server
// ---------------------------------------------------------
// Author Khachatur Ashtotyan <khachatur.ashotyan@gmail.com>

package main

import (
"net"
"time"
"strings"
"text/template"
"bytes"
"regexp"
"log"
)

const (
// Servers listen to requests on the well-known port number 43
port = ":43"
// Set maximum connection time (deadline)
maxConnTime = 10 * time.Second
// Set maximum request length
maxReqLength = 64
)
var (
// Initializing help template
helpTemplate = InitHelp()
// Initializing top level error template
topErrTemplate = InitTopError()
// Initializing second level error template
secondErrTemplate = InitSecondError()
// Initializing syntax error template
syntaxErrTemplate = InitSyntaxError()
// Initializing domain name length error template
lenErrTemplate = InitLenError()
// Initializing success template
successTemplate = InitSuccess()
// Initializing success more template
successMoreTemplate = InitSuccessMore()
// Buffer initializing
tpl bytes.Buffer
)


func main() {
// Resolve TCP address
tcpAddr, err := net.ResolveTCPAddr("tcp4", port)
checkError(err)
// Initialize TCP Listener
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)

for {
conn, err := listener.Accept() // waits for the next call and returns a generic Conn

if err != nil {
continue
}

// Handle TCP queries
go handleClient(conn)
}
}

// Initialize Template by name and path
// @param {string} name name of template
// @param {string} path path of template
// @return {*template.Template} template representation pointer
func InitTemplate( name string, path string ) *template.Template {
t := template.New(name) // allocates a new, undefined template with the given name.

tmpl, err := t.ParseFiles(path) // parses the named files and associates the resulting templates with t
checkError(err)
tpl.Reset() // reset buffer story

return tmpl
}

// Initialize Help template
// @return {string} help template
func InitHelp() string {
helpTemplate := InitTemplate("Help", "./tmpl/help") // initialize template pointer

err := helpTemplate.ExecuteTemplate(&tpl,"help", nil) // write template with given parameter
checkError(err)

return tpl.String()
}

// Initialize Length Error template
// @return {string} length error template
func InitLenError() string {
helpTemplate := InitTemplate("Error", "./tmpl/error/len_error") // initialize template pointer

err := helpTemplate.ExecuteTemplate(&tpl,"len_error", nil) // write template with given parameter
checkError(err)

return tpl.String()
}

// Initialize Syntax Error template
// @return {string} syntax error template
func InitSyntaxError() string {
helpTemplate := InitTemplate("Error", "./tmpl/error/syntax_error") // initialize template pointer

err := helpTemplate.ExecuteTemplate(&tpl,"syntax_error", nil) // write template with given parameter
checkError(err)

return tpl.String()
}

// Initialize Top Level Error template
// @return {string} top level error template
func InitTopError() string {
helpTemplate := InitTemplate("Error", "./tmpl/error/top_level_error") // initialize template pointer

err := helpTemplate.ExecuteTemplate(&tpl,"top_level_error", nil) // write template with given parameter
checkError(err)

return tpl.String()
}

// Initialize Second Level Error template
// @return {string} second level error template
func InitSecondError() string {
helpTemplate := InitTemplate("Error", "./tmpl/error/second_level_error") // initialize template pointer

err := helpTemplate.ExecuteTemplate(&tpl,"second_level_error", nil) // write template with given parameter
checkError(err)

return tpl.String()
}

// Initialize Success Template for handling success queries
// @return {*template.Template} template representation pointer
func InitSuccess() *template.Template {
return InitTemplate("Success", "./tmpl/success/success")
}

// Initialize Success More Template for handling success queries
// @return {*template.Template} template representation pointer
func InitSuccessMore() *template.Template {
return InitTemplate("Success", "./tmpl/success/success_more")
}

// Handle Client WHOIS queries
// @param {net.Conn} conn generic stream-oriented network connection.
func handleClient(conn net.Conn) {
conn.SetReadDeadline(time.Now().Add(maxConnTime)) // set maximum connection time 10 second
request := make([]byte, maxReqLength) // set maximum request length to 128B to prevent flood based attacks
defer conn.Close() // close connection before exit
for {
readLen, err := conn.Read(request) // read client query

if err != nil {
logError(err)
break
}

if readLen == 0 {
break // connection already closed by client
} else {
req := strings.TrimSpace(string(request[:readLen])) // client query object

if req == "help" {
conn.Write([]byte(helpTemplate)) // client receive help
conn.Close()
} else {
if checkDomain(req, conn) { // check query correction
handleSuccess(req, conn) // all is correct send to client WHOIS data
}

}
}
}
}

// Check domain name correctness
// @param {string} domain generic stream-oriented network connection.
// @param {net.Conn} conn generic stream-oriented network connection.
// @return {bool} if all is OK. return true, if not receive specific error
func checkDomain(domain string, conn net.Conn) bool {
domain = strings.ToLower(domain) // domain name to lowercase
match, _ := regexp.MatchString(`^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$`, domain ) // check domain name correctness by regex

if ! match {
conn.Write([]byte(syntaxErrTemplate)) // client have syntax error
conn.Close()
} else {
domainParts := strings.Split(domain, ".") // check domain name parts

// check this domain name is belongs to us
if ( len(domainParts) == 2 && domainParts[1] == "ge" ) ||
( len(domainParts) == 3 && (
( domainParts[1] == "com" ||
domainParts[1] == "edu" ||
domainParts[1] == "gov" ||
domainParts[1] == "org" ||
domainParts[1] == "mil" ||
domainParts[1] == "net" ||
domainParts[1] == "pvt" ) && domainParts[2] == "ge" ) ) {
if len(domainParts[0]) < 2 {
conn.Write([]byte(lenErrTemplate)) // for finish check domain name length correctness
conn.Close()
}
return true
} else {
// send specific error by domain name
if len(domainParts) == 2 {
conn.Write([]byte(topErrTemplate)) // send top level error
conn.Close()
} else {
conn.Write([]byte(secondErrTemplate)) // send second level serror
conn.Close()
}
}
}

return true
}

type SuccessData struct {
DomainName string
Registrar string
Status string
Registrant Registrant
}

type Registrant struct {
Name string
Address1 string
Address2 string
ZIP string
Country string
}

type SuccessMoreData struct {
Administrative Administrative
Technical Technical
DNS []string
Registered string
Modified string
Expires string
}

type Administrative struct {
Name string
Address1 string
Address2 string
ZIP string
Country string
Email string
Phone string
}

type Technical struct {
Name string
Address1 string
Address2 string
ZIP string
Country string
Email string
Phone string
}

// TODO::Connect to database and send request
// If all is correct send to client success request
// @param {string} req client request (domain name)
// @param {net.Conn} generic stream-oriented network connection.
func handleSuccess(req string, conn net.Conn) {
tpl.Reset()
err := successTemplate.ExecuteTemplate(&tpl,"success", SuccessData{
DomainName: req,
Registrar: "RegNest.com (RegNest LLC)",
Status: "active, registrar locked",
Registrant: Registrant{
Name: "John Doe",
Address1: "123 6th St.",
Address2: "Melbourne, FL",
ZIP: "32904",
Country: "US",
},
} )
checkError(err)
conn.Write([]byte(tpl.String()))

tpl.Reset()
err = successMoreTemplate.ExecuteTemplate(&tpl,"success_more", SuccessMoreData{
Administrative: Administrative{
Name: "John Doe",
Address1: "123 6th St.",
Address2: "Melbourne, FL",
ZIP: "32904",
Country: "US",
Phone:"6503491051",
Email:"john@doe.ge",
},
Technical: Technical{
Name: "John Doe",
Address1: "123 6th St.",
Address2: "Melbourne, FL",
ZIP: "32904",
Country: "US",
Phone:"6503491051",
Email:"john@doe.ge",
},
DNS: []string{"coco.ns.cloudflare.com","todd.ns.cloudflare.com"},
Registered: "2004-12-28",
Modified: "2017-06-14",
Expires: "2022-12-28",
} )
checkError(err)
conn.Write([]byte(tpl.String()))
conn.Close()
}

// Fatal Error handling
// Log the message and turn off server
// @param {error} err error interface
func checkError(err error) {
if err != nil {
log.Fatalf("Fatal error: %s", err.Error())
}
}

// Warnings handling
// Log the server messages (for example, client closed connection)
// @param {error} err error interface
func logError(err error) {
if err != nil {
log.Printf("Warning: %s", err.Error())
}
}
3 changes: 3 additions & 0 deletions tmpl/error/len_error
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

This TLDs Domain Names must have minimum of 2 and a maximum of 63 characters

3 changes: 3 additions & 0 deletions tmpl/error/second_level_error
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

Wrong second level domain name in query

3 changes: 3 additions & 0 deletions tmpl/error/syntax_error
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

Syntax error or wrong char(s) in query

3 changes: 3 additions & 0 deletions tmpl/error/top_level_error
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

Wrong top level domain name in query

Loading

0 comments on commit 5aaa0a1

Please sign in to comment.