From: mid Date: Tue, 28 Dec 1999 05:47:03 +0000 (+0000) Subject: Added aimdump. X-Git-Tag: rel_0_99_2~188 X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/commitdiff_plain/fa684c5105e60318fd4f7c2f417e0ec0837cbc39 Added aimdump. --- diff --git a/utils/aimdump/Makefile b/utils/aimdump/Makefile new file mode 100644 index 0000000..21e3260 --- /dev/null +++ b/utils/aimdump/Makefile @@ -0,0 +1,16 @@ +include ../Makefile.dynamicrules +include $(LIBFAIM_LIB)/Makefile.rules + +LDFLAGS += -lpcap -lfaim + +EXEC_NAME = aimdump +EXEC_OBJECTS = \ + main.o \ + util.o \ + icbmparse.o + +all: $(EXEC_OBJECTS) + $(CC) $(CFLAGS) -o $(EXEC_NAME) $(EXEC_OBJECTS) $(LDFLAGS) + +clean: + rm -f $(EXEC_OBJECTS) $(EXEC_NAME) diff --git a/utils/aimdump/aimdump.h b/utils/aimdump/aimdump.h new file mode 100644 index 0000000..b35b5e9 --- /dev/null +++ b/utils/aimdump/aimdump.h @@ -0,0 +1,23 @@ +#ifndef __AIMDUMP_H__ +#define __AIMDUMP_H__ + +#include +#include +#include +#include "util.h" +#include +#include +#include + +/* + * These are in NETWORK (big-endian) BYTE ORDER!!! + */ +#define SAPLEN 3 /* the length of the SAP header */ +#define SAPHEADER {0xfc, 0xfc, 0x03} /* SAP header bytes */ +#define ETHERTYPE_INCOMING 0x0056 /* on data from the 8227 */ +#define ETHERTYPE_FOUND 0x003d /* on outgoing FOUND frames */ +#define ETHERTYPE_DATA 0x05dc /* on outgoing Data frames */ + +void parser_icbm_incoming(u_char *data, int len); + +#endif /* __AIMDUMP_H__ */ diff --git a/utils/aimdump/icbmparse.c b/utils/aimdump/icbmparse.c new file mode 100644 index 0000000..80c7702 --- /dev/null +++ b/utils/aimdump/icbmparse.c @@ -0,0 +1,190 @@ + + +#include + +void parser_icbm_incoming(u_char *data, int len) +{ + struct aim_userinfo_s userinfo; + u_int i = 0, j = 0, y = 0, z = 0; + char *msg = NULL; + u_int icbmflags = 0; + u_char cookie[8]; + int channel; + struct aim_tlvlist_t *tlvlist; + struct aim_tlv_t *msgblocktlv, *tmptlv; + u_char *msgblock; + u_short wastebits; + u_short flag1,flag2; + + memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); + + i = 0; + /* + * Read ICBM Cookie. And throw away. + */ + for (z=0; z<8; z++,i++) + cookie[z] = data[i]; + + /* + * Channel ID. + * + * Channel 0x0001 is the message channel. There are + * other channels for things called "rendevous" + * which represent chat and some of the other new + * features of AIM2/3/3.5. We only support + * standard messages; those on channel 0x0001. + */ + channel = aimutil_get16(data+i); + i += 2; + if (channel != 0x0001) + { + printf("faim: icbm: ICBM received on an unsupported channel. Ignoring.\n (chan = %04x)", channel); + return; + } + + /* + * Source screen name. + */ + memcpy(userinfo.sn, data+i+1, (int)data[i]); + userinfo.sn[(int)data[i]] = '\0'; + i += 1 + (int)data[i]; + + /* + * Unknown bits. + */ + wastebits = aimutil_get16(data+i); + i += 2; + wastebits = aimutil_get16(data+i); + i += 2; + + /* + * Read block of TLVs. All further data is derived + * from what is parsed here. + */ + tlvlist = aim_readtlvchain(data+i, len-i); + + /* + * Check Autoresponse status. If it is an autoresponse, + * it will contain a second type 0x0004 TLV, with zero length. + */ + if (aim_gettlv(tlvlist, 0x0004, 2)) + icbmflags |= AIM_IMFLAGS_AWAY; + + /* + * Check Ack Request status. + */ + if (aim_gettlv(tlvlist, 0x0003, 2)) + icbmflags |= AIM_IMFLAGS_ACK; + + /* + * Extract the various pieces of the userinfo struct. + */ + /* Class. */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0001, 1))) + userinfo.class = aimutil_get16(tmptlv->value); + /* Member-since date. */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0002, 1))) + { + /* If this is larger than 4, its probably the message block, skip */ + if (tmptlv->length <= 4) + userinfo.membersince = aimutil_get32(tmptlv->value); + } + /* On-since date */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0003, 1))) + userinfo.onlinesince = aimutil_get32(tmptlv->value); + /* Idle-time */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0004, 1))) + userinfo.idletime = aimutil_get16(tmptlv->value); + /* Session Length (AIM) */ + if ((tmptlv = aim_gettlv(tlvlist, 0x000f, 1))) + userinfo.sessionlen = aimutil_get16(tmptlv->value); + /* Session Length (AOL) */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0010, 1))) + userinfo.sessionlen = aimutil_get16(tmptlv->value); + + /* + * Message block. + * + * XXX: Will the msgblock always be the second 0x0002? + */ + msgblocktlv = aim_gettlv(tlvlist, 0x0002, 1); + if (!msgblocktlv) + { + printf("faim: icbm: major error! no message block TLV found!\n"); + aim_freetlvchain(&tlvlist); + } + + /* + * Extracting the message from the unknown cruft. + * + * This is a bit messy, and I'm not really qualified, + * even as the author, to comment on it. At least + * its not as bad as a while loop shooting into infinity. + * + * "Do you believe in magic?" + * + */ + msgblock = msgblocktlv->value; + j = 0; + + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + + y = aimutil_get16(msgblock+j); + j += 2; + for (z = 0; z < y; z++) + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + + /* + * Message string length, including flag words. + */ + i = aimutil_get16(msgblock+j); + j += 2; + + /* + * Flag words. + * + * Its rumored that these can kick in some funky + * 16bit-wide char stuff that used to really kill + * libfaim. Hopefully the latter is no longer true. + * + * Though someone should investiagte the former. + * + */ + flag1 = aimutil_get16(msgblock+j); + j += 2; + flag2 = aimutil_get16(msgblock+j); + j += 2; + + if (flag1 || flag2) + printf("faim: icbm: **warning: encoding flags are being used! {%04x, %04x}\n", flag1, flag2); + + /* + * Message string. + */ + i -= 4; + msg = (char *)malloc(i+1); + memcpy(msg, msgblock+j, i); + msg[i] = '\0'; + + /* + * Free up the TLV chain. + */ + aim_freetlvchain(&tlvlist); + + printf("ICBM:\n"); + printf("\tChannel:\t0x%04x\n", channel); + printf("\tSource:\t%s\n", userinfo.sn); + printf("\tICBM Flags:\t%s %s\n", + (icbmflags & AIM_IMFLAGS_AWAY)?"Away":"", + (icbmflags & AIM_IMFLAGS_ACK)?"Ack":""); + printf("\tEncoding Flags:\t{0x%02x, 0x%02x}\n", flag1, flag2); + printf("\tMessage:\n"); + printf("\t\t%s\n", msg); + + free(msg); + + return; +} diff --git a/utils/aimdump/main.c b/utils/aimdump/main.c new file mode 100644 index 0000000..fe9123b --- /dev/null +++ b/utils/aimdump/main.c @@ -0,0 +1,521 @@ +/* + * + * + * + * + */ + +#include "aimdump.h" + +#define IMAGEFILE "ibmboot.img" +#define DEVNAME "eth0" + +pcap_t *pd = NULL; + +static u_int8_t clientaddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0x0ff, 0xff}; /* loaded with client address */ +static u_int8_t multicastaddr[ETH_ALEN] = {0x03, 0x00, 0x02, 0x00, 0x00, 0x00}; + +pcap_t *open_pcap(char *device) +{ + pcap_t *pd = NULL; + char errbuf[PCAP_ERRBUF_SIZE]; + + if (device == NULL) + { + if ( (device = pcap_lookupdev(errbuf)) == NULL) + { + fprintf(stderr, "pcap_lookup: %s\n", errbuf); + return NULL; + } + } + + if ( (pd = pcap_open_live(device, 1500, 1, 500, errbuf)) == NULL) + { + fprintf(stderr, "pcap_open_live: %s\n", errbuf); + return NULL; + } + + return pd; +} + +void showstats(pcap_t *pd) +{ + struct pcap_stat stats; + + fflush(stdout); + printf("\n"); + + if (pcap_stats(pd, &stats) < 0) + { + fprintf(stderr, "cap_stats: %s\n", pcap_geterr(pd)); + return; + } + printf("%d packets recieved by filter\n", stats.ps_recv); + printf("%d packets dropped by kernel\n", stats.ps_drop); + + return; +} + +char *next_pcap(pcap_t *pd, struct pcap_pkthdr *hdr) +{ + char *ptr; + + while ( (ptr = (char *)pcap_next(pd, hdr)) == NULL) + ; + + return ptr; +} + +/* + * This covers stage two of the fast-path, after we've determined its + * an incoming RPL frame. + * + */ +void processframe(struct pcap_pkthdr *hdr, char *pkt, char *device) +{ + static struct ether_header *ether = NULL; +#if 0 + u_int8_t cmpaddr[ETH_ALEN] = {0x10, 0x00, 0x5a, 0x3b, 0x0b, 0x72}; + u_int8_t cmpaddr[ETH_ALEN] = {0x03, 0x00, 0x02, 0x00, 0x00, 0x00}; +#endif + if ( (!hdr) || (!pkt) ) + return; + + ether = (struct ether_header *)pkt; + + if (hdr->caplen != hdr->len) + fprintf(stderr, "rpld: caplen/len mismatch\n"); + + + if ((clientaddr[0] != 0xff) && cmpether(clientaddr, ether->ether_shost)) + { + int command = 0x0000; + fprintf(stderr, "rpld: got a %sframe from our client\n", (cmpether(multicastaddr, ether->ether_dhost))?"multicast ":""); + command = (pkt[19]<<8)+pkt[20]; + fprintf(stderr, "rpld: command: 0x%04x\n", command); + +#if 0 + if (command == 0x0001) /* FIND */ + send_found(link, device); + else if (command == 0x0010) /* Send File Request */ + send_file(link, device); +#endif + + } + else if (cmpether(multicastaddr, ether->ether_dhost)) + { + if (clientaddr[0] != 0xff) + { + /* we're already servicing another client */ + fprintf(stderr, "rpld: not adding client %s\n", printether(ether->ether_shost)); + return; + } + else + { + /* we're not busy yet, lets process this one */ + fprintf(stderr, "rpld: adding client %s\n", printether(ether->ether_shost)); + memcpy(clientaddr, ether->ether_shost, ETH_ALEN); + } + } +#if 0 + else if (cmpether(clientaddr, ether->ether_dhost)) + { + fprintf(stderr, "rpld: showing outgoing frame...\n"); + printframe(hdr, pkt); + } +#endif + else + fprintf(stderr, "rpld: uncaught case\n"); + +#if 0 + if (cmpether(cmpaddr, ether->ether_shost) || + cmpether(cmpaddr, ether->ether_dhost) ) + { + printf("\n\n%s > ", printether(ether->ether_shost)); + printf("%s\n", printether(ether->ether_dhost)); + + if (pkt[20] != 0x01) + printf("\aSTATUS CHANGE\n"); + + //pkt = 18; /* skip over ethernet headers */ + for (i=0;icaplen;i+=2) + { + if (!((i)%8)) + printf("\n\t"); + printf("%02x%02x ", pkt[i] &0xff, pkt[i+1] & 0xff); + } + } + else + return; +#endif +} + +void sigint(int sig) +{ + fflush(stdout); + showstats(pd); + exit(0); + return; +} + +struct flaphdr { + __u8 start; + __u8 channel; + __u16 seqnum; + __u16 len; +}; + +struct snachdr { + u_short family; + u_short subtype; + u_char flags[2]; + u_long id; +}; + +struct subtype_s { + char *name; + void (*parser)(u_char *data, int len); +}; + +struct snactype_s { + char *family; + struct subtype_s subtypes[21]; +} snactypes[16] = { + {"Invalid", { + {NULL, NULL}} + }, + {"General", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Client Ready", NULL}, + {"Server Ready", NULL}, + {"Service Request", NULL}, + {"Redirect", NULL}, + {"Rate Information Request", NULL}, + {"Rate Information", NULL}, + {"Rate Information Ack", NULL}, + {"Rate Information Change", NULL}, + {"Server Pause", NULL}, + {"Server Resume", NULL}, + {"Request Personal User Information", NULL}, + {"Personal User Information", NULL}, + {"Evil Notification", NULL}, + {"Migration notice", NULL}, + {"Message of the Day", NULL}, + {"Set Privacy Flags", NULL}, + {"Well Known URL", NULL}, + {"NOP", NULL}, + {NULL, NULL}} + }, + {"Location", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Request Rights", NULL}, + {"Rights Information", NULL}, + {"Set user information", NULL}, + {"Request User Information", NULL}, + {"User Information", NULL}, + {"Watcher Sub Request", NULL}, + {"Watcher Notification", NULL}, + {NULL, NULL}} + }, + {"Buddy List Management", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Request Rights", NULL}, + {"Rights Information", NULL}, + {"Add Buddy", NULL}, + {"Remove Buddy", NULL}, + {"Watcher List Query", NULL}, + {"Watcher List Response", NULL}, + {"Watcher SubRequest", NULL}, + {"Watcher Notification", NULL}, + {"Reject Notification", NULL}, + {"Oncoming Buddy", NULL}, + {"Offgoing Buddy", NULL}, + {NULL, NULL}}, + }, + {"Messeging", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Add ICBM Parameter", NULL}, + {"Remove ICBM Parameter", NULL}, + {"Request Parameter Information", NULL}, + {"Parameter Information", NULL}, + {"Outgoing Message", NULL}, + {"Incoming Message", parser_icbm_incoming}, + {"Evil Request", NULL}, + {"Evil Reply", NULL}, + {"Missed Calls", NULL}, + {"Message Error", NULL}, + {"Host Ack", NULL}, + {NULL, NULL}} + }, + {"Advertisements", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Request Ad", NULL}, + {"Ad Data (GIFs)", NULL}, + {NULL, NULL}} + }, + {"Invitation / Client-to-Client", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Invite a Friend", NULL}, + {"Invitation Ack", NULL}, + {NULL, NULL}} + }, + {"Administrative", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Information Request", NULL}, + {"Information Reply", NULL}, + {"Information Change Request", NULL}, + {"Information Chat Reply", NULL}, + {"Account Confirm Request", NULL}, + {"Account Confirm Reply", NULL}, + {"Account Delete Request", NULL}, + {"Account Delete Reply", NULL}, + {NULL, NULL}} + }, + {"Popups", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Display Popup", NULL}, + {NULL, NULL}} + }, + {"BOS", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Request Rights", NULL}, + {"Rights Response", NULL}, + {"Set group permission mask", NULL}, + {"Add permission list entries", NULL}, + {"Delete permission list entries", NULL}, + {"Add deny list entries", NULL}, + {"Delete deny list entries", NULL}, + {"Server Error", NULL}, + {NULL, NULL}} + }, + {"User Lookup", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Search Request", NULL}, + {"Search Response", NULL}, + {NULL, NULL}} + }, + {"Stats", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Set minimum report interval", NULL}, + {"Report Events", NULL}, + {NULL, NULL}} + }, + {"Translate", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Translate Request", NULL}, + {"Translate Reply", NULL}, + {NULL, NULL}} + }, + {"Chat Navigation", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Request rights", NULL}, + {"Request Exchange Information", NULL}, + {"Request Room Information", NULL}, + {"Request Occupant List", NULL}, + {"Search for Room", NULL}, + {"Create Room", NULL}, + {"Navigation Information", NULL}, + {NULL, NULL}} + }, + {"Chat", { + {"Invalid", NULL}, + {"Error", NULL}, + {"Room Information Update", NULL}, + {"Users Joined", NULL}, + {"Users Left", NULL}, + {"Outgoing Message", NULL}, + {"Incoming Message", NULL}, + {"Evil Request", NULL}, + {"Evil Reply", NULL}, + {"Chat Error", NULL}, + {NULL, NULL}} + }, + {NULL, { + {NULL, NULL}} + } +}; + +void detectaim(struct pcap_pkthdr *hdr, char *pkt) +{ + int i; + struct ether_header *ether = NULL; + struct iphdr *ip = NULL; + struct tcphdr*tcp= NULL; + struct flaphdr *flap = NULL; + struct snachdr *snac = NULL; + char *orig = pkt; + u_int newlen; + int maxfamily = 0; + int maxsubtype = 0; + + if ( (!hdr) || (!pkt) ) + return; + + if (hdr->caplen != hdr->len) + fprintf(stderr, "aimdump: caplen/len mismatch\n"); + + newlen = hdr->caplen; + + ether = (struct ether_header *)pkt; + +#if 0 + printf("\n\naimdump: %s > ", printether(ether->ether_shost)); + printf("%s\n", printether(ether->ether_dhost)); +#endif + + pkt += sizeof(struct ether_header); /* skip over ether headers */ + newlen -= sizeof(struct ether_header); + + ip = (struct iphdr *)pkt; + if (ip->version != 0x4) + return; /* ditch non IPv4 packets */ + pkt += (ip->ihl)*4; + newlen -= (ip->ihl)*4; + + tcp = (struct tcphdr *)pkt; + if(!tcp->psh) /* we only want actual data packets */ + return; + pkt += sizeof(struct tcphdr); + newlen -= sizeof(struct tcphdr); + + flap = (struct flaphdr *)pkt; + + if (flap->start != 0x2a) + return; /* ditch non-FLAP packets */ + +#if 0 + /* TODO: notify user of new connections (SYN) and closed connections (FIN) */ + printf("\nTCP options: %s %s %s %s %s %s\n\n", + tcp->fin?"fin":"", + tcp->syn?"syn":"", + tcp->rst?"rst":"", + tcp->psh?"psh":"", + tcp->ack?"ack":"", + tcp->urg?"urg":""); +#endif + + flap->seqnum = ntohs(flap->seqnum); + flap->len = ntohs(flap->len); + + snac = (struct snachdr *)(pkt+6); + + snac->family = ntohs(snac->family); + snac->subtype= ntohs(snac->subtype); + snac->id = (htons(snac->id & 0x0000ffff)) + (htons(snac->id >>16)<<16); + + printf("\n--------------------\n"); + printf("FLAP:\n"); + printf("\tChannel:\t0x%02x\t\tSeqNum:\t0x%04x\n\tLength:\t\t0x%04x\n", + flap->channel, + flap->seqnum, + flap->len); + printf("SNAC:\n"); + + + /* for overrun checking... */ + for (maxfamily=1;snactypes[maxfamily].family; maxfamily++) + ; + if (snac->family <= maxfamily) + { + for (maxsubtype=1;snactypes[snac->family].subtypes[maxsubtype].name; maxsubtype++) + ; + } + maxfamily--; + maxsubtype--; + + printf("\tFamily:\t\t0x%04x (%s)\n", + snac->family, + (snac->family > maxfamily)?"Out of Range":snactypes[snac->family].family); + printf("\tSubtype:\t0x%04x (%s)\n", + snac->subtype, + (snac->subtype > maxsubtype)?"Out of Range":snactypes[snac->family].subtypes[snac->subtype].name); + printf("\tFlags:\t\t0x%02x,0x%02x\tID:\t0x%08lx\n", snac->flags[0], snac->flags[1], snac->id); + + /* jump around flap+snac */ + pkt += 16; + newlen -= 16; + + if (snactypes[snac->family].subtypes[snac->subtype].parser) + (*(snactypes[snac->family].subtypes[snac->subtype].parser))((u_char *)pkt, newlen); + + printf("\nRAW:\n"); + + for (i=0;iether_type == (ETHERTYPE_INCOMING<<8)) || + (etherhdr->ether_type == (ETHERTYPE_FOUND<<8)) || + (etherhdr->ether_type == (ETHERTYPE_DATA<<8)) ) + processframe(&hdr, pkt, link, DEVNAME); + else + fprintf(stderr, "rpld: skipping ethertype %04x\n", etherhdr->ether_type); + } +#endif + showstats(pd); + + return 0; +} diff --git a/utils/aimdump/util.c b/utils/aimdump/util.c new file mode 100644 index 0000000..e699252 --- /dev/null +++ b/utils/aimdump/util.c @@ -0,0 +1,56 @@ +/* + * + * + * + */ + +#include "aimdump.h" + +char *printether(u_int8_t *addr) +{ + static char out[18]; + + memset(out, 0, 18); + sprintf(out, "%02x:%02x:%02x:%02x:%02x:%02x", + addr[0], addr[1], + addr[2], addr[3], + addr[4], addr[5]); + + return out; +} + +int cmpether(u_int8_t *addr, u_int8_t *addr2) +{ + int i; + for (i=0; icaplen != hdr->len) + fprintf(stderr, "rpld: caplen/len mismatch\n"); + + ether = (struct ether_header *)pkt; + + printf("\n\nrpld: %s > ", printether(ether->ether_shost)); + printf("%s\n", printether(ether->ether_dhost)); + + //pkt = 18; /* skip over ethernet headers */ + for (i=0;icaplen;i+=2) + { + if (!((i)%8)) + printf("\nrpld:\t"); + printf("%02x%02x ", pkt[i] &0xff, pkt[i+1] & 0xff); + } +} diff --git a/utils/aimdump/util.h b/utils/aimdump/util.h new file mode 100644 index 0000000..b086e78 --- /dev/null +++ b/utils/aimdump/util.h @@ -0,0 +1,11 @@ +/* + * + */ +#ifndef __UTIL_H__ +#define __UTIL_H__ + +char *printether(u_int8_t *addr); +int cmpether(u_int8_t *addr, u_int8_t *addr2); +void printframe(struct pcap_pkthdr *hdr, char *pkt); + +#endif /* __UTIL_H__ */