Så er mit værk færdigt!
Dette er en IRC bot, der placerer sig på vores IRC channel og holder fast i forbindelsen indtil den skal noget. Samtidig åbnes en socket, som er klar til at modtage data der skal skrives i chatten. Skide genialt, da dette kan bruges i samarbejde med en masse andre programmer, her bruger vi den så sammen med MyBB, så derfor har jeg kaldt den BB2IRC.
Det den gør er simpelt, når en besked bliver oprettet på forummet, sendes en besked til bottens åbne socket (INC_IP:INC_PORT).
Med PHP har jeg gjort dette med noget så simpelt som dette:
<?php
$msgtype = array("oprettet en tråd med titlen", "besvaret tråden");
$title = $_GET['title'];
$user = $_GET['user'];
$link = "http://shellsec.pw/showthread.php?tid=" . $_GET['tid'] . "&pid=" . $_GET['pid'] . "#pid" . $_GET['pid'];
$msg = $user . " har " . $msgtype[$_GET['type']] . " \"" . $title . "\"" . $INC_DELIM . $link;
$sockfd = fsockopen($INC_IP, $INC_PORT, $errno, $errstr, 120);
if(!$sockfd){
die();
}else{
fwrite($sockfd, $msg);
fclose($sockfd);
}
?>
Et eksempel på en besked oprettes således ved en query til serveren med denne querystring:
?user=Doctor%20Blue&type=0&title=[C++]%20IRC%20bot%20til%20overvågning%20af%20forum%20posts&tid=207&pid=
$INC_DELIM repræsenterer det tegn, der også sættes som konstanten INC_DELIM i botten, og er altså det tegn der indikerer en ny linje.
Output vil altså være:
Citer:Botnick: Doctor Blue har oprettet en tråd med titlen [C++] IRC bot til overvågning af forum posts
Botnick: http://shellsec.pw/showthread.php?tid=207&pid=#pid
og så har vi selve botten her:
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
using namespace std;
static const string IRC_IP = "208.64.123.83";
static const int IRC_PORT = 6667;
static const string NSNAME = "NickServ";
static const string NICKNAME = "Shellsec";
static const string NICKPASS = "";
static const string CHANNEL = "Shellsec";
static const string INC_IP = "127.0.0.1";
static const int INC_PORT = 6111;
static const string INC_DELIM = ";";
bool SetSocketBlockingEnabled(int fd, bool blocking)
{
if (fd < 0) return false;
#ifdef WIN32
unsigned long mode = blocking ? 0 : 1;
return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
#else
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return false;
flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
#endif
}
class IRC{
private:
int sockfd, n, listfd, clientfd;
char recvBuff[1024];
char listBuff[1024];
string sendBuff;
struct sockaddr_in irc_addr, list_addr;
public:
void send(string message){
sendBuff = message + "\r\n";
write(sockfd, sendBuff.c_str(), strlen(sendBuff.c_str()));
}
void open(string ip, int port){
cout << "Establishing connection\n";
memset(recvBuff, '0', sizeof(recvBuff));
memset(listBuff, '0', sizeof(listBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
cout << "Error: Could not create socket\n";
exit(1);
}
cout << "Creating socket for listening";
if((listfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
cout << "Error: Could not create listening socket\n";
exit(1);
}
if(inet_pton(AF_INET, ip.c_str(), &irc_addr.sin_addr) <= 0){
cout << "Error: Failed to read IP address\n";
exit(1);
}
if(inet_pton(AF_INET, INC_IP.c_str(), &list_addr.sin_addr) <= 0){
cout << "Error: Failed to read incoming IP address\n";
exit(1);
}
irc_addr.sin_family = AF_INET;
irc_addr.sin_port = htons(IRC_PORT);
list_addr.sin_family = AF_INET;
list_addr.sin_port = htons(INC_PORT);
if(connect(sockfd, (struct sockaddr *)&irc_addr,sizeof(irc_addr)) < 0){
cout << "Error: Could not connect to server\n";
exit(1);
}
cout << "Binding listener";
if(bind(listfd, (struct sockaddr *)&list_addr, sizeof(list_addr)) < 0){
cout << "Error: Failed to bind to listening IP";
exit(1);
}
cout << "Starting listener";
if(listen(listfd, 3) < 0){
cout << "Error: Failed to start listener";
exit(1);
}
}
void poolListener(){
struct sockaddr_in client_addr;
socklen_t clilen = sizeof client_addr;
stringstream stream;
string word;
SetSocketBlockingEnabled(listfd, false);
clientfd = accept(listfd, (struct sockaddr *)&client_addr, &clilen);
if(clientfd > 0){
cout << "Client connected, recieving message: ";
if((n = read(clientfd, listBuff, sizeof(listBuff) - 1)) > 0)
listBuff[n] = 0;
stringstream stream(listBuff);
while( getline(stream, word, ';') ){
cout << word << ";";
send("PRIVMSG #ShellSec :" + word);
}
cout << "\n";
}
}
string monitor(){
istringstream iss;
while(true){
poolListener();
if((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0)
recvBuff[n] = 0;
istringstream iss(recvBuff);
string streampart;
do{
iss >> streampart;
if(streampart == "Auth"){
send("NICK " + NICKNAME);
send("USER " + NICKNAME + " * * :" + NICKNAME);
}
if(streampart == "001"){
send("JOIN #" + CHANNEL);
if(NICKPASS != ""){
send("PRIVMSG " + NSNAME + " : IDENTIFY " + NICKPASS);
}
}
if(streampart == "PING"){
send("PONG");
cout << "\n>PONG\n";
}
if(streampart == "PRIVMSG"){
iss >> streampart;
if(streampart == "#ShellSec"){
iss >> streampart;
if(streampart == ":" + NICKNAME){
send("PRIVMSG #" + CHANNEL + " :Reporting for duty!");
}
}
}
}while(iss);
if(fputs(recvBuff, stdout) == EOF){
cout << "Error: Couldn't output to stdout";
}
if(n < 0){
cout << "Error: Read failed";
}
}
}
} conn;
int main() {
cout << "BB2IRC is starting...\n";
cout << "Made by Doctor Blue\n";
sleep(3);
conn.open(IRC_IP, IRC_PORT);
conn.monitor();
exit(EXIT_SUCCESS);
return 0;
}
Hele molevitten er cross-compatible, altså det funger på Linux og Windows, og i princippet burde det også virke på Mac, men jeg har ikke testet :)
Hyggehejsa, nyd mit arbejde når Morph får det op at køre :)