/* * Copyright (c) 2002, Hai Huang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * o Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * o Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * o Neither the name of the Beijing LyangTech Corp Ltd. nor the names of * its contributors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #define MAX_PRINT 80 #define MAX_LINE 16 #define MAX_DEVICE 16 #define MAX_DEV_NAME_LEN 64 #define MAX_SESSION 64 #define MAX_RING_BUFFER 16384 // an ether frame struct _ether_frame { u_char e_dest[6]; u_char e_sour[6]; u_char e_type[2]; u_char ip_ver; u_char ip_type; u_char ip_len[2]; u_char ip_id[2]; u_char ip_flag_off[2]; u_char ip_ttl; u_char ip_proto; u_char ip_chk[2]; u_char ip_sour[4]; u_char ip_dest[4]; u_char tcp_sour_port[2]; u_char tcp_dest_port[2]; u_char tcp_seq[4]; u_char tcp_ack[4]; u_char tcp_len_rev_flag[2]; u_char tcp_window[2]; u_char tcp_chk[2]; u_char tcp_urgent[2]; u_char tcp_data[1]; }; // a MSN session struct _msn_sess { u_char ip_local[4]; u_char ip_remote[4]; u_short port_remote; u_short port_local; char ring_buf[MAX_RING_BUFFER]; int start, end; char login[64]; }; #ifdef WIN2000 unsigned short _all_device[MAX_DEVICE][MAX_DEV_NAME_LEN]; #else unsigned char _all_device[MAX_DEVICE][MAX_DEV_NAME_LEN]; #endif struct _msn_sess* _all_sess[MAX_SESSION]; int _n_sess; void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *); void usage(); /* look up all available devices, return device name in _all_device, which is a global variable. return the number of device found. only work on win98 and later system. note that in win2000 and later system the device name is returned in wide-char form, which is equavilent to unsigned short */ int LookUpDev(); /* print all device name storen in global variable _all_device, ndev is the number of device */ void PrintDev(int ndev); /* print out a ether frame */ void PrintFrame(struct _ether_frame *pfrm); /* process msn message */ void proc_msn_msg(u_char local_ip[4], u_char remote_ip[4], u_short local_port, u_short remote_port, char *pdata, char dir, int data_len); void debug_msg(u_char local_ip[4], u_char remote_ip[4], u_short local_port, u_short remote_port, char *pdata, char dir, int data_len); void display_xml_msg(char *pc, char *pbuf); int main(int argc, char **argv) { pcap_t *fp; char error[PCAP_ERRBUF_SIZE]; int n; int ndev = 0; _n_sess = 0; if ( (n=LookUpDev(_all_device)) == -1 ) { printf("Cannot find any available device\n"); exit(0); } if ( argc > 1 ) ndev = atoi(argv[1]); else { PrintDev(n); exit(0); } // select a device and open live on it, in this machine _all_device[1] is // the one which we can capture packet if ( (fp= pcap_open_live((char*)_all_device[ndev], 1600, 1, 20, error) ) == NULL) { fprintf(stderr,"\nError opening adapter\n"); return 0; } while(1) pcap_dispatch(fp, 100, dispatcher_handler, NULL); return 0; } int LookUpDev() { char ebuf[PCAP_ERRBUF_SIZE]; int i,j,n; #ifdef WIN2000 unsigned short *device; #else unsigned char *device; #endif #ifdef WIN2000 device=(unsigned short*)pcap_lookupdev(ebuf); #else device=(unsigned char*)pcap_lookupdev(ebuf); #endif if (device == NULL) return -1; i=0; n=0; j=0; while(device[i]!=0||device[i+1]!=0) { if(device[i]==0) { _all_device[n][j]=device[i]; n++; j=0; } else { _all_device[n][j++]=device[i]; } if(device[i+1]==0) { _all_device[n][j]=device[i+1]; n++; j=0; } else { _all_device[n][j++]=device[i+1]; } i+=2; } _all_device[n][j]=0; n++; return n; } void PrintDev(int ndev) { int i,j; for ( i=0;i %d.%d.%d.%d:%d\n", pfrm->ip_sour[0], pfrm->ip_sour[1], pfrm->ip_sour[2], pfrm->ip_sour[3], pfrm->tcp_sour_port[0]*256 + pfrm->tcp_sour_port[1], pfrm->ip_dest[0], pfrm->ip_dest[1], pfrm->ip_dest[2], pfrm->ip_dest[3], pfrm->tcp_dest_port[0]*256 + pfrm->tcp_dest_port[1] ); printf("%s\n", pfrm->tcp_data); printf("\n"); } void dispatcher_handler(u_char *temp1, const struct pcap_pkthdr *header, const u_char *pkt_data) { u_int i=0; struct _ether_frame *pfrm; u_char msn_port[2]={0x07, 0x47}; u_short sour_port, dest_port; int len; pfrm = (struct _ether_frame*) pkt_data; if ( pfrm->e_type[0] == 0x08 && pfrm->ip_proto == 0x06 ) { // a tcp packet if ( memcmp(pfrm->tcp_sour_port, msn_port, 2) == 0 ) { // a message from msn server to client sour_port = pfrm->tcp_sour_port[0] * 256 + pfrm->tcp_sour_port[1]; dest_port = pfrm->tcp_dest_port[0] * 256 + pfrm->tcp_dest_port[1]; len = pfrm->ip_len[0] * 256 + pfrm->ip_len[1]; len -= 30; proc_msn_msg(pfrm->ip_dest, pfrm->ip_sour, dest_port, sour_port, pfrm->tcp_data, 'D', len); } else if ( memcmp(pfrm->tcp_dest_port, msn_port, 2) == 0 ) { // a message from client to msn server sour_port = pfrm->tcp_sour_port[0] * 256 + pfrm->tcp_sour_port[1]; dest_port = pfrm->tcp_dest_port[0] * 256 + pfrm->tcp_dest_port[1]; len = pfrm->ip_len[0] * 256 + pfrm->ip_len[1]; len -= 30; proc_msn_msg(pfrm->ip_sour, pfrm->ip_dest, sour_port, dest_port, pfrm->tcp_data, 'U', len); } } } void proc_msn_msg(u_char local_ip[4], u_char remote_ip[4], u_short local_port, u_short remote_port, char *pdata, char dir, int data_len) { // msn has many commands, in this version, we only support the following // commands: // // command direction description // BYE D tell client another user close the session // CAL U initial a session // CHG U change the user's status // FLN D tell client another user logoff // ILN D tell client another user login // JOI D tell client another user join a session // MSG U/D send message // NLN D tell client another user change status // OUT U/D close session // USR D login // // for more information, please refer to the MSN protocol char buf[1600]; char msgbuf[1600]; char *pc, *pstart; char substate[128]; char userhandler[128]; char friendlyname[128]; char filename[256]; FILE *pf; sprintf(filename, "log/%d-%d-%d-%d_%d", local_ip[0], local_ip[1], local_ip[2], local_ip[3], local_port); strncpy(buf, pdata, data_len); buf[data_len] = 0; if (strncmp(pdata, "BYE", 3) == 0) { // BYE D tell client another user close the session if ( dir == 'D' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pc = strchr(((char*)buf)+4, '\r'); if ( pc != NULL ) { *pc = 0; } printf("%s leave the session\n", buf+4); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "%s leave the session\n", buf+4); fclose(pf); } } } else if (strncmp(pdata, "CAL", 3) == 0) { // CAL U initial a session if ( dir == 'U' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pc = strchr(buf+4, ' '); pc++; pstart = pc; pc = strchr(pc, '\r'); if ( pc != NULL ) { *pc = 0; } printf("invited %s into the session\n", pstart); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf,"invited %s into the session\n", pstart); fclose(pf); } } } else if (strncmp(pdata, "CHG", 3) == 0) { // CHG U change the user's status if ( dir == 'U' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pc = strchr(buf+4, ' '); pc++; pstart = pc; pc = strchr(pc, '\r'); if ( pc != NULL ) { *pc = 0; } printf("change status to %s\n", pstart); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "change status to %s\n", pstart); fclose(pf); } } } else if (strncmp(pdata, "FLN", 3) == 0) { // FLN D tell client another user logoff if ( dir == 'D' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pc = strchr(buf+4, '\r'); if ( pc != NULL ) { *pc = 0; } printf("%s logoff\n", buf+4); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "%s logoff\n", buf+4); fclose(pf); } } } else if (strncmp(pdata, "ILN", 3) == 0) { // ILN D tell client another user login if ( dir == 'D' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pc = strchr(buf+4, ' '); pc++; pstart = pc; pc = strchr(pstart, ' '); *pc = 0; strcpy(substate, pstart); pc++; pstart = pc; pc = strchr(pstart, ' '); *pc = 0; strcpy(userhandler, pstart); pc++; pstart = pc; pc = strchr(pstart, '\r'); if ( pc!=NULL ) *pc = 0; strcpy(friendlyname, pstart); printf("%s status:%s friendlyname:%s login\n", userhandler, substate, friendlyname); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "%s status:%s friendlyname:%s login\n", userhandler, substate, friendlyname); fclose(pf); } } } else if (strncmp(pdata, "JOI", 3) == 0) { // JOI D tell client another user join a session if ( dir == 'D' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pc = strchr(buf+4, ' '); *pc = 0; strcpy(userhandler, buf+4); pc++; pstart = pc; pc = strchr(pstart, '\r'); if ( pc != NULL ) *pc = 0; strcpy(friendlyname, pstart); printf("%s firendlyname:%s join session\n", userhandler, friendlyname); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "%s firendlyname:%s join session\n", userhandler, friendlyname); fclose(pf); } } } else if (strncmp(pdata, "MSG", 3) == 0) { // MSG U/D send message if (strstr(buf, "Content-Type: text/plain") != NULL) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); if ( dir == 'U' ) { // upload message pc = strchr(buf+4,' '); pc++; printf("send out the following message\n", pc); display_xml_msg(pc, msgbuf); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "send out the following message\n", pc); fprintf(pf, "%s\n", msgbuf); fclose(pf); } } else { // download message pc = strchr(buf+4, ' '); *pc = 0; strcpy(userhandler, buf+4); pc++; pstart = pc; pc = strchr(pstart, ' '); if ( pc != NULL ) *pc = 0; strcpy(friendlyname, pstart); pc++; printf("%s friendlyname:%s send the following message\n", userhandler, friendlyname); display_xml_msg(pc, msgbuf); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "%s friendlyname:%s send the following message\n", userhandler, friendlyname); fprintf(pf, "%s\n", msgbuf); fclose(pf); } } } } else if (strncmp(pdata, "NLN", 3) == 0) { // NLN D tell client another user change status if ( dir == 'D' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pstart = buf + 4; pc = strchr(pstart, ' '); *pc = 0; strcpy(substate, pstart); pc++; pstart = pc; pc = strchr(pstart, ' '); *pc = 0; strcpy(userhandler, pstart); pc++; pstart = pc; pc = strchr(pstart, '\r'); if ( pc!=NULL ) *pc = 0; strcpy(friendlyname, pstart); printf("%s friendlyname:%s change to status %s\n", userhandler, friendlyname, substate); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "%s friendlyname:%s change to status %s\n", userhandler, friendlyname, substate); fclose(pf); } } } else if (strncmp(pdata, "OUT", 3) == 0) { // OUT U close session if ( dir == 'U' ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); printf("logoff\n"); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "logoff\n*****END*****\n\n"); fclose(pf); } } } else if (strncmp(pdata, "USR", 3) == 0) { // USR D login if ( dir == 'D' ) { if ( (pstart = strstr(buf," OK ")) != NULL ) { debug_msg(local_ip, remote_ip, local_port, remote_port, pdata, dir, data_len); pstart+=4; pc = strchr(pstart, ' '); *pc = 0; strcpy(userhandler, pstart); pc++; pstart = pc; pc = strchr(pstart, ' '); if ( pc!=NULL ) *pc = 0; pc = strchr(pstart, '\r'); if ( pc!=NULL ) *pc = 0; strcpy(friendlyname, pstart); printf("local %s friendlyname %s login\n", userhandler, friendlyname); if ( (pf = fopen(filename, "a") ) != NULL ) { fprintf(pf, "*****START*****\n"); fprintf(pf, "remote server:%d.%d.%d.%d:%d\n", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3], remote_port); fprintf(pf, "local %s friendlyname %s login\n", userhandler, friendlyname); fclose(pf); } } } } } void debug_msg(u_char local_ip[4], u_char remote_ip[4], u_short local_port, u_short remote_port, char *pdata, char dir, int data_len) { printf("local:%d.%d.%d.%d:%d remote:%d.%d.%d.%d:%d DIR:%c CMD:%c%c%c LEN:%d\n", local_ip[0], local_ip[1], local_ip[2], local_ip[3], local_port, remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3], remote_port, dir, pdata[0], pdata[1], pdata[2], data_len); } void display_xml_msg(char *pc, char *pbuf) { char *pstart, *pend; int len; if ( *pc == 'U' || *pc == 'N' || *pc == 'A' ) { pstart=strchr(pc, ' '); pstart++; } else { pstart = pc; } pend = strchr(pstart, '\r'); *pend = 0; len = atoi(pstart); pstart=pend+2; *(pstart+len)=0; printf("%s\n", pstart); sprintf(pbuf, "%s\n", pstart); } void usage() { printf("hear [ndev]\n"); printf("\tif no ndev specified, then it display all available devices.\n"); exit(0); }