commit 1878aa76c6edb08d990ac267be5cd6cd6835a58f Author: caramel Date: Tue Aug 13 20:59:39 2024 -0600 Whois implementation speedrun Signed-off-by: caramel diff --git a/data/dns.fur.meta b/data/dns.fur.meta new file mode 100644 index 0000000..3b858d4 --- /dev/null +++ b/data/dns.fur.meta @@ -0,0 +1,4 @@ +DotFur Internal +7:46PM August 13th, 2024 +7:46PM August 13th, 2034 +ok \ No newline at end of file diff --git a/data/dot.fur.meta b/data/dot.fur.meta new file mode 100644 index 0000000..3b858d4 --- /dev/null +++ b/data/dot.fur.meta @@ -0,0 +1,4 @@ +DotFur Internal +7:46PM August 13th, 2024 +7:46PM August 13th, 2034 +ok \ No newline at end of file diff --git a/data/example.fur b/data/example.fur new file mode 100644 index 0000000..5ceb41e --- /dev/null +++ b/data/example.fur @@ -0,0 +1,41 @@ +---------------------------------------------------------------- +Hi! This is example.fur, a domain registered for use in +documentation, or when you need to use an example domain in +any conversation, text, or anywhere else! + +For example: When formatting a whois request on debian using +the APT `whois` package, you can specify a host with +`whois example.fur -h hostname`, which will send a whois req +to the server `hostname`. + +Because this domain is an example one, there's no ownership +information to return via WHOIS protocol, so instead we made +you a gay unicode cat, because everyone likes gay unicode cats. + +⠀⠀⠀⢰⠶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠶⠲⣄⠀ +⠀⠀⣠⡟⠀⠈⠙⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⡶⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠾⠋⠁⠀⠀⢽⡄ +⠀⠀⡿⠀⠀⠀⠀⠀⠉⠷⣄⣀⣤⠤⠤⠤⠤⢤⣷⡀⠙⢷⡄⠀⠀⠀⠀⣠⠞⠉⠀⠀⠀⠀⠀⠈⡇ +⠀⢰⡇⠀⠀⠀⠀⠀⠀⠀⠉⠳⣄⠀⠀⠀⠀⠀⠈⠁⠀⠀⠹⣦⠀⣠⡞⠁⠀⠀⠀⠀⠀⠀⠀⠀⡗ +⠀⣾⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣻⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣏ +⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡇ +⠀⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⠂ +⠀⢿⠀⠀⠀⠀⣤⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⣤⣤⣤⡀⠀⠀⠀⠀⠀⣸⠇⠀ +⠀⠘⣇⠀⠀⠀⠀⠉⠉⠛⠛⢿⣶⣦⠀⠀⠀⠀⠀⠀⢴⣾⣟⣛⡋⠋⠉⠉⠁⠀⠀⠀⠀⣴⠏⠀⠀ +⢀⣀⠙⢷⡄⠀⠀⣀⣤⣶⣾⠿⠋⠁⠀⢴⠶⠶⠄⠀⠀⠉⠙⠻⠿⣿⣷⣶⡄⠀⠀⡴⠾⠛⠛⣹⠇ +⢸⡍⠉⠉⠉⠀⠀⠈⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⣬⠷⣆⣠⡤⠄⢀⣤⠞⠁⠀ +⠈⠻⣆⡀⠶⢻⣇⡴⠖⠀⠀⠀⣴⡀⣀⡴⠚⠳⠦⣤⣤⠾⠀⠀⠀⠀⠀⠘⠟⠋⠀⠀⠀⢻⣄⠀⠀ +⠀⠀⣼⠃⠀⠀⠉⠁⠀⠀⠀⠀⠈⠉⢻⡆⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⠀⠀ +⠀⢠⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡀⠀⠀⢀⡇⠀⠀⠀⠀⠀⠀⠀⠀⣀⡿⠧⠿⠿⠟⠀⠀ +⠀⣾⡴⠖⠛⠳⢦⣿⣶⣄⣀⠀⠀⠀⠀⠘⢷⣀⠀⣸⠃⠀⠀⠀⣀⣀⣤⠶⠚⠉⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠈⢷⡀⠈⠻⠦⠀⠀⠀⠀⠉⠉⠁⠀⠀⠀⠀⠹⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⢀⡴⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⢠⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⡄⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠈⠉⠛⠛⢲⡗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡆⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠋⠀⠀⠀⠀⠀⠀⠀ + +.... You may need to make sure your whois client or terminal +support UTF-8 in order to see this gay unicode cat. + +Much love, +- .fur WHOIS Server~ \ No newline at end of file diff --git a/data/example.fur.meta b/data/example.fur.meta new file mode 100644 index 0000000..3b858d4 --- /dev/null +++ b/data/example.fur.meta @@ -0,0 +1,4 @@ +DotFur Internal +7:46PM August 13th, 2024 +7:46PM August 13th, 2034 +ok \ No newline at end of file diff --git a/data/nic.fur.meta b/data/nic.fur.meta new file mode 100644 index 0000000..3b858d4 --- /dev/null +++ b/data/nic.fur.meta @@ -0,0 +1,4 @@ +DotFur Internal +7:46PM August 13th, 2024 +7:46PM August 13th, 2034 +ok \ No newline at end of file diff --git a/data/whois.fur.meta b/data/whois.fur.meta new file mode 100644 index 0000000..3b858d4 --- /dev/null +++ b/data/whois.fur.meta @@ -0,0 +1,4 @@ +DotFur Internal +7:46PM August 13th, 2024 +7:46PM August 13th, 2034 +ok \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..02c3747 --- /dev/null +++ b/main.go @@ -0,0 +1,161 @@ +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) + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..f37055c --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +Domain WHOIS contents are stored in `data`, in a plaintext named with the domain `example.fur`, and an accompanying file `example.fur.meta` which contains the Registration date, Expiry date, EPP status, and registrar. \ No newline at end of file