--- policy/bittorrent.bro 2009-03-19 14:41:02.000000000 -0700 +++ policy/bittorrent.bro 2009-06-22 16:25:38.000000000 -0700 @@ -2,7 +2,7 @@ # # bittorrent.bro - policy script for analyzing BitTorrent traffic # --------------------------------------------------------------- -# This code contributed by Nadi Sarrar. +# This code contributed by Nadi Sarrar and Martin Szydlowski @load dpd @load weird @@ -125,7 +125,7 @@ { local cid = record_peer_protocol_traffic(c, is_orig, len); print bittorrent_log, - fmt("%s %s %s", bt_log_id(c$id, cid, tag, is_orig), + fmt("%s %s %As", bt_log_id(c$id, cid, tag, is_orig), pdu_log_len(len), str); } @@ -149,14 +149,14 @@ bytestring_to_hexstr(reserved))); } -event bittorrent_peer_keep_alive(c: connection, is_orig: bool) +event bittorrent_peer_keep_alive(c: connection, is_orig: bool, pdulen: count) { - log_pdu(c, is_orig, "keep-alive", 4); + log_pdu(c, is_orig, "keep-alive", pdulen + 4); } -event bittorrent_peer_choke(c: connection, is_orig: bool) +event bittorrent_peer_choke(c: connection, is_orig: bool, pdulen: count) { - local cid = log_pdu(c, is_orig, "choke", 5); + local cid = log_pdu(c, is_orig, "choke", pdulen + 4); if ( cid > 0 ) { local pc = bt_peer_conns[c$id]; @@ -164,9 +164,9 @@ } } -event bittorrent_peer_unchoke(c: connection, is_orig: bool) +event bittorrent_peer_unchoke(c: connection, is_orig: bool, pdulen: count) { - local cid = log_pdu(c, is_orig, "unchoke", 5); + local cid = log_pdu(c, is_orig, "unchoke", pdulen + 4); if ( cid > 0 ) { local pc = bt_peer_conns[c$id]; @@ -174,64 +174,104 @@ } } -event bittorrent_peer_interested(c: connection, is_orig: bool) +event bittorrent_peer_interested(c: connection, is_orig: bool, pdulen: count) { - log_pdu(c, is_orig, "interested", 5); + log_pdu(c, is_orig, "interested", pdulen + 4); } -event bittorrent_peer_not_interested(c: connection, is_orig: bool) +event bittorrent_peer_not_interested(c: connection, is_orig: bool, pdulen: count) { - log_pdu(c, is_orig, "not-interested", 5); + log_pdu(c, is_orig, "not-interested", pdulen + 4); } -event bittorrent_peer_have(c: connection, is_orig: bool, piece_index: count) +event bittorrent_peer_have(c: connection, is_orig: bool, pdulen: count, piece_index: count) { - log_pdu(c, is_orig, "have", 9); + log_pdu_str(c, is_orig, "have", pdulen + 4, fmt("[index:%d]", piece_index)); } -event bittorrent_peer_bitfield(c: connection, is_orig: bool, bitfield: string) +event bittorrent_peer_bitfield(c: connection, is_orig: bool, pdulen: count, bitfield: string) { - log_pdu_str(c, is_orig, "bitfield", 5 + byte_len(bitfield), + log_pdu_str(c, is_orig, "bitfield", pdulen + 4, fmt("[bitfield:%s]", bytestring_to_hexstr(bitfield))); } -event bittorrent_peer_request(c: connection, is_orig: bool, index: count, +event bittorrent_peer_request(c: connection, is_orig: bool, pdulen: count, index: count, begin: count, length: count) { - log_pdu_str(c, is_orig, "request", 17, + log_pdu_str(c, is_orig, "request", pdulen + 4, fmt("[index:%d begin:%d length:%d]", index, begin, length)); } -event bittorrent_peer_piece(c: connection, is_orig: bool, index: count, +event bittorrent_peer_piece(c: connection, is_orig: bool, pdulen: count, index: count, begin: count, piece_length: count) { - log_pdu_str_n(c, is_orig, "piece", 13, 13 + piece_length, + log_pdu_str_n(c, is_orig, "piece", (pdulen + 4) - piece_length, pdulen + 4, fmt("[index:%d begin:%d piece_length:%d]", index, begin, piece_length)); } -event bittorrent_peer_cancel(c: connection, is_orig: bool, index: count, +event bittorrent_peer_cancel(c: connection, is_orig: bool, pdulen: count, index: count, begin: count, length: count) { - log_pdu_str(c, is_orig, "cancel", 7, + log_pdu_str(c, is_orig, "cancel", pdulen + 4, fmt("[index:%d begin:%d length:%d]", index, begin, length)); } -event bittorrent_peer_port(c: connection, is_orig: bool, listen_port: port) +event bittorrent_peer_port(c: connection, is_orig: bool, pdulen: count, listen_port: port) { - log_pdu_str(c, is_orig, "port", 5, + log_pdu_str(c, is_orig, "port", pdulen + 4, fmt("[listen_port:%s]", listen_port)); } -event bittorrent_peer_unknown(c: connection, is_orig: bool, message_id: count, +event bittorrent_peer_suggest_piece(c: connection, is_orig: bool, pdulen: count, piece_index: count) + { + log_pdu_str(c, is_orig, "suggest-piece", pdulen + 4, fmt("[index:%d]", piece_index)); + } + +event bittorrent_peer_have_all(c: connection, is_orig: bool, pdulen: count) + { + log_pdu(c, is_orig, "have-all", pdulen + 4); + } + +event bittorrent_peer_have_none(c: connection, is_orig: bool, pdulen: count) + { + log_pdu(c, is_orig, "have-none", pdulen + 4); + } + +event bittorrent_peer_reject_request(c: connection, is_orig: bool, pdulen: count, index: count, + begin: count, length: count) + { + log_pdu_str(c, is_orig, "reject-request", pdulen + 4, + fmt("[index:%d begin:%d length:%d]", + index, begin, length)); + } + +event bittorrent_peer_allowed_fast(c: connection, is_orig: bool, pdulen: count, piece_index: count) + { + log_pdu_str(c, is_orig, "allowed-fast", pdulen + 4, fmt("[index:%d]", piece_index)); + } + +event bittorrent_peer_extended(c: connection, is_orig: bool, pdulen: count, sub_type: count, + message: string) + { + log_pdu_str(c, is_orig, "extended", pdulen + 4, + fmt("[message_id:%d message:%s]", sub_type, message)); + } + +event bittorrent_peer_unknown(c: connection, is_orig: bool, pdulen: count, message_id: count, data: string) { - log_pdu_str(c, is_orig, "", 5 + byte_len(data), + log_pdu_str(c, is_orig, "", pdulen + 4, fmt("[message_id:%d]", message_id)); } +event bittorrent_peer_azumessage(c: connection, is_orig: bool, pdulen: count, len: count, typestr: string, message: string) + { + log_pdu_str(c, is_orig, "Azureus", pdulen + 4, fmt("[message_id:%s message:%s]", typestr, message)); + } + event bittorrent_peer_weird(c: connection, is_orig: bool, msg: string) { local pc = lookup_bt_peer(c$id); --- policy/bt-tracker-plist.bro 1969-12-31 16:00:00.000000000 -0800 +++ policy/bt-tracker-plist.bro 2009-06-22 16:25:38.000000000 -0700 @@ -0,0 +1,56 @@ +# $Id:$ +# +# bt-tracker.bro - analysis of BitTorrent tracker traffic +# ------------------------------------------------------------------------------ +# This code contributed by Nadi Sarrar and Martin Szudlowski + +@load bt-tracker + +module BitTorrent; + +function print_peers(peers: bittorrent_peer_set):string + { + if ( length(peers) == 0 ) + return ""; + + local plist = "plist:"; + for ( peer in peers ) { + plist = cat(plist, peer$h, ".", peer$p, ","); + } + return plist; + } + +redef event bt_tracker_response(c: connection, status: count, + headers: bt_tracker_headers, + peers: bittorrent_peer_set, + benc: bittorrent_benc_dir) + { + if ( c$id !in bt_tracker_conns ) + return; + + local id = bt_tracker_conns[c$id]; + + for ( peer in peers ) + expect_connection(c$id$orig_h, peer$h, peer$p, + ANALYZER_BITTORRENT, 1 min); + + if ( "failure reason" in benc ) + { + print bt_tracker_log, + fmt("%s [failure_reason:\"%s\"]", + bt_log_tag(c$id, id, "response", F), + benc["failure reason"]?$s ? + benc["failure reason"]$s : ""); + return; + } + + print bt_tracker_log, + fmt("%s [%s%s%s%s%speers:%d%s]", + bt_log_tag(c$id, id, "response", F), + benc_status(benc, "warning message"), + benc_status(benc, "complete"), + benc_status(benc, "incomplete"), + benc_status(benc, "interval"), + benc_status(benc, "min interval"), + length(peers), print_peers(peers)); + } --- policy/Makefile.am 2008-09-16 22:58:52.000000000 -0700 +++ policy/Makefile.am 2009-06-22 16:25:38.000000000 -0700 @@ -13,7 +13,7 @@ bropolicydir=$(datadir)/bro dist_bropolicy_DATA = bro.init adu.bro alarm.bro analy.bro \ anon.bro arp.bro backdoor.bro bittorrent.bro \ - blaster.bro bt-tracker.bro brolite.bro \ + blaster.bro bt-tracker.bro bt-tracker-plist.bro brolite.bro \ brolite-backdoor.bro brolite-sigs.bro \ capture-events.bro capture-state-updates.bro \ checkpoint.bro clear-passwords.bro conn-flood.bro conn-id.bro \ --- src/bittorrent-analyzer.pac 2009-03-19 14:41:02.000000000 -0700 +++ src/bittorrent-analyzer.pac 2009-06-22 16:25:32.000000000 -0700 @@ -1,10 +1,20 @@ # $Id:$ # -# This code contributed by Nadi Sarrar. +# This code contributed by Nadi Sarrar and Martin Szydlowski. connection BitTorrent_Conn(bro_analyzer: BroAnalyzer) { upflow = BitTorrent_Flow(true); downflow = BitTorrent_Flow(false); + + function is_handshake_complete(): bool + %{ + return upflow()->is_handshake_delivered() && downflow()->is_handshake_delivered(); + %} + + function is_azu_conn(): bool + %{ + return upflow()->is_azu_extended() && downflow()->is_azu_extended(); + %} }; flow BitTorrent_Flow(is_orig: bool) { @@ -13,11 +23,13 @@ %member{ bool handshake_ok; uint64 _next_message_offset; + bool azu_extended; %} %init{ handshake_ok = false; _next_message_offset = 0; + azu_extended = false; %} function next_message_offset(): uint64 @@ -37,6 +49,42 @@ return handshake_ok; %} + function is_azu_extended(): bool + %{ + return azu_extended; + %} + + function azu_has_padding(typever: uint8): bool + %{ + return (typever & 0x10) ? true : false; + %} + + function azu_typestr_to_typenum(typestr: bytestring): uint32 + %{ + // TYPE_* defined in bittorrent-protocol.pac + // standard bittorrent messages in azureus guise + if (typestr == "BT_CHOKE") { return TYPE_CHOKE; } + else if (typestr == "BT_UNCHOKE") { return TYPE_UNCHOKE; } + else if (typestr == "BT_INTERESTED") { return TYPE_INTERESTED; } + else if (typestr == "BT_UNINTERESTED") { return TYPE_NOT_INTERESTED; } + else if (typestr == "BT_HAVE") { return TYPE_HAVE; } + else if (typestr == "BT_BITFIELD") { return TYPE_BITFIELD; } + else if (typestr == "BT_REQUEST") { return TYPE_REQUEST; } + else if (typestr == "BT_PIECE") { return TYPE_PIECE; } + else if (typestr == "BT_CANCEL") { return TYPE_CANCEL; } + else if (typestr == "BT_PORT") { return TYPE_PORT; } + // from here on the returned TYPE_* are fictional + else if (typestr == "BT_HANDSHAKE") { return TYPE_BT_HANDSHAKE; } + else if (typestr == "BT_KEEP_ALIVE") { return TYPE_BT_KEEP_ALIVE; } + // azureus-specific messages + else if (typestr == "AZ_HANDSHAKE") { return TYPE_AZ_HANDSHAKE; } + else if (typestr == "AZ_PEER_EXCHANGE") { return TYPE_AZ_PEER_EXCHANGE; } + else if (typestr == "AZ_REQUEST_HINT") { return TYPE_AZ_REQUEST_HINT; } + else if (typestr == "AZ_HAVE") { return TYPE_AZ_HAVE; } + else if (typestr == "AZ_BAD_PIECE") { return TYPE_AZ_BAD_PIECE; } + else { return TYPE_UNKNOWN; } + %} + function validate_handshake(pstrlen: uint8, pstr: const_bytestring): bool %{ if ( pstrlen != 19 || @@ -73,105 +121,107 @@ bytestring_to_val(peer_id)); } + azu_extended = (reserved[0] & 0x80) ? true : false; + connection()->bro_analyzer()->ProtocolConfirmation(); return true; %} - function deliver_keep_alive(): bool + function deliver_keep_alive(pdulen: uint32): bool %{ if ( ::bittorrent_peer_keep_alive ) { bro_event_bittorrent_peer_keep_alive( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig()); + is_orig(), pdulen); } return true; %} - function deliver_choke(): bool + function deliver_choke(pdulen: uint32): bool %{ if ( ::bittorrent_peer_choke ) { bro_event_bittorrent_peer_choke( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig()); + is_orig(), pdulen); } return true; %} - function deliver_unchoke(): bool + function deliver_unchoke(pdulen: uint32): bool %{ if ( ::bittorrent_peer_unchoke ) { bro_event_bittorrent_peer_unchoke( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig()); + is_orig(), pdulen); } return true; %} - function deliver_interested(): bool + function deliver_interested(pdulen: uint32): bool %{ if ( ::bittorrent_peer_interested ) { bro_event_bittorrent_peer_interested( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig()); + is_orig(), pdulen); } return true; %} - function deliver_not_interested(): bool + function deliver_not_interested(pdulen: uint32): bool %{ if ( ::bittorrent_peer_not_interested ) { bro_event_bittorrent_peer_not_interested( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig()); + is_orig(), pdulen); } return true; %} - function deliver_have(piece_index: uint32): bool + function deliver_have(pdulen: uint32, piece_index: uint32): bool %{ if ( ::bittorrent_peer_have ) { bro_event_bittorrent_peer_have( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig(), + is_orig(), pdulen, piece_index); } return true; %} - function deliver_bitfield(bitfield: const_bytestring): bool + function deliver_bitfield(pdulen: uint32, bitfield: const_bytestring): bool %{ if ( ::bittorrent_peer_bitfield ) { bro_event_bittorrent_peer_bitfield( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig(), + is_orig(), pdulen, bytestring_to_val(bitfield)); } return true; %} - function deliver_request(index: uint32, begin: uint32, + function deliver_request(pdulen: uint32, index: uint32, begin: uint32, length: uint32): bool %{ if ( ::bittorrent_peer_request ) @@ -179,14 +229,14 @@ bro_event_bittorrent_peer_request( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig(), + is_orig(), pdulen, index, begin, length); } return true; %} - function deliver_piece(index: uint32, begin: uint32, + function deliver_piece(pdulen: uint32, index: uint32, begin: uint32, piece_length: uint32): bool %{ if ( ::bittorrent_peer_piece ) @@ -194,14 +244,14 @@ bro_event_bittorrent_peer_piece( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig(), + is_orig(), pdulen, index, begin, piece_length); } return true; %} - function deliver_cancel(index: uint32, begin: uint32, + function deliver_cancel(pdulen: uint32, index: uint32, begin: uint32, length: uint32): bool %{ if ( ::bittorrent_peer_cancel ) @@ -209,39 +259,135 @@ bro_event_bittorrent_peer_cancel( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig(), + is_orig(), pdulen, index, begin, length); } return true; %} - function deliver_port(listen_port: uint16): bool + function deliver_port(pdulen: uint32, listen_port: uint16): bool %{ if ( ::bittorrent_peer_port ) { bro_event_bittorrent_peer_port( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig(), + is_orig(), pdulen, new PortVal(listen_port, TRANSPORT_TCP)); } return true; %} - function deliver_unknown(id: uint8, data: const_bytestring): bool + function deliver_suggest_piece(pdulen: uint32, piece_index: uint32): bool + %{ + if ( ::bittorrent_peer_suggest_piece ) + { + bro_event_bittorrent_peer_suggest_piece( + connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + is_orig(), pdulen, + piece_index); + } + + return true; + %} + + function deliver_have_all(pdulen: uint32): bool + %{ + if ( ::bittorrent_peer_have_all ) + { + bro_event_bittorrent_peer_have_all( + connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + is_orig(), pdulen); + } + + return true; + %} + + function deliver_have_none(pdulen: uint32): bool + %{ + if ( ::bittorrent_peer_have_none ) + { + bro_event_bittorrent_peer_have_none( + connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + is_orig(), pdulen); + } + + return true; + %} + + function deliver_reject_request(pdulen: uint32, index: uint32, begin: uint32, + length: uint32): bool + %{ + if ( ::bittorrent_peer_reject_request ) + { + bro_event_bittorrent_peer_reject_request( + connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + is_orig(), pdulen, + index, begin, length); + } + + return true; + %} + + function deliver_allowed_fast(pdulen: uint32, piece_index: uint32): bool + %{ + if ( ::bittorrent_peer_allowed_fast ) + { + bro_event_bittorrent_peer_allowed_fast( + connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + is_orig(), pdulen, + piece_index); + } + + return true; + %} + + function deliver_extended(pdulen: uint32, sub_type: uint8, message: bytestring): bool + %{ + if ( ::bittorrent_peer_extended ) + { + bro_event_bittorrent_peer_extended( + connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + is_orig(), pdulen, + sub_type, bytestring_to_val(message)); + } + + return true; + %} + + + function deliver_unknown(pdulen: uint32, id: uint8, data: const_bytestring): bool %{ if ( ::bittorrent_peer_unknown ) { bro_event_bittorrent_peer_unknown( connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), - is_orig(), - id, - bytestring_to_val(data)); + is_orig(), pdulen, + id, bytestring_to_val(data)); } return true; %} + + function deliver_azumessage(pdulen: uint32, len: uint32, typestr: const_bytestring, message: const_bytestring): bool + %{ + if ( ::bittorrent_peer_azumessage ) + { + bro_event_bittorrent_peer_azumessage( + connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + is_orig(), pdulen, + len, bytestring_to_val(typestr), bytestring_to_val(message)); + } + return true; + %} }; --- src/bittorrent-protocol.pac 2009-03-19 14:41:02.000000000 -0700 +++ src/bittorrent-protocol.pac 2009-06-22 16:25:33.000000000 -0700 @@ -1,18 +1,34 @@ # $Id:$ # -# This code contributed by Nadi Sarrar. +# This code contributed by Nadi Sarrar and Martin Szydlowski. enum BitTorrent_peer_msg_type { - TYPE_CHOKE = 0, - TYPE_UNCHOKE = 1, - TYPE_INTERESTED = 2, - TYPE_NOT_INTERESTED = 3, - TYPE_HAVE = 4, - TYPE_BITFIELD = 5, - TYPE_REQUEST = 6, - TYPE_PIECE = 7, - TYPE_CANCEL = 8, - TYPE_PORT = 9, + TYPE_CHOKE = 0, + TYPE_UNCHOKE = 1, + TYPE_INTERESTED = 2, + TYPE_NOT_INTERESTED = 3, + TYPE_HAVE = 4, + TYPE_BITFIELD = 5, + TYPE_REQUEST = 6, + TYPE_PIECE = 7, + TYPE_CANCEL = 8, +# non-standard message types + TYPE_PORT = 9, + TYPE_SUGGEST_PIECE = 13, + TYPE_HAVE_ALL = 14, + TYPE_HAVE_NONE = 15, + TYPE_REJECT_REQUEST = 16, + TYPE_ALLOWED_FAST = 17, + TYPE_EXTENDED = 20, +# fictional message types + TYPE_BT_HANDSHAKE = 0x8000, + TYPE_BT_KEEP_ALIVE = 0x8001, + TYPE_AZ_HANDSHAKE = 0x8100, + TYPE_AZ_PEER_EXCHANGE = 0x8101, + TYPE_AZ_REQUEST_HINT = 0x8102, + TYPE_AZ_HAVE = 0x8103, + TYPE_AZ_BAD_PIECE = 0x8104, + TYPE_UNKNOWN = 0xFFFF, }; type BitTorrent_Handshake = record { @@ -30,96 +46,137 @@ $context.flow.deliver_handshake(reserved, info_hash, peer_id); }; -type BitTorrent_KeepAlive = empty &let { - deliver: bool = $context.flow.deliver_keep_alive(); +type BitTorrent_KeepAlive(pdulen: uint32) = empty &let { + deliver: bool = $context.flow.deliver_keep_alive(pdulen); }; -type BitTorrent_Choke = empty &let { - deliver: bool = $context.flow.deliver_choke(); +type BitTorrent_Choke(pdulen: uint32) = empty &let { + deliver: bool = $context.flow.deliver_choke(pdulen); }; -type BitTorrent_Unchoke = empty &let { - deliver: bool = $context.flow.deliver_unchoke(); +type BitTorrent_Unchoke(pdulen: uint32) = empty &let { + deliver: bool = $context.flow.deliver_unchoke(pdulen); }; -type BitTorrent_Interested = empty &let { - deliver: bool = $context.flow.deliver_interested(); +type BitTorrent_Interested(pdulen: uint32) = empty &let { + deliver: bool = $context.flow.deliver_interested(pdulen); }; -type BitTorrent_NotInterested = empty &let { - deliver: bool = $context.flow.deliver_not_interested(); +type BitTorrent_NotInterested(pdulen: uint32) = empty &let { + deliver: bool = $context.flow.deliver_not_interested(pdulen); }; -type BitTorrent_Have = record { +type BitTorrent_Have(pdulen: uint32) = record { piece_index: uint32; } &let { - deliver: bool = $context.flow.deliver_have(piece_index); + deliver: bool = $context.flow.deliver_have(pdulen, piece_index); }; -type BitTorrent_Bitfield(len: uint32) = record { +type BitTorrent_Bitfield(pdulen: uint32, len: uint32) = record { bitfield: bytestring &length = len; } &let { - deliver: bool = $context.flow.deliver_bitfield(bitfield); + deliver: bool = $context.flow.deliver_bitfield(pdulen, bitfield); }; -type BitTorrent_Request = record { +type BitTorrent_Request(pdulen: uint32) = record { index: uint32; begin: uint32; length: uint32; } &let { - deliver: bool = $context.flow.deliver_request(index, begin, length); + deliver: bool = $context.flow.deliver_request(pdulen, index, begin, length); }; -type BitTorrent_PieceHeader(len: uint32) = record { +type BitTorrent_PieceHeader(len: uint32, hdrlen: uint32) = record { index: uint32; begin: uint32; } &let { incoffset: bool = - $context.flow.increment_next_message_offset(true, len + 5); + $context.flow.increment_next_message_offset(true, len + hdrlen); }; -type BitTorrent_Piece(len: uint32) = record { - header: BitTorrent_PieceHeader(len); +type BitTorrent_Piece(pdulen: uint32, len: uint32, hdrlen: uint32) = record { + header: BitTorrent_PieceHeader(len, hdrlen); : bytestring &length = len - 8; } &let { - deliver: bool = $context.flow.deliver_piece(header.index, + deliver: bool = $context.flow.deliver_piece(pdulen, header.index, header.begin, len - 8); }; -type BitTorrent_Cancel = record { +type BitTorrent_Cancel(pdulen: uint32) = record { index: uint32; begin: uint32; length: uint32; } &let { - deliver: bool = $context.flow.deliver_cancel(index, begin, length); + deliver: bool = $context.flow.deliver_cancel(pdulen, index, begin, length); }; -type BitTorrent_Port = record { +type BitTorrent_Port(pdulen: uint32) = record { listen_port: uint16; } &let { - deliver: bool = $context.flow.deliver_port(listen_port); + deliver: bool = $context.flow.deliver_port(pdulen, listen_port); }; -type BitTorrent_Unknown(id: uint8, len: uint32) = record { +type BitTorrent_SuggestPiece(pdulen: uint32) = record { + index: uint32; +} &let { + deliver: bool = $context.flow.deliver_suggest_piece(pdulen, index); +}; + +type BitTorrent_HaveAll(pdulen: uint32) = empty &let { + deliver: bool = $context.flow.deliver_have_all(pdulen); +}; + +type BitTorrent_HaveNone(pdulen: uint32) = empty &let { + deliver: bool = $context.flow.deliver_have_none(pdulen); +}; + +type BitTorrent_RejectRequest(pdulen: uint32) = record { + index: uint32; + begin: uint32; + length: uint32; +} &let { + deliver: bool = $context.flow.deliver_reject_request(pdulen, index, begin, length); +}; + +type BitTorrent_AllowedFast(pdulen: uint32) = record { + index: uint32; +} &let { + deliver: bool = $context.flow.deliver_allowed_fast(pdulen, index); +}; + +type BitTorrent_Extended(pdulen: uint32, len: uint32) = record { + sub_type: uint8; + message: bytestring &length = len - 1; +} &let { + deliver: bool = $context.flow.deliver_extended(pdulen, sub_type, message); +}; + +type BitTorrent_Unknown(pdulen: uint32, id: uint8, len: uint32) = record { data: bytestring &length = len; } &let { - deliver: bool = $context.flow.deliver_unknown(id, data); + deliver: bool = $context.flow.deliver_unknown(pdulen, id, data); }; type BitTorrent_MessageID(len: uint32) = record { id: uint8; data: case id of { - TYPE_CHOKE -> choke: BitTorrent_Choke; - TYPE_UNCHOKE -> unchoke: BitTorrent_Unchoke; - TYPE_INTERESTED -> interested: BitTorrent_Interested; - TYPE_NOT_INTERESTED -> not_interested: BitTorrent_NotInterested; - TYPE_HAVE -> have: BitTorrent_Have; - TYPE_BITFIELD -> bitfield: BitTorrent_Bitfield(len - 1); - TYPE_REQUEST -> request: BitTorrent_Request; - TYPE_PIECE -> piece: BitTorrent_Piece(len - 1); - TYPE_CANCEL -> cancel: BitTorrent_Cancel; - TYPE_PORT -> port: BitTorrent_Port; - default -> unknown: BitTorrent_Unknown(id, len - 1); + TYPE_CHOKE -> choke: BitTorrent_Choke(len); + TYPE_UNCHOKE -> unchoke: BitTorrent_Unchoke(len); + TYPE_INTERESTED -> interested: BitTorrent_Interested(len); + TYPE_NOT_INTERESTED -> not_interested: BitTorrent_NotInterested(len); + TYPE_HAVE -> have: BitTorrent_Have(len); + TYPE_BITFIELD -> bitfield: BitTorrent_Bitfield(len, len - 1); + TYPE_REQUEST -> request: BitTorrent_Request(len); + TYPE_PIECE -> piece: BitTorrent_Piece(len, len - 1, 1); + TYPE_CANCEL -> cancel: BitTorrent_Cancel(len); + TYPE_PORT -> port: BitTorrent_Port(len); + TYPE_SUGGEST_PIECE -> suggest_piece: BitTorrent_SuggestPiece(len); + TYPE_HAVE_ALL -> have_all: BitTorrent_HaveAll(len); + TYPE_HAVE_NONE -> have_none: BitTorrent_HaveNone(len); + TYPE_REJECT_REQUEST -> reject_request: BitTorrent_RejectRequest(len); + TYPE_ALLOWED_FAST -> allowed_fast: BitTorrent_AllowedFast(len); + TYPE_EXTENDED -> extended: BitTorrent_Extended(len, len - 1); + default -> unknown: BitTorrent_Unknown(len, id, len - 1); }; }; @@ -129,18 +186,70 @@ validate: bool = $context.flow.validate_message_length(len); }; -type BitTorrent_Message = record { - len: BitTorrent_MessageLength; - data: case len.len of { - 0 -> keep_alive: BitTorrent_KeepAlive; - default -> message_id: BitTorrent_MessageID(len.len); +type BitTorrent_AzuPad = record { + padlen: uint16; + padbytes: bytestring &length = padlen, &transient; +} &let { + len: uint32 = padlen + 2; +}; + +type BitTorrent_AzuHeader = record { + typelen: uint32; + typestr: bytestring &length = typelen; + typever: uint8; + msgpad: case haspad of { + true -> pad: BitTorrent_AzuPad; + default -> nopad: empty; + } &requires(haspad); +} &let { + haspad: bool = $context.flow.azu_has_padding(typever); + len: uint32 = 4 + typelen + 1 + (haspad ? pad.len : 0); + typenum: uint32 = $context.flow.azu_typestr_to_typenum(typestr); +}; + +type BitTorrent_AzuUnknown(pdulen: uint32, len: uint32, typestr: bytestring) = record { + message: bytestring &length = len; +} &let { + deliver: bool = $context.flow.deliver_azumessage(pdulen, len, typestr, message); +}; + +type BitTorrent_AzuMessage(len: uint32) = record { + hdr: BitTorrent_AzuHeader; + data: case hdr.typenum of { + TYPE_CHOKE -> choke: BitTorrent_Choke(len); + TYPE_UNCHOKE -> unchoke: BitTorrent_Unchoke(len); + TYPE_INTERESTED -> interested: BitTorrent_Interested(len); + TYPE_NOT_INTERESTED -> not_interested: BitTorrent_NotInterested(len); + TYPE_HAVE -> have: BitTorrent_Have(len); + TYPE_BITFIELD -> bitfield: BitTorrent_Bitfield(len, len - hdr.len); + TYPE_REQUEST -> request: BitTorrent_Request(len); + TYPE_PIECE -> piece: BitTorrent_Piece(len, len - hdr.len, hdr.len); + TYPE_CANCEL -> cancel: BitTorrent_Cancel(len); + TYPE_BT_KEEP_ALIVE -> keep_alive: BitTorrent_KeepAlive(len); + default -> unknown: BitTorrent_AzuUnknown(len, len - hdr.len, hdr.typestr); }; -} &length = 4 + len.len, &let { +} &let { + incoffset: bool = $context.flow.increment_next_message_offset( + hdr.typenum != TYPE_PIECE, 4 + len); +}; + +type BitTorrent_StdMessage(len: uint32) = case len of { + 0 -> keep_alive: BitTorrent_KeepAlive(len); + default -> message_id: BitTorrent_MessageID(len); +} &let { incoffset: bool = $context.flow.increment_next_message_offset( - len.len == 0 || message_id.id != TYPE_PIECE, - 4 + len.len); + len == 0 || message_id.id != TYPE_PIECE, + 4 + len); }; +type BitTorrent_Message = record { + len: BitTorrent_MessageLength; + payload: case $context.connection.is_azu_conn() of { + false -> stdmessage: BitTorrent_StdMessage(len.len); + true -> azumessage: BitTorrent_AzuMessage(len.len); + }; +} &length = 4 + len.len; + type BitTorrent_PDU = case $context.flow.is_handshake_delivered() of { false -> handshake: BitTorrent_Handshake; true -> message: BitTorrent_Message; --- src/BitTorrentTracker.cc 2008-07-15 15:00:40.000000000 -0700 +++ src/BitTorrentTracker.cc 2009-06-22 16:25:35.000000000 -0700 @@ -478,8 +478,8 @@ // addresses in network order but PortVal's // take ports in host order. BitTorrent specifies // that both are in network order here. - uint32 ad = extract_uint32((u_char*) value); - uint16 pt = ntohs((value[4] << 8) | value[5]); + uint32 ad = ntohl(extract_uint32((u_char *) value)); + uint16 pt = ((value[4] << 8) | value[5]); RecordVal* peer = new RecordVal(bittorrent_peer); peer->Assign(0, new AddrVal(ad)); --- src/event.bif 2009-03-19 14:41:02.000000000 -0700 +++ src/event.bif 2009-06-22 16:25:20.000000000 -0700 @@ -79,22 +79,32 @@ event bittorrent_peer_handshake%(c: connection, is_orig: bool, reserved: string, info_hash: string, peer_id: string%); -event bittorrent_peer_keep_alive%(c: connection, is_orig: bool%); -event bittorrent_peer_choke%(c: connection, is_orig: bool%); -event bittorrent_peer_unchoke%(c: connection, is_orig: bool%); -event bittorrent_peer_interested%(c: connection, is_orig: bool%); -event bittorrent_peer_not_interested%(c: connection, is_orig: bool%); -event bittorrent_peer_have%(c: connection, is_orig: bool, piece_index: count%); -event bittorrent_peer_bitfield%(c: connection, is_orig: bool, bitfield: string%); -event bittorrent_peer_request%(c: connection, is_orig: bool, index: count, +event bittorrent_peer_keep_alive%(c: connection, is_orig: bool, pdulen: count%); +event bittorrent_peer_choke%(c: connection, is_orig: bool, pdulen: count%); +event bittorrent_peer_unchoke%(c: connection, is_orig: bool, pdulen: count%); +event bittorrent_peer_interested%(c: connection, is_orig: bool, pdulen: count%); +event bittorrent_peer_not_interested%(c: connection, is_orig: bool, pdulen: count%); +event bittorrent_peer_have%(c: connection, is_orig: bool, pdulen: count, piece_index: count%); +event bittorrent_peer_bitfield%(c: connection, is_orig: bool, pdulen: count, bitfield: string%); +event bittorrent_peer_request%(c: connection, is_orig: bool, pdulen: count, index: count, begin: count, length: count%); -event bittorrent_peer_piece%(c: connection, is_orig: bool, index: count, +event bittorrent_peer_piece%(c: connection, is_orig: bool, pdulen: count, index: count, begin: count, piece_length: count%); -event bittorrent_peer_cancel%(c: connection, is_orig: bool, index: count, +event bittorrent_peer_cancel%(c: connection, is_orig: bool, pdulen: count, index: count, begin: count, length: count%); -event bittorrent_peer_port%(c: connection, is_orig: bool, listen_port: port%); -event bittorrent_peer_unknown%(c: connection, is_orig: bool, message_id: count, +event bittorrent_peer_port%(c: connection, is_orig: bool, pdulen: count, listen_port: port%); +event bittorrent_peer_suggest_piece%(c: connection, is_orig: bool, pdulen: count, piece_index: count%); +event bittorrent_peer_have_all%(c: connection, is_orig: bool, pdulen: count%); +event bittorrent_peer_have_none%(c: connection, is_orig: bool, pdulen: count%); +event bittorrent_peer_reject_request%(c: connection, is_orig: bool, pdulen: count, index: count, + begin: count, length: count%); +event bittorrent_peer_allowed_fast%(c: connection, is_orig: bool, pdulen: count, piece_index: count%); +event bittorrent_peer_extended%(c: connection, is_orig: bool, pdulen: count, sub_type: count, + message: string%); +event bittorrent_peer_unknown%(c: connection, is_orig: bool, pdulen: count, message_id: count, data: string%); +event bittorrent_peer_azumessage%(c: connection, is_orig: bool, pdulen: count, + len: count, typestr: string, message:string%); event bittorrent_peer_weird%(c: connection, is_orig: bool, msg: string%); event bt_tracker_request%(c: connection, uri: string, headers: bt_tracker_headers%);