Files
whois/main.go
2024-08-13 20:59:39 -06:00

162 lines
5.3 KiB
Go

package main
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"strings"
"time"
)
const (
port = "43"
whoisversion = "v0.01"
dataDir = "./data" // Directory where domain files are stored
crlf = "\r\n"
)
// Function to get metadata for a domain
func getDomainMetadata(domain string) (string, string, string, string, error) {
metaFilePath := fmt.Sprintf("%s/%s.meta", dataDir, domain)
file, err := os.Open(metaFilePath)
if err != nil {
return "", "", "", "", err
}
defer file.Close()
scanner := bufio.NewScanner(file)
var registrar, registrationDate, expirationDate, status string
if scanner.Scan() {
registrar = scanner.Text()
}
if scanner.Scan() {
registrationDate = scanner.Text()
}
if scanner.Scan() {
expirationDate = scanner.Text()
}
if scanner.Scan() {
status = scanner.Text()
}
if err := scanner.Err(); err != nil {
return "", "", "", "", err
}
return registrar, registrationDate, expirationDate, status, nil
}
func handleConnection(conn net.Conn) {
defer conn.Close()
// Get the client's IP address
clientIP := conn.RemoteAddr().String()
// Read the domain name from the client
reader := bufio.NewReader(conn)
request, err := reader.ReadString('\n')
if err != nil {
log.Println("Error reading from connection:", err)
return
}
// Clean up the request
domain := strings.TrimSpace(request)
// Get the current timestamp
timestamp := time.Now().Format(time.RFC3339)
// Check if the domain file exists
filePath := fmt.Sprintf("%s/%s", dataDir, domain)
domainInfo, err := ioutil.ReadFile(filePath)
if err != nil {
// Domain file not found, so check if metadata file exists
metaFilePath := fmt.Sprintf("%s/%s.meta", dataDir, domain)
if _, err := os.Stat(metaFilePath); err == nil {
// Metadata file exists but domain file doesn't
registrar, registrationDate, expirationDate, status, err := getDomainMetadata(domain)
if err != nil {
log.Println("Error reading metadata file:", err)
conn.Write([]byte("Error reading domain metadata" + crlf))
return
}
response := fmt.Sprintf(" __ __ ____ \n ____/ /____ / /_ / __/__ __ _____\n / __ // __ \\ / __/ / /_ / / / // ___/\n/ /_/ // /_/ // /_ _ / __// /_/ // / | \n\\__,_/ \\____/ \\__/(_)/_/ \\__,_//_/ | dot.fur WHOIS Server\n _ __ __ __ ____ ____ _____ | whois.fur | whois.dotfur.net\n| | / // / / // __ \\ / _// ___/ | Version: %s\n| | /| / // /_/ // / / / / / \\__ \\ |\n| |/ |/ // __ // /_/ /_/ / ___/ / \n|__/|__//_/ /_/ \\____//___/ /____/ \n \n", whoisversion)
response += fmt.Sprintf(
"Domain: %s%sOrigin IP: %s%sTimestamp: %s%sRegistrar: %s%sRegistration Date: %s%sExpiration Date: %s%sStatus: %s%sNo WHOIS Info to show%s",
domain, crlf,
clientIP, crlf,
timestamp, crlf,
registrar, crlf,
registrationDate, crlf,
expirationDate, crlf,
status, crlf,
crlf)
response += fmt.Sprintf("\n.fur WHOIS Server | https://git.fur/caramel/whois | Version: %s", whoisversion)
response += crlf
conn.Write([]byte(response))
} else {
// Both domain file and metadata file not found
log.Println("Domain and metadata file not found")
conn.Write([]byte("Domain not found" + crlf))
}
return
}
// Domain file found, get metadata for the domain
registrar, registrationDate, expirationDate, status, err := getDomainMetadata(domain)
if err != nil {
log.Println("Error reading metadata file:", err)
conn.Write([]byte("Error reading domain metadata" + crlf))
return
}
// Format the response with additional fields, origin IP, and timestamp
response := fmt.Sprintf(" __ __ ____ \n ____/ /____ / /_ / __/__ __ _____\n / __ // __ \\ / __/ / /_ / / / // ___/\n/ /_/ // /_/ // /_ _ / __// /_/ // / | \n\\__,_/ \\____/ \\__/(_)/_/ \\__,_//_/ | dot.fur WHOIS Server\n _ __ __ __ ____ ____ _____ | whois.fur | whois.dotfur.net\n| | / // / / // __ \\ / _// ___/ | Version: %s\n| | /| / // /_/ // / / / / / \\__ \\ |\n| |/ |/ // __ // /_/ /_/ / ___/ / \n|__/|__//_/ /_/ \\____//___/ /____/ \n \n", whoisversion)
response += fmt.Sprintf(
"Domain: %s%sOrigin IP: %s%sTimestamp: %s%sRegistrar: %s%sRegistration Date: %s%sExpiration Date: %s%sStatus: %s%s%s",
domain, crlf,
clientIP, crlf,
timestamp, crlf,
registrar, crlf,
registrationDate, crlf,
expirationDate, crlf,
status, crlf,
string(domainInfo))
// Add a final CRLF to signify the end of the response
response += fmt.Sprintf("\n.fur WHOIS Server | https://git.fur/caramel/whois | Version: %s", whoisversion)
response += crlf
// Send the response back to the client
conn.Write([]byte(response))
log.Printf("Served domain: %s to %s at %s\n", domain, clientIP, timestamp)
}
func main() {
// Start the TCP server
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatalf("Error starting server: %s", err)
}
defer listener.Close()
log.Printf("Whois server running on port %s\n", port)
for {
// Accept incoming connections
conn, err := listener.Accept()
if err != nil {
log.Println("Error accepting connection:", err)
continue
}
// Handle the connection in a new goroutine
go handleConnection(conn)
}
}