C기반 IRC 봇

조회 수 3576 추천 수 0 2009.01.16 23:41:24

/*
        by hkpco (ChanAm Park)
        hkpco@korea.com
        http://hkpco.kr/

        irc bot program
*/

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdarg.h>

void pong( int sockfd, char *ping, int sz );
// keep-alive를 위한 함수

int irc_req( int sockfd, char *req, ... );
// request를 보내기 위한 함수

int main( int argc , char **argv )
{
        pid_t pid;
        int sockfd, port, status;
        struct sockaddr_in sock;
        struct hostent *host_st;
        char nickname[64] = {0x00,}, channel[64] = {0x00,};
        char rcv_data[4096] = {0x00,}, tmp_buf[64+2] = {0x00,}, *strp;

        if( argc < 5 ) {
                fprintf( stderr, "%s <irc_server> <port> <nickname> <channel>\n", argv[0] );
                return -1;
        }

        /******* 데몬 프로그램을 위한 세팅 *******/
        pid = fork();
        if( pid < 0 ) {
                perror( "fork()" );
                return -1;
        }
        else if( pid != 0 ) {
                return 0;
        }
        else {
                setsid();
        }
        /******* 세팅 끝 *******/

        printf( "\n\n<code by hkpco>\n\n" );

        /******* 접속 정보 저장 *******/
        port = atoi(argv[2]);

        strncpy( nickname, argv[3], sizeof(nickname) -1 );

        strncpy( channel, "#", 1 );
 strncat( channel, argv[4], sizeof(channel) -2 );
        /******* 접속 정보 저장 끝 *******/

        host_st = gethostbyname(argv[1]);
        if( host_st == NULL ) {
                perror( "gethostbyname()" );
                return -1;
        }

        if( argc > 2 )
                port = atoi(argv[2]);

        sockfd = socket( PF_INET, SOCK_STREAM, 0 );
        if( sockfd < 0 ) {
                perror( "socket()" );
                return -1;
        }

        bzero( sock.sin_zero, sizeof(sock.sin_zero) );
        sock.sin_family = AF_INET;
        sock.sin_port = htons(port);
        sock.sin_addr = *((struct in_addr *)host_st->h_addr);

        if( connect( sockfd, (struct sockaddr *)&sock, sizeof(sock) ) < 0 ) {
                perror( "connect()" );
                return -1;
        }

        /******* IRC 초기 접속 *******/
        irc_req( sockfd, "NICK", nickname, NULL );
        read( sockfd, rcv_data,  sizeof(rcv_data) );
        printf( "Response:\n%s\n\n", rcv_data );
        memset( rcv_data, 0x0, sizeof(rcv_data) );

        memset( tmp_buf , 0x0, sizeof(tmp_buf));
        snprintf( tmp_buf, sizeof(tmp_buf) -1, ":%s\n", nickname );

        irc_req( sockfd, "USER", nickname, ". ." , tmp_buf , NULL );
        read( sockfd, rcv_data, sizeof(rcv_data) );
        printf( "Response:\n%s\n\n", rcv_data );

        if( (strp = strstr( rcv_data, "PING" )) == NULL ) {
                memset( rcv_data, 0x0, sizeof(rcv_data) );
                read( sockfd, rcv_data, sizeof(rcv_data) );

                strp = strstr( rcv_data, "PING" );
                pong( sockfd, strp, strlen(strp) );
        }
        else {
                pong( sockfd, strp, strlen(strp) );
        }

        memset( rcv_data, 0x0, sizeof(rcv_data) );
        read( sockfd, rcv_data, sizeof(rcv_data) );
        printf( "Response:\n%s\n\n", rcv_data );

        irc_req( sockfd, "USERHOST", nickname, NULL );
        read( sockfd, rcv_data, sizeof(rcv_data) );
        printf( "Response:\n%s\n\n", rcv_data );
        memset( rcv_data, 0x0, sizeof(rcv_data) );

        irc_req( sockfd, "JOIN", channel, NULL );
        read( sockfd, rcv_data, sizeof(rcv_data) );
        printf( "Response:\n%s\n\n", rcv_data );
        memset( rcv_data, 0x0, sizeof(rcv_data) );
        irc_req( sockfd, "PRIVMSG", channel, ":상호의 봇이 접속했다예요.", NULL );
        read( sockfd, rcv_data, sizeof(rcv_data) );
        memset( rcv_data, 0x0, sizeof(rcv_data) );
        /******* IRC 초기 접속 끝 *******/

        /******* 메시지 처리 *******/
        while(1)
        {
                fd_set fds;
                int cmd_pps[2];
                pid_t cmd_prcs;
                char cmd_buf[1024] = {0x00,}, buf_snd[2048] = {0x00,};;
                char buf[1024] = {0x00,}, *p;

                FD_ZERO(&fds);
                FD_SET( sockfd, &fds );

                if( (select( sockfd +1, &fds, (fd_set *)NULL, (fd_set *)NULL, (struct timeval*)NULL )) < 0 ) {
                        perror( "select()" );
                        return -1;
                }

                if( FD_ISSET( sockfd, &fds ) ) {
                        read( sockfd, buf, sizeof(buf) -1 );

                        if( (p = strstr( buf, "PING" )) ) {
                                pong( sockfd, p, strlen(p) );
                        }

                        else if( strstr( buf, "whoareyou?" ) ) {
                                if( pipe(cmd_pps) < 0 ) {
                                        perror( "pipe()" );
                                        continue;
                                }
                                // 자식 프로세스와의 통신을 위한 pipe 생성

                                if( (cmd_prcs = fork()) < 0 ) {
                                        perror( "fork()" );
                                        continue;
                                }

                                if( cmd_prcs == 0 ) {
                                        dup2( cmd_pps[1], 1 );
                                        dup2( cmd_pps[1], 2 );
                                        close(cmd_pps[0]);
                                        close(cmd_pps[1]);
                                        execl( "/usr/bin/id", "-a", NULL );
                                        // id 명령의 결과는 파이프를 통하여 전송됨

                                        return 0;
                                }
                                else {
                                        read( cmd_pps[0], cmd_buf, sizeof(cmd_buf) -1 );
                                        // 파이프를 통하여 자식 프로세스의 id 명령 결과를 수신

                                        snprintf( buf_snd, sizeof(buf_snd) -1, "PRIVMSG %s :%s\n", channel, cmd_buf );
                                        write( sockfd, buf_snd, strlen(buf_snd) );

                                        close(cmd_pps[0]);
                                        close(cmd_pps[1]);
                                }

                                waitpid( cmd_prcs, &status, 0 );
                        }
  // irc bot 종료 명령 체크
                        else if( strstr( buf, "!go_away" ) ) {
                                break;
                        }

                        memset( buf, 0x0, sizeof(buf) );
                        memset( cmd_buf, 0x0, sizeof(cmd_buf) );
                        memset( buf_snd, 0x0, sizeof(buf_snd) );
                }
        }
        /******* 메시지 처리 끝 *******/

        printf( "\n[-] EXIT\n" );
        close(sockfd);
        return 0;
}

void pong( int sockfd, char *ping, int sz )
{
        int cnt;
        char buffer[4096] = {0x00,};

        strncpy( buffer, ping, sz );
        memcpy( buffer, "PONG", 4 );

        for( cnt = 1 ; cnt < sz ; cnt++ )
        {
                if( buffer[cnt] == '\n' )
                        break;
        }

        write( sockfd, buffer, cnt );
        printf( "Request:\n" );
        write( 1, buffer, cnt );
        printf( "\n\n" );

}

int irc_req( int sockfd, char *req, ... )
{
        va_list v_arg;
        char buffer[4096] = {0x00,};
        char *ptr;

        strncpy( buffer, req, sizeof(buffer) -1 );

        va_start( v_arg, req );
        while( (ptr = va_arg( v_arg, char* )) != NULL )
        {
                strncat( buffer, " ", sizeof(buffer) -1 );
                strncat( buffer, ptr, sizeof(buffer) -1 );
        }

        strncat( buffer, "\n", sizeof(buffer) -1 );
        write( sockfd, buffer, strlen(buffer) );
        printf( "Request:\n%s\n\n", buffer );

        return 0;
}



hkpco님이 짜신겁니다...실제 컴파일하고 실행시켜보니 돌아가네요




댓글 '1'

123

2010.02.03 23:07:12
*.138.115.199

어떻게 만져야 .. ;;

문서 첨부 제한 : 0Byte/ 2.00MB
파일 제한 크기 : 2.00MB (허용 확장자 : *.*)
List of Articles
번호 제목 글쓴이 날짜 조회 수
5 1부터 n까지의 홀수의 합 윤상호 2009-05-14 3433
4 원하는 갯수의 피보나치수열 출력하기 윤상호 2009-02-21 3757
» C기반 IRC 봇 [1] 윤상호 2009-01-16 3576
2 웹에서 코딩하기.. imagefile [3] 윤상호 2008-11-24 3831
1 원하는 갯수의 # 출력프로그램 [2] 윤상호 2008-11-17 3614

 


XE Login

OpenID Login