From 1910f371735a7d60a30ec22c514ae2723ca45dd8 Mon Sep 17 00:00:00 2001 From: acidvegas Date: Tue, 3 Oct 2023 00:13:24 -0400 Subject: [PATCH] added glang example --- skelly.go | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 skelly.go diff --git a/skelly.go b/skelly.go new file mode 100644 index 0000000..7b2c91f --- /dev/null +++ b/skelly.go @@ -0,0 +1,176 @@ +package main + +import ( + "bufio" + "crypto/tls" + "flag" + "fmt" + "log" + "net" + "strconv" + "strings" + "time" +) + +var ( + server string + port string + useSSL bool + channel string + key string +) + +func init() { + flag.StringVar(&server, "server", "", "The IRC server address (e.g., 1.2.3.4)") + flag.StringVar(&port, "port", "6667", "The port of the IRC server (e.g., 6667)") + flag.BoolVar(&useSSL, "ssl", false, "Whether to use SSL or not") + flag.StringVar(&channel, "channel", "", "The IRC channel to join (e.g., #channelName)") + flag.StringVar(&key, "key", "", "The IRC channel key") + flag.Parse() +} + +const ( + nickname = "[dev]skelly" + username = "golang" + realname = "IRC Bot Skeleton in Golang" +) + +func checkArgs() { + if server == "" || channel == "" { + log.Fatal("Both server and channel arguments are required.") + } else if channel[0] != '#' { + channel = "#" + channel // Using # on the commandline requires escaping, lets just make it optional + } + num, err := strconv.Atoi(port) + if err != nil { + log.Fatal("Invalid port number.") + } else if num < 1 || num > 65535 { + log.Fatal("Port number must be between 1 and 65535.") + } +} + +func main() { + checkArgs() + + fullServer := fmt.Sprintf("%s:%s", server, port) + + var conn net.Conn + var err error + + if useSSL { + conn, err = tls.Dial("tcp", fullServer, &tls.Config{InsecureSkipVerify: true}) + } else { + conn, err = net.Dial("tcp", fullServer) + } + if err != nil { + log.Printf("Failed to connect: %v", err) + time.Sleep(15 * time.Second) + } + + messageChannel := make(chan string, 100) // for received IRC messages + sendChannel := make(chan string, 100) // for messages to send to the IRC server + quit := make(chan struct{}) + + timeoutDuration := 300 * time.Second + timeoutTimer := time.NewTimer(timeoutDuration) + + go func() { + reader := bufio.NewReader(conn) + for { + line, err := reader.ReadString('\n') + if err != nil { + log.Println("Error reading from server:", err) + conn.Close() + close(quit) + return + } + select { + case messageChannel <- line: + timeoutTimer.Reset(timeoutDuration) + case <-quit: + return + case <-timeoutTimer.C: + log.Println("No data received for 300 seconds. Reconnecting...") + conn.Close() + close(quit) + return + } + } + }() + + go func() { + for { + select { + case message := <-sendChannel: + data := []byte(message) + if len(data) > 510 { + data = data[:510] + } + _, err := conn.Write(append(data, '\r', '\n')) + if err != nil { + log.Println("Error writing to server:", err) + conn.Close() + close(quit) + return + } + case <-quit: + return + } + } + }() + + // Initial handshake + sendChannel <- fmt.Sprintf("NICK %s", nickname) + sendChannel <- fmt.Sprintf("USER %s 0 * :%s", username, realname) + + for { + dataHandler(<-messageChannel, sendChannel) + } +} + +func eventPrivate(nick, ident, msg string) { + fmt.Println("Private message from", nick, ":", msg) +} + +func eventMessage(nick, ident, channel, msg string) { + fmt.Println("Channel message from", nick, ":", msg) + if ident == "acidvegas!~stillfree@most.dangerous.motherfuck" { + args := strings.Split(msg, " ") + switch args[0] { + case "!masscan": + fmt.Println("The value is a") + case "!nmap": + fmt.Println("The value is b") + case "!httpx": + fmt.Println("The value is c") + case "!nuclei": + fmt.Println("The value is c") + default: + fmt.Println("Unknown value") + } + } +} + +func dataHandler(data string, sendChannel chan<- string) { + fmt.Println(data) + parts := strings.Split(data, " ") + + if parts[0] == "PING" { + sendChannel <- fmt.Sprintf("PONG %s", parts[1]) + } else if parts[1] == "001" { // RPL_WELCOME + time.Sleep(5 * time.Second) // JOIN channel delay after connection, required for many networks with flood protection / mitigation + sendChannel <- fmt.Sprintf("JOIN %s %s", channel, key) + } else if parts[1] == "KICK" { + return + } else if len(parts) > 3 && parts[1] == "PRIVMSG" { + nick := strings.Split(parts[0], "!")[0][1:] + ident := strings.Split(parts[0], ":")[1] + target := parts[2] + msg := strings.Join(parts[3:], " ")[1:] + if target == nickname { // Private Messages + eventPrivate(nick, ident, msg) + } else if target == channel { // Channel Messages + eventMessage(nick, ident, channel, msg) + } + } +}