skeleton

- bot skeleton for irc
git clone git://git.acid.vegas/skeleton.git
Log | Files | Refs | Archive | README | LICENSE

commit 1910f371735a7d60a30ec22c514ae2723ca45dd8
parent a4efb1ad08120c1cc38dfbdd07288b996cb7f978
Author: acidvegas <acid.vegas@acid.vegas>
Date: Tue, 3 Oct 2023 00:13:24 -0400

added glang example

Diffstat:
Askelly.go | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

1 file changed, 176 insertions(+), 0 deletions(-)

diff --git a/skelly.go 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)
+		}
+	}
+}