summaryrefslogtreecommitdiff
path: root/tools/sniffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/sniffer.cpp')
-rw-r--r--tools/sniffer.cpp183
1 files changed, 108 insertions, 75 deletions
diff --git a/tools/sniffer.cpp b/tools/sniffer.cpp
index 14d32bd..abc2dc0 100644
--- a/tools/sniffer.cpp
+++ b/tools/sniffer.cpp
@@ -34,7 +34,7 @@
#undef max
#endif
-#include "../util/builder.h"
+#include "../bson/util/builder.h"
#include "../util/message.h"
#include "../util/mmap.h"
#include "../db/dbmessage.h"
@@ -74,6 +74,10 @@ using mongo::MemoryMappedFile;
int captureHeaderSize;
set<int> serverPorts;
string forwardAddress;
+bool objcheck = false;
+
+ostream *outPtr = &cout;
+ostream &out() { return *outPtr; }
/* IP header */
struct sniff_ip {
@@ -205,23 +209,23 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
if ( bytesRemainingInMessage[ c ] == 0 ) {
m.setData( (MsgData*)payload , false );
- if ( !m.data->valid() ) {
+ if ( !m.header()->valid() ) {
cerr << "Invalid message start, skipping packet." << endl;
return;
}
- if ( size_payload > m.data->len ) {
+ if ( size_payload > m.header()->len ) {
cerr << "Multiple messages in packet, skipping packet." << endl;
return;
}
- if ( size_payload < m.data->len ) {
- bytesRemainingInMessage[ c ] = m.data->len - size_payload;
+ if ( size_payload < m.header()->len ) {
+ bytesRemainingInMessage[ c ] = m.header()->len - size_payload;
messageBuilder[ c ].reset( new BufBuilder() );
- messageBuilder[ c ]->append( (void*)payload, size_payload );
+ messageBuilder[ c ]->appendBuf( (void*)payload, size_payload );
return;
}
} else {
bytesRemainingInMessage[ c ] -= size_payload;
- messageBuilder[ c ]->append( (void*)payload, size_payload );
+ messageBuilder[ c ]->appendBuf( (void*)payload, size_payload );
if ( bytesRemainingInMessage[ c ] < 0 ) {
cerr << "Received too many bytes to complete message, resetting buffer" << endl;
bytesRemainingInMessage[ c ] = 0;
@@ -237,84 +241,103 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
DbMessage d( m );
- cout << inet_ntoa(ip->ip_src) << ":" << ntohs( tcp->th_sport )
- << ( serverPorts.count( ntohs( tcp->th_dport ) ) ? " -->> " : " <<-- " )
- << inet_ntoa(ip->ip_dst) << ":" << ntohs( tcp->th_dport )
- << " " << d.getns()
- << " " << m.data->len << " bytes "
- << " id:" << hex << m.data->id << dec << "\t" << m.data->id;
+ out() << inet_ntoa(ip->ip_src) << ":" << ntohs( tcp->th_sport )
+ << ( serverPorts.count( ntohs( tcp->th_dport ) ) ? " -->> " : " <<-- " )
+ << inet_ntoa(ip->ip_dst) << ":" << ntohs( tcp->th_dport )
+ << " " << d.getns()
+ << " " << m.header()->len << " bytes "
+ << " id:" << hex << m.header()->id << dec << "\t" << m.header()->id;
processMessage( c , m );
}
-void processMessage( Connection& c , Message& m ){
- DbMessage d(m);
+class AuditingDbMessage : public DbMessage {
+public:
+ AuditingDbMessage( const Message &m ) : DbMessage( m ) {}
+ BSONObj nextJsObj( const char *context ) {
+ BSONObj ret = DbMessage::nextJsObj();
+ if ( objcheck && !ret.valid() ) {
+ // TODO provide more debugging info
+ cout << "invalid object in " << context << ": " << ret.hexDump() << endl;
+ }
+ return ret;
+ }
+};
- if ( m.data->operation() == mongo::opReply )
- cout << " - " << m.data->responseTo;
- cout << endl;
+void processMessage( Connection& c , Message& m ){
+ AuditingDbMessage d(m);
+
+ if ( m.operation() == mongo::opReply )
+ out() << " - " << (unsigned)m.header()->responseTo;
+ out() << endl;
- switch( m.data->operation() ){
- case mongo::opReply:{
- mongo::QueryResult* r = (mongo::QueryResult*)m.data;
- cout << "\treply" << " n:" << r->nReturned << " cursorId: " << r->cursorId << endl;
- if ( r->nReturned ){
- mongo::BSONObj o( r->data() , 0 );
- cout << "\t" << o << endl;
+ try {
+ switch( m.operation() ){
+ case mongo::opReply:{
+ mongo::QueryResult* r = (mongo::QueryResult*)m.singleData();
+ out() << "\treply" << " n:" << r->nReturned << " cursorId: " << r->cursorId << endl;
+ if ( r->nReturned ){
+ mongo::BSONObj o( r->data() , 0 );
+ out() << "\t" << o << endl;
+ }
+ break;
+ }
+ case mongo::dbQuery:{
+ mongo::QueryMessage q(d);
+ out() << "\tquery: " << q.query << " ntoreturn: " << q.ntoreturn << " ntoskip: " << q.ntoskip << endl;
+ break;
+ }
+ case mongo::dbUpdate:{
+ int flags = d.pullInt();
+ BSONObj q = d.nextJsObj( "update" );
+ BSONObj o = d.nextJsObj( "update" );
+ out() << "\tupdate flags:" << flags << " q:" << q << " o:" << o << endl;
+ break;
+ }
+ case mongo::dbInsert:{
+ out() << "\tinsert: " << d.nextJsObj( "insert" ) << endl;
+ while ( d.moreJSObjs() ) {
+ out() << "\t\t" << d.nextJsObj( "insert" ) << endl;
+ }
+ break;
+ }
+ case mongo::dbGetMore:{
+ int nToReturn = d.pullInt();
+ long long cursorId = d.pullInt64();
+ out() << "\tgetMore nToReturn: " << nToReturn << " cursorId: " << cursorId << endl;
+ break;
+ }
+ case mongo::dbDelete:{
+ int flags = d.pullInt();
+ BSONObj q = d.nextJsObj( "delete" );
+ out() << "\tdelete flags: " << flags << " q: " << q << endl;
+ break;
+ }
+ case mongo::dbKillCursors:{
+ int *x = (int *) m.singleData()->_data;
+ x++; // reserved
+ int n = *x;
+ out() << "\tkillCursors n: " << n << endl;
+ break;
+ }
+ default:
+ cerr << "*** CANNOT HANDLE TYPE: " << m.operation() << endl;
}
- break;
- }
- case mongo::dbQuery:{
- mongo::QueryMessage q(d);
- cout << "\tquery: " << q.query << " ntoreturn: " << q.ntoreturn << " ntoskip: " << q.ntoskip << endl;
- break;
- }
- case mongo::dbUpdate:{
- int flags = d.pullInt();
- BSONObj q = d.nextJsObj();
- BSONObj o = d.nextJsObj();
- cout << "\tupdate flags:" << flags << " q:" << q << " o:" << o << endl;
- break;
- }
- case mongo::dbInsert:{
- cout << "\tinsert: " << d.nextJsObj() << endl;
- while ( d.moreJSObjs() )
- cout << "\t\t" << d.nextJsObj() << endl;
- break;
- }
- case mongo::dbGetMore:{
- int nToReturn = d.pullInt();
- long long cursorId = d.pullInt64();
- cout << "\tgetMore nToReturn: " << nToReturn << " cursorId: " << cursorId << endl;
- break;
- }
- case mongo::dbDelete:{
- int flags = d.pullInt();
- BSONObj q = d.nextJsObj();
- cout << "\tdelete flags: " << flags << " q: " << q << endl;
- break;
- }
- case mongo::dbKillCursors:{
- int *x = (int *) m.data->_data;
- x++; // reserved
- int n = *x;
- cout << "\tkillCursors n: " << n << endl;
- break;
- }
- default:
- cerr << "*** CANNOT HANDLE TYPE: " << m.data->operation() << endl;
+ } catch ( ... ) {
+ cerr << "Error parsing message for operation: " << m.operation() << endl;
}
-
+
+
if ( !forwardAddress.empty() ) {
- if ( m.data->operation() != mongo::opReply ) {
+ if ( m.operation() != mongo::opReply ) {
boost::shared_ptr<DBClientConnection> conn = forwarder[ c ];
if ( !conn ) {
conn.reset(new DBClientConnection( true ));
conn->connect( forwardAddress );
forwarder[ c ] = conn;
}
- if ( m.data->operation() == mongo::dbQuery || m.data->operation() == mongo::dbGetMore ) {
- if ( m.data->operation() == mongo::dbGetMore ) {
+ if ( m.operation() == mongo::dbQuery || m.operation() == mongo::dbGetMore ) {
+ if ( m.operation() == mongo::dbGetMore ) {
DbMessage d( m );
d.pullInt();
long long &cId = d.pullInt64();
@@ -322,8 +345,8 @@ void processMessage( Connection& c , Message& m ){
}
Message response;
conn->port().call( m, response );
- QueryResult *qr = (QueryResult *) response.data;
- if ( !( qr->resultFlags() & QueryResult::ResultFlag_CursorNotFound ) ) {
+ QueryResult *qr = (QueryResult *) response.singleData();
+ if ( !( qr->resultFlags() & mongo::ResultFlag_CursorNotFound ) ) {
if ( qr->cursorId != 0 ) {
lastCursor[ c ] = qr->cursorId;
return;
@@ -336,9 +359,9 @@ void processMessage( Connection& c , Message& m ){
} else {
Connection r = c.reverse();
long long myCursor = lastCursor[ r ];
- QueryResult *qr = (QueryResult *) m.data;
+ QueryResult *qr = (QueryResult *) m.singleData();
long long yourCursor = qr->cursorId;
- if ( ( qr->resultFlags() & QueryResult::ResultFlag_CursorNotFound ) )
+ if ( ( qr->resultFlags() & mongo::ResultFlag_CursorNotFound ) )
yourCursor = 0;
if ( myCursor && !yourCursor )
cerr << "Expected valid cursor in sniffed response, found none" << endl;
@@ -366,7 +389,7 @@ void processDiagLog( const char * file ){
long read = 0;
while ( read < length ){
Message m(pos,false);
- int len = m.data->len;
+ int len = m.header()->len;
DbMessage d(m);
cout << len << " " << d.getns() << endl;
@@ -389,6 +412,9 @@ void usage() {
" or a file containing output from mongod's --diaglog option.\n"
" If no source is specified, mongosniff will attempt to sniff\n"
" from one of the machine's network interfaces.\n"
+ "--objcheck Log hex representation of invalid BSON objects and nothing\n"
+ " else. Spurious messages about invalid objects may result\n"
+ " when there are dropped tcp packets.\n"
"<port0>... These parameters are used to filter sniffing. By default, \n"
" only port 27017 is sniffed.\n"
"--help Print this help message.\n"
@@ -397,6 +423,9 @@ void usage() {
int main(int argc, char **argv){
+ stringstream nullStream;
+ nullStream.clear(ios::failbit);
+
const char *dev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *handle;
@@ -435,6 +464,10 @@ int main(int argc, char **argv){
else
dev = args[ ++i ];
}
+ else if ( arg == string( "--objcheck" ) ) {
+ objcheck = true;
+ outPtr = &nullStream;
+ }
else {
serverPorts.insert( atoi( args[ i ] ) );
}