diff --git a/.gitignore b/.gitignore index 4d7075d..dc1a786 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ # Ignore Doxygen generated files doc/html +/autom4te.cache diff --git a/Doxyfile b/Doxyfile index 583291e..6a3b5f8 100644 --- a/Doxyfile +++ b/Doxyfile @@ -20,7 +20,7 @@ # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. -DOXYFILE_ENCODING = ISO-8859-1 +DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need @@ -32,13 +32,13 @@ PROJECT_NAME = sngrep # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.1 +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = "SIP Messages flow viewer" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not @@ -356,7 +356,7 @@ EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. @@ -544,7 +544,7 @@ SHOW_USED_FILES = YES # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. -#SHOW_DIRECTORIES = NO +SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the @@ -648,7 +648,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = src doc +INPUT = src/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -656,7 +656,7 @@ INPUT = src doc # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. -INPUT_ENCODING = ISO-8859-1 +INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp @@ -750,7 +750,7 @@ INPUT_FILTER = # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = *.lua=/usr/bin/lua2dox +FILTER_PATTERNS = *.lua=/usr/bin/lua2dox # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source @@ -938,7 +938,7 @@ HTML_TIMESTAMP = YES # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. -#HTML_ALIGN_MEMBERS = YES +HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the @@ -1129,7 +1129,7 @@ ENUM_VALUES_PER_LINE = 4 # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. -#USE_INLINE_TREES = NO +USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree @@ -1779,4 +1779,3 @@ GENERATE_LEGEND = YES # the various graphs. DOT_CLEANUP = YES - diff --git a/src/capture.h b/src/capture.h index 11360ed..b55fab8 100644 --- a/src/capture.h +++ b/src/capture.h @@ -181,6 +181,9 @@ capture_offline(); void parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packet); +/** + * @brief Close pcap handler + */ void capture_close(); @@ -191,12 +194,23 @@ capture_close(); int datalink_size(int datalink); +/** + * @brief Open a new dumper file for capture handler + */ pcap_dumper_t * dump_open(const char *dumpfile); +/** + * @brief Store a packet in dump file + * + * File must be previously opened with dump_open + */ void dump_packet(pcap_dumper_t *pd, const struct pcap_pkthdr *header, const u_char *packet); +/** + * @brief Close a dump file + */ void dump_close(pcap_dumper_t *pd); diff --git a/src/capture_tls.c b/src/capture_tls.c index 0719e34..7e7eb61 100644 --- a/src/capture_tls.c +++ b/src/capture_tls.c @@ -105,7 +105,7 @@ PRF(unsigned char *dest, int dlen, unsigned char *pre_master_secret, int plen, u for (i = 0; i < dlen; i++) dest[i] = h_md5[i] ^ h_sha[i]; - return 1; + return 0; } struct SSLConnection * @@ -354,7 +354,7 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment) (unsigned char *) "master secret", SEED, sizeof(struct Random) * 2); memcpy(SEED, &conn->server_random, sizeof(struct Random)); - memcpy(SEED + sizeof(struct Random), &conn->client_random, 32); + memcpy(SEED + sizeof(struct Random), &conn->client_random, sizeof(struct Random)); // Generate MACs, Write Keys and IVs PRF((unsigned char *) &conn->key_material, sizeof(struct tls_data), diff --git a/src/capture_tls.h b/src/capture_tls.h index d363bd6..2bce01b 100644 --- a/src/capture_tls.h +++ b/src/capture_tls.h @@ -40,37 +40,60 @@ #include #include "capture.h" +//! Cast two bytes into decimal (Big Endian) #define UINT16_INT(i) ((i.x[0] << 8) | i.x[1]) +//! Cast three bytes into decimal (Big Endian) #define UINT24_INT(i) ((i.x[0] << 16) | (i.x[1] << 8) | i.x[2]) +//! One byte unsigned integer typedef unsigned char uint8; +//! Two bytes unsigned integer typedef struct uint16 { unsigned char x[2]; } uint16; +//! Three bytes unsigned integer typedef struct uint24 { unsigned char x[3]; } uint24; +//! Four bytes unsigned interger typedef struct uint32 { unsigned char x[4]; } uint32; + +//! One byte generic type typedef unsigned char opaque; +//! SSLConnections states enum SSLConnectionState { + //! Initial SYN packet has been received from client TCP_STATE_SYN = 0, + //! SYN/ACK packet has been sent from the server TCP_STATE_SYN_ACK, + //! Client ACK'ed the connection TCP_STATE_ACK, + //! Connection is up, now SSL handshake should start! TCP_STATE_ESTABLISHED, + //! Connection about to end TCP_STATE_FIN, + //! Connection closed TCP_STATE_CLOSED }; +/** + * XXX We could remove this enum and HandshakeType because + * they are not really used as enums. + * Enumerated values are, in most cases, stored as 4 bytes integer + * while the value it represents in SSL headers is only one byte, + * so we may use SSL3_ defines instead. + */ +//! ContentType values as defined in RFC5246 enum ContentType { change_cipher_spec = SSL3_RT_CHANGE_CIPHER_SPEC, @@ -79,6 +102,7 @@ enum ContentType application_data = SSL3_RT_APPLICATION_DATA }; +//! HanshakeType values as defined in RFC5246 enum HandshakeType { hello_request = SSL3_MT_HELLO_REQUEST, @@ -92,12 +116,14 @@ enum HandshakeType finished = SSL3_MT_FINISHED }; +//! ProtocolVersion header as defined in RFC5246 struct ProtocolVersion { uint8 major; uint8 minor; }; +//! TLSPlaintext record structure struct TLSPlaintext { uint8 type; @@ -105,18 +131,21 @@ struct TLSPlaintext uint16 length; }; +//! Hanshake record structure struct Handshake { uint8 type; uint24 length; }; +//! Handshake random structure struct Random { uint32 gmt_unix_time; opaque random_bytes[28]; }; +//! ClientHello type in Handshake records struct ClientHello { struct ProtocolVersion client_version; @@ -126,6 +155,7 @@ struct ClientHello // Extension extensions; }; +//! ServerHello type in Handshake records struct ServerHello { struct ProtocolVersion server_version; @@ -151,12 +181,18 @@ struct EncryptedPreMasterSecret uint8 pre_master_secret[128]; }; +//! ClientKeyExchange type in Handshake records struct ClientKeyExchange { uint16 length; struct EncryptedPreMasterSecret exchange_keys; }; +/** + * Structure to store all information from a TLS + * connection. This is also used as linked list + * node. + */ struct SSLConnection { //! Connection status @@ -166,10 +202,13 @@ struct SSLConnection //! Data is encrypted flag int encrypted; - //! Source and Destiny IP:port + //! Client IP address struct in_addr client_addr; + //! Server IP address struct in_addr server_addr; + //! Client port u_short client_port; + //! Server port u_short server_port; SSL *ssl; @@ -196,39 +235,166 @@ struct SSLConnection struct SSLConnection *next; }; +/** + * @brief P_hash expansion function as defined in RFC5246 + * + * This function will expand Secret and Seed into output using digest + * hash function. The amount of data generated will be determined by output + * length (dlen). + * + * @param digest Digest name to get the hash function + * @param dest Destiny of hash function result. Memory must be already allocated + * @param dlen Destiny length in bytes + * @param secret Input for the hash function + * @param sslen Secret length in bytes + * @param seed Input for the hash function + * @param slen Seed length in bytes + * @return Output bytes + */ int P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret, int sslen, unsigned char *seed, int slen); +/** + * @brief Pseudorandom Function as defined in RFC5246 + * + * This function will generate MasterSecret and KeyMaterial data from PreMasterSecret and Seed + * + * @param dest Destiny of PRF function result. Memory must be already allocated + * @param dlen Destiny length in bytes + * @param pre_master_secret PreMasterSecret decrypted from ClientKeyExchange Handhsake record + * @param pslen PreMasterSecret length in bytes + * @param label Fixed ASCII string + * @param seed Concatenation of Random data from Hello Handshake records + * @param slen Seed length in bytes + * @return 0 in call cases + */ int PRF(unsigned char *dest, int dlen, unsigned char *pre_master_secret, int plen, unsigned char *label, unsigned char *seed, int slen); +/** + * @brief Create a new SSLConnection + * + * This will allocate enough memory to store all connection data + * from a detected SSL connection. This will also add this structure to + * the connections linked list. + * + * @param caddr Client address + * @param cport Client port + * @param saddr Server address + * @param sport Server port + * @return a pointer to a new allocated SSLConnection structure + */ struct SSLConnection * tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr, u_short sport); +/** + * @brief Destroys an existing SSLConnection + * + * This will free all allocated memory of SSLConnection also removing + * the connection from connections list. + * + * @param conn Existing connection pointer + */ void tls_connection_destroy(struct SSLConnection *conn); +/** + * @brief Check if given keyfile is valid + * + * This can be used to check if a file contains valid RSA data + * + * @param keyfile Absolute path the keyfile + * @return true if file contains RSA private info, false otherwise + */ bool tls_check_keyfile(const char *keyfile); +/** + * @brief Determines packet direction + * + * Determine if the given address is from client or server. + * + * @param conn Existing connection pointer + * @param addr Client or server address + * @param port Client or server port + * @return 0 if address belongs to client, 1 to server or -1 otherwise + */ int tls_connection_dir(struct SSLConnection *conn, struct in_addr addr, u_short port); +/** + * @brief Find a connection + * + * Try to find connection data for a given address and port. + * This address:port convination can be the client or server one. + * + * @param addr Client or server address + * @param port Client or server port + * @return an existing Connection pointer or NULL if not found + */ struct SSLConnection* tls_connection_find(struct in_addr addr, u_short port); +/** + * @brief Process a TCP segment to check TLS data + * + * Check if a TCP segment contains TLS data. In case a TLS record is found + * process it and return decrypted data if case of application_data record. + * + * @param ip Pointer to ip header of the packet + * @param out Pointer to the output char array. Memory must be already allocated + * @param out Number of bytes returned by this function + * @return 0 in all cases + */ int tls_process_segment(const struct nread_ip *ip, uint8 **out, int *outl); +/** + * @brief Process TLS record data + * + * Process a TLS record + * - If the record type is Handshake process it in tls_process_record_handshake + * - If the record type is Application Data process it in tls_process_record_data + * + * @param conn Existing connection pointer + * @param payload Packet peyload + * @param len Payload length + * @param out pointer to store decryted data + * @param outl decrypted data length + * @return Decrypted data length + */ int tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int len, uint8 **out, int *outl); +/** + * @brief Process TLS Handshake record types + * + * Process all types of Handshake records to store and compute all required + * data to decrypt application data packets + * + * @param conn Existing connection pointer + * @param fragment Handshake record data + * @return 0 in all cases + */ int tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment); +/** + * @brief Process TLS ApplicationData record types + * + * Process application data record, trying to decrypt it with connection + * information + * + * @param conn Existing connection pointer + * @param fragment Application record data + * @param len record length in bytes + * @param out pointer to store decryted data + * @param outl decrypted data length + * @return decoded data length + */ int tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len, uint8 **out, int *outl); diff --git a/src/group.h b/src/group.h index a52af1f..3057052 100644 --- a/src/group.h +++ b/src/group.h @@ -46,40 +46,108 @@ typedef struct sip_call_group sip_call_group_t; * same call flow. Instead of displaying a call flow, we will display * a calls group flow. * - * @note Trying to merge extended and normal callflow into a unique - * panel and allowing multiple dialog in a callflow. - * * @fixme Remove 1024 "limitation" */ struct sip_call_group { + //! Calls array in the group sip_call_t *calls[1024]; + //! Calls counter int callcnt; + //! Color of the last printed call in mode Color-by-Call int color; + //! Only consider SDP messages from Calls bool sdp_only; }; +/** + * @brief Create a new groupt to hold Calls in it + * + * Allocate memory to create a new calls group + * + * @todo Create a call group destructor + * @return Pointer to a new group + */ sip_call_group_t * call_group_create(); +/** + * @brief Add a Call to the group + * + * @param group Pointer to an existing group + * @param call Pointer to an existing call + */ void call_group_add(sip_call_group_t *group, sip_call_t *call); +/** + * @brief Remove a call from the group + * + * @param group Pointer to an existing group + * @param call Pointer to an existing call + */ void call_group_del(sip_call_group_t *group, sip_call_t *call); +/** + * @brief Check if a call is in the group + * + * @param group Pointer to an existing group + * @param call Pointer to an existing call + * @return 1 if the call is in the group, 0 otherwise + */ int call_group_exists(sip_call_group_t *group, sip_call_t *call); +/** + * @brief Return the color pair number of a call + * + * When color by callid mode is enabled, this function will + * return the color pair number of the call depending its + * position inside the call + * + * @param group Pointer to an existing group + * @param call Pointer to an existing call + * @return Color pair number + */ int call_group_color(sip_call_group_t *group, sip_call_t *call); +/** + * @brief Return the next call in the group + * + * Return then next call after the given call parameter. + * If NULL is used as parameter, return the first call. + * It will return NULL if last call is given as parameter. + * + * @param group Pointer to an existing group + * @param call Pointer to an existing call or NULL + * @return Next call of the group, or NULL + */ sip_call_t * call_group_get_next(sip_call_group_t *group, sip_call_t *call); +/** + * @brief Return message count in the group + * + * Return the sum of messages of all calls in the group + * + * @param group Pointer to an existing group + * @return How many messages have the calls in the group + */ int call_group_msg_count(sip_call_group_t *group); +/** + * @brief Return Message position in the group + * + * Return how many messages are before the given message + * sorting all messages in all group calls by timestamp + * + * @param group Pointer to an existing group + * @param msg A sip message from a call in the group + * @return The position of given message in the group + */ int call_group_msg_number(sip_call_group_t *group, sip_msg_t *msg); @@ -91,11 +159,22 @@ call_group_msg_number(sip_call_group_t *group, sip_msg_t *msg); * * @param callgroup SIP call group structure * @param msg Actual SIP msg from any call of the group (can be NULL) - * @return Next chronological message in the group + * @return Next chronological message in the group or NULL */ sip_msg_t * call_group_get_next_msg(sip_call_group_t *group, sip_msg_t *msg); +/** + * @brief Check if a message is older than other + * + * @todo Move this to sip.h + * + * @param one SIP message pointer + * @param two SIP message pointer + * @return 0 if the messages has the same timestamp + * @return 1 if one is older than two + * @return 2 if two is older than one + */ int sip_msg_is_older(sip_msg_t *one, sip_msg_t *two); diff --git a/src/option.h b/src/option.h index 3f46d16..fa8f0c8 100644 --- a/src/option.h +++ b/src/option.h @@ -189,6 +189,18 @@ is_option_disabled(const char *opt); int is_ignored_value(const char *field, const char *fvalue); +/** + * @brief Toggle a boolean option + * + * An option is considered disabled if it has "off" or "0" as value, + * otherwise will be enabled. + * This function will set off for those options with on value, and + * viceversa. + * + * @todo Implement also for "1"/"0" options + * + * @param option Name of configuration option + */ void toggle_option(const char *option); diff --git a/src/ui_call_flow.h b/src/ui_call_flow.h index fe7d3af..6619856 100644 --- a/src/ui_call_flow.h +++ b/src/ui_call_flow.h @@ -114,15 +114,47 @@ call_flow_redraw_required(PANEL *panel, sip_msg_t *msg); int call_flow_draw(PANEL *panel); + +/** + * @brief Draw the footer of the panel with keybindings info + * + * @param panel Ncurses panel pointer + */ void call_flow_draw_footer(PANEL *panel); +/** + * @brief Draw the visible columns in panel window + * + * @param panel Ncurses panel pointer + */ int call_flow_draw_columns(PANEL *panel); +/** + * @brief Draw the message arrow in the given line + * + * Draw the given message arrow in the given line. + * This function will calculate origin and destriny coordinates + * base on message information. Each message use two lines + * + * @param panel Ncurses panel pointer + * @param msg Message data to draw + * @param cline Window line to draw the message + * @return 0 if arrow is drawn, 1 otherwise + */ int call_flow_draw_message(PANEL *panel, sip_msg_t *msg, int cline); +/** + * @brief Draw raw panel with message payload + * + * Draw the given message payload into the raw window. + * + * @param panel Ncurses panel pointer + * @param msg Message data to draw + * @return 0 in all cases + */ int call_flow_draw_raw(PANEL *panel, sip_msg_t *msg); @@ -163,9 +195,29 @@ call_flow_help(PANEL *panel); int call_flow_set_group(sip_call_group_t *group); +/** + * @brief Add a new column (if required) + * + * Check if the given callid and address has already a column. + * If not, create a new call for that callid/address + * Each column has one address and two callids (unless split mode + * is disabled) + * + * @param panel Ncurses panel pointer + * @param callid Call-Id header of SIP payload + * @param addr Address:port string + */ void call_flow_column_add(PANEL *panel, const char *callid, const char *addr); +/** + * @brief Get a flow column data + * + * @param panel Ncurses panel pointer + * @param callid Call-Id header of SIP payload + * @param addr Address:port string + * @return column structure pointer or NULL if not found + */ call_flow_column_t * call_flow_column_get(PANEL *panel, const char *callid, const char *addr); diff --git a/src/ui_call_raw.h b/src/ui_call_raw.h index 89d7406..8d0a483 100644 --- a/src/ui_call_raw.h +++ b/src/ui_call_raw.h @@ -88,6 +88,15 @@ call_raw_redraw_required(PANEL *panel, sip_msg_t *msg); int call_raw_draw(PANEL *panel); +/** + * @brief Draw a message in call Raw + * + * Draw a new message in the Raw pad. + * + * @param panel Ncurses panel pointer + * @param msg New message to be printed + * @return 0 in call cases + */ int call_raw_print_msg(PANEL *panel, sip_msg_t *msg);