Hi, I just checked the following file in to the subversion repository. It's a quick howto for writing new protocols for firestorm. It will be in the next release, and online eventually. ======================================================================== Firestorm v0.5.x - Programmers Manual. Part 1. Understanding the Decode subsystem and Writing Decode Plugins. Copyright (c) 2003 Gianni Tedesco <gianni at scaramanga dot co dot uk> ======================================================================== THE THEORY ========== A packet contains many headers one encapsulated inside the other. Like this: +--------------+ + Ethernet Hdr + Lower memory addresses +--------------+ (start of packet) + IP Header + +--------------+ | + TCP Header + | +--------------+ V + HTTP Headers + +--------------+ + + + data... + Higher memory addresses + + (end of packet) +--------------+ The decode information can be represented as a directed acyclic graph like this: ether -> ip -> tcp -> http -> data Because a network protocol can only encapsulate certain other specific protocols within them, one can represent all possible packet decodes as a bigger graph, and the individual packet decode is a subgraph of this. ether -> ip -> tcp -> smtp | | `-> http | | `-> pop3 | | `-> telnet | | | `-> udp -> dns | `->icmp `-> arp `-> ipv6 Eeach of these nodes is a 'struct proto', the subgraph (or path) through here is stored inside 'struct packet' in the 'layer' array/vector. Each node in the decode graph contains a linked list of all the nodes that are possible to come after it (the 'children' member). For our example the IP protocol will will contain links to tcp, then udp then icmp. Most network protocol structures have fields which tell us which protocol is encapsulated within. For example IP has this field set to 6 for TCP and 17 for UDP and so on. These ID numbers are used to decide which child we will call. This tree lends itself well to a recursive algorithm. Infact the problem is essentially recursive and there is no escaping it. Firestorm starts the decode process in the capdev plugins. The capture device knows what it is capturing from (eg: if the interface is an ethernet network card, then we are pretty sure that what we are getting is ethernet. The decode plugins all do pretty much the same thing: 1. What is the protocol field set to in this header? 2. Look in our list for a matching protocol, if not found, terminate. 3. If found, call the function pointer for that protocol (ie: recurse) Infact the only reason decode functions are needed is because each protocol header has different layout and different ways of encoding which protocol is to come next. Some protocols have no children and thus always terminate. THE PRACTICE ============ Plugin decode plugins, the order of things: 1. Check the packet space is big enough for the minimum size of your header, if not return. 2. If your header is variable sized, take the size of the header, check there is enough room for it. If not return. 3. Validate any other important fields such as checksums. Alert, if anything is really suspicious. 4. Set the pointer in the next layer and increment pkt->llen. 5. If p->llen < PKT_LAYERS, pass on to children remembering to blank the flags and session fields, if nothing is passed on, then call dispatch(pkt); A sample plugin for foo protocol follows: void foo_decode(struct packet *p) { struct layer *l = &p->layer[p->llen].h.raw; struct foo_hdr *hdr = (struct foo_hdr *)p->layer[p->llen].h.raw; struct proto_child *pc; if ( l->h.raw + sizeof(struct foo_hdr) > p->end ) return; if ( l->h.raw + ntohs(foo->len) > p->end ) return; if ( !foo_csum(foo) ) { alert(&bad_csum, p); return; } p->layer[++p->llen].h.raw = l->h.raw + ntohs(foo->len); if ( p->llen >= PKT_LAYERS ) goto finish; for(pc=l->proto->children; pc; pc=pc->next) { if ( l->h.proto == pc->id ) { p->layer[p->llen].flags = 0; p->layer[p->llen].session = 0; p->layer[p->llen].proto = pc->proto; pc->proto->decode(p); return; } } finish: dispatch(p); } -- // Gianni Tedesco (gianni at scaramanga dot co dot uk) lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import 8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
Attachment:
signature.asc
Description: This is a digitally signed message part