/* This is a sybase proxy/sniffer. It sits between a sybase (posing as a sybase server) and a sybase server. It records requests and logs some statistics. */ #include #include #include #include #include #include #include #include #include #include #include #include "tdslib.h" using namespace std; extern DEBUG_KEY D_SRVMSG; extern DEBUG_KEY D_CLIMSG; enum CLIENT_TYPE{ TYPE_NULL, TYPE_CONTROL, TYPE_CLIENT, TYPE_SERVER }; struct SNIFF_CLI_INFO: public ARRAY_OBJ{ long long start; // Start of the query string sql; // Current query SNIFF_CLI_INFO(){ start = 0; } }; struct SNIFF_SRV_INFO: public ARRAY_OBJ{ SNIFF_CLI_INFO *cli; STREAMP_BUF buf; SNIFF_SRV_INFO(SNIFF_CLI_INFO *n){ cli = n; } }; int main (int argc, char *argv[]) { glocal const char *bind = NULL; glocal const char *port = "4101"; glocal const char *control = "/var/run/tdssniff.sock"; glocal const char *user = "nobody"; glocal const char *sybaseserver = NULL; glocal const char *serverport = "4101"; glocal const char *logsession = NULL; glocal const char *logerror = NULL; glocal const char *logsql = NULL; glocal const char *logdata = NULL; glocal bool daemon = false; glocal const char *pidfile = "/var/run/tdssniff.pid"; glocal int ret = -1; glocal.ret = (argc,argv); setproginfo ("tdssniff",VERSION,"Sybase/proxy sniffer\n"); setarg ('b',"bind","Bind on this IP",glocal.bind,false); setarg ('p',"sybaseport","Listen on this port for sybase client",glocal.port,false); setarg (' ',"control","Unix socket port to conrol and monitor this program",glocal.control,false); setarg ('S',"sybaseserver","Sybase server",glocal.sybaseserver,true); setarg ('P',"serverport","Sybase server port",glocal.serverport,false); setgrouparg ("Misc."); setarg ('d',"daemon","Run in background",glocal.daemon,false); setarg ('u',"user","Run as this user",glocal.user,false); setarg (' ',"pidfile","PID file",glocal.pidfile,false); setgrouparg ("Log files"); setarg (' ',"logsession","File holding sessions stats",glocal.logsession,false); setarg (' ',"logerror","File holding errors",glocal.logerror,false); setarg (' ',"logsql","File holding all SQL requests",glocal.logsql,false); setarg (' ',"logdata","File holding all SQL results",glocal.logdata,false); glocal FILE_LOG flog; glocal.flog.fsession = glocal.flog.open("log session",glocal.logsession); glocal.flog.ferror = glocal.flog.open("log error",glocal.logerror); glocal.flog.fsql = glocal.flog.open("log sql",glocal.logsql); glocal.flog.fdata = glocal.flog.open("log data",glocal.logdata); int ret = ("tdssniff",glocal.bind,glocal.port,glocal.control,glocal.user,glocal.daemon,glocal.pidfile); int ret = 0; if (words.size() == 1 && words[0] == "fflush"){ if (glocal.flog.fsession != NULL) fflush (glocal.flog.fsession); if (glocal.flog.ferror != NULL) fflush( glocal.flog.ferror); if (glocal.flog.fsql != NULL) fflush(glocal.flog.fsql); if (glocal.flog.fdata != NULL) fflush (glocal.flog.fdata); }else if (words.size() == 1 && words[0] == "closedatalog"){ if (glocal.flog.fdata != NULL){ fclose (glocal.flog.fdata); glocal.flog.fdata = NULL; } }else if (words.size() == 2 && words[0] == "opendatalog"){ if (glocal.flog.fdata != NULL) fclose (glocal.flog.fdata); glocal.flog.fdata = glocal.flog.open("log data",words[1].c_str()); }else if (words.size() == 1 && words[0] == "debugon"){ debug_seton(); }else if (words.size() == 1 && words[0] == "debugoff"){ debug_setoff(); }else if (words.size() == 2 && words[0] == "debugfile"){ debug_setfdebug (words[1].c_str()); }else{ ret = -1; } return ret; int fd = cmdsock_connect (glocal.sybaseserver,glocal.serverport,1,1); if (fd == -1){ tlmp_error ("Can't connect to sybase server %s (%s)\n",glocal.sybaseserver,strerror(errno)); endclient = true; }else{ SNIFF_CLI_INFO *cli = new SNIFF_CLI_INFO; info.data = cli; SNIFF_SRV_INFO *n = new SNIFF_SRV_INFO(cli); link(fd,n); } s->sendto (to_fd,buf,len); tdslib_debug (D_CLIMSG,id,login,"LOGIN\n"); SNIFF_CLI_INFO *n = (SNIFF_CLI_INFO*)info.data; n->start = tdslib_getnow(); n->sql = sql; tdslib_debug (D_CLIMSG,id,login,"SQL %s\n",sql); if (glocal.flog.fdata != NULL){ fprintf (glocal.flog.fdata,"SQL: %d ",id); while (*sql != '\0'){ char car = *sql++; if (car == '\n'){ fputc (';',glocal.flog.fdata); car=' '; } fputc (car,glocal.flog.fdata); } fputc ('\n',glocal.flog.fdata); } glocal SNIFF_SRV_INFO *n = (SNIFF_SRV_INFO*)info.data; glocal unsigned id = id; glocal TDS_LOGIN *login = &login; glocal BULK_RECORDS *brecs = &brecs; char buf[10000]; int len = read(server_fd,buf,sizeof(buf)); if (len <= 0){ endclient = true; }else{ copy (s,server_fd,client_fd,id,login,buf,len,info); (glocal.n->buf,buf,len); bool error = false; int used = tdslib_process ((const char *)buf,len,error); if (error){ debug_printf (D_SRVMSG,"ERROR len=%d used=%d error=%d\n",len,used,error); char tmp[100]; snprintf (tmp,sizeof(tmp)-1,"error=%d",error); tdslib_logerr (glocal.flog.ferror,glocal.id,*glocal.login,tmp,glocal.n->cli->sql.c_str(),NULL); }else if (used > 0){ const char *ptb = (const char *)buf; int numrows; int status = tdslib_parseres ((const char *)buf,used,numrows,glocal.id,*glocal.login,*glocal.brecs,glocal.flog.fdata); tdslib_logsql (glocal.flog.fsql,glocal.id,*glocal.login,glocal.n->cli->start,numrows,glocal.n->cli->sql.c_str()); tdslib_debug (D_SRVMSG,glocal.id,*glocal.login,"type=%d len=%d used=%d error=%d numrows=%d status=%d\n" ,ptb[0],len,used,error,numrows,status); } return used; } return ret; printf ("Server ending\n"); return glocal.ret; }