# $Id:$ %include bro.pac %extern{ #include "SOCKS.h" %} analyzer SOCKS withcontext { connection: SOCKS_Conn; flow: SOCKS_Flow; }; type SOCKS_Message(is_orig: bool) = case is_orig of { true -> request: SOCKS_Request; false -> reply: SOCKS_Reply; }; type SOCKS_Request = record { version: uint8; command: uint8; port: uint16; addr: uint32; user: uint8[] &until($element == 0); host: case v4a of { true -> name: uint8[] &until($element == 0); # v4a false -> empty: uint8[] &length=0; } &requires(v4a); # FIXME: Can this be non-zero? If so we need to keep it for the # next analyzer. rest: bytestring &restofdata; } &byteorder = bigendian &let { v4a: bool = (addr <= 0x000000ff); process_request: bool = $context.flow.socks_request(command, addr, empty, port, user); }; type SOCKS_Reply = record { zero: uint8; status: uint8; port: uint16; addr: uint32; # FIXME: Can this be non-zero? If so we need to keep it for the # next analyzer. rest: bytestring &restofdata; } &byteorder = bigendian &let { process_reply: bool = $context.flow.socks_reply((status == 0x5a), addr, port); }; connection SOCKS_Conn(bro_analyzer: BroAnalyzer) { upflow = SOCKS_Flow(true); downflow = SOCKS_Flow(false); }; %code{ StringVal* array_to_string(vector *a) { int len = a->size(); char tmp[len]; char *s = tmp; for ( vector::iterator i = a->begin(); i != a->end(); *s++ = *i++ ); while ( len > 0 && tmp[len-1] == '\0' ) --len; return new StringVal(len, tmp); } %} flow SOCKS_Flow(is_orig: bool) { datagram = SOCKS_Message(is_orig) withcontext(connection, this); function socks_request(cmd: uint8, dstaddr: uint32, dstname: uint8[], p: uint16, user: uint8[]) : bool %{ bro_event_socks_request(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), new Val(cmd, TYPE_INT), v4_addr_to_addr(htonl(dstaddr)), array_to_string(dstname), new PortVal(p | TCP_PORT_MASK), array_to_string(user)); static_cast(connection()->bro_analyzer())->EndpointDone(true); return true; %} function socks_reply(granted: bool, dst: uint32, p: uint16) : bool %{ bro_event_socks_reply(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), granted, v4_addr_to_addr(htonl(dst)), new PortVal(p | TCP_PORT_MASK)); static_cast(connection()->bro_analyzer())->EndpointDone(false); return true; %} };