Commit c4eab721 authored by Victor Seva's avatar Victor Seva

Imported Upstream version 0.3.2

parent da713581
2015-05-17 Ivan Alonso <kaian@irontec.com>
* sngrep 0.3.2 released
* Fixed sources compilation for BSD systems
* Fixed a bug where Contact header was displayed in SIP From column
* Fixed some keybindings in filter and save panels
* Improved SIP packet detection from payload
* Highlight local address columns in Call Flow
2015-04-14 Ivan Alonso <kaian@irontec.com>
* sngrep 0.3.1 released
......
AC_PREREQ([2.59])
AC_INIT([sngrep], [0.3.1], [kaian@irontec.com], [sngrep], [http://www.irontec.com/])
AC_INIT([sngrep], [0.3.2], [kaian@irontec.com], [sngrep], [http://www.irontec.com/])
AM_INIT_AUTOMAKE([1.9])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_HEADERS([src/config.h])
......
......@@ -3,7 +3,7 @@
.\" Copyright (c) 2013-2015 Ivan Alonso <kaian@irontec.com>
.\" Copyright (c) 2013-2015 Irontec S.L.
.TH SNGREP 8 "March 2015" "sngrep 0.3.1"
.TH SNGREP 8 "March 2015" "sngrep 0.3.2"
.SH NAME
......@@ -11,7 +11,7 @@ sngrep \- SIP Messages flow viewer
.SH SYNOPSIS
.B sngrep [-hVciv] [ -IO
.B sngrep [-hVcivlkNq] [ -IO
.I pcap_dump
.B ] [ -d
.I dev
......@@ -79,6 +79,14 @@ Use private keyfile to decrypt TLS packets.
.I -l limit
Change default capture limit (10000 dialogs)
.TP
.I -N
Don't display sngrep interface, just capture
.TP
.I -q
Don't print captured dialogs in no interface mode
.TP
.I match expression
Match given expression in Messages' payload. If one request message matches the
......
......@@ -136,6 +136,8 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
{
// Datalink Header size
int size_link;
// IP version
uint32_t ip_ver;
// IP header data
struct ip *ip4;
#ifdef WITH_IPV6
......@@ -148,14 +150,24 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
uint32_t ip_len;
// IP header size
uint32_t size_ip;
// Fragment offset
uint16_t ip_off = 0;
// Fragmentation flag
uint8_t ip_frag = 0;
// Fragmentation offset
uint16_t ip_frag_off = 0;
//! Source Address
char ip_src[INET6_ADDRSTRLEN + 1];
//! Destination Address
char ip_dst[INET6_ADDRSTRLEN + 1];
// UDP header data
struct nread_udp *udp;
struct udphdr *udp;
// UDP header size
uint16_t udp_size;
// TCP header data
struct nread_tcp *tcp;
struct tcphdr *tcp;
// TCP header size
uint16_t tcp_size;
// Packet payload data
u_char *msg_payload = NULL;
// Packet payload size
......@@ -188,13 +200,20 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
ip6 = (struct ip6_hdr*)(packet + size_link);
#endif
switch(ip4->ip_v) {
// Get IP version
ip_ver = ip4->ip_v;
switch(ip_ver) {
case 4:
size_ip = ip4->ip_hl * 4;
ip_proto = ip4->ip_p;
ip_len = ntohs(ip4->ip_len);
inet_ntop(AF_INET, &ip4->ip_src, ip_src, sizeof(ip_src));
inet_ntop(AF_INET, &ip4->ip_dst, ip_dst, sizeof(ip_dst));
ip_off = ntohs(ip4->ip_off);
ip_frag = ip_off & (IP_MF | IP_OFFMASK);
ip_frag_off = (ip_frag) ? (ip_off & IP_OFFMASK) * 8 : 0;
break;
#ifdef WITH_IPV6
case 6:
......@@ -203,8 +222,15 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
ip_len = ntohs(ip6->ip6_plen);
inet_ntop(AF_INET6, &ip6->ip6_src, ip_src, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &ip6->ip6_dst, ip_dst, INET6_ADDRSTRLEN);
if (ip_proto == IPPROTO_FRAGMENT) {
struct ip6_frag *ip6f = (struct ip6_frag *) (ip6 + ip_len);
ip_frag_off = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
}
break;
#endif
default:
return;
}
// Only interested in UDP packets
......@@ -213,42 +239,46 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
transport = 0;
// Get UDP header
udp = (struct nread_udp*) (packet + size_link + size_ip);
udp = (struct udphdr*) (packet + size_link + size_ip);
udp_size = (ip_frag_off) ? 0 : sizeof(struct udphdr);
// Set packet ports
sport = udp->udp_sport;
dport = udp->udp_dport;
sport = udp->uh_sport;
dport = udp->uh_dport;
size_payload = htons(udp->udp_hlen) - SIZE_UDP;
if (size_payload > 0 ) {
size_payload = htons(udp->uh_ulen) - udp_size;
if ((int32_t)size_payload > 0 ) {
// Get packet payload
msg_payload = malloc(size_payload + 1);
memset(msg_payload, 0, size_payload + 1);
memcpy(msg_payload, (u_char *) (packet + size_link + size_ip + SIZE_UDP), size_payload);
memcpy(msg_payload, (u_char *) (packet + size_link + size_ip + udp_size), size_payload);
}
// Total packet size
size_packet = size_link + size_ip + SIZE_UDP + size_payload;
size_packet = size_link + size_ip + udp_size + size_payload;
} else if (ip_proto == IPPROTO_TCP) {
// Set transport TCP
transport = 1;
tcp = (struct nread_tcp*) (packet + size_link + size_ip);
tcp = (struct tcphdr*) (packet + size_link + size_ip);
tcp_size = (ip_frag_off) ? 0 : (tcp->th_off * 4);
// Set packet ports
sport = tcp->th_sport;
dport = tcp->th_dport;
// We're only interested in packets with payload
size_payload = ip_len - (size_ip + SIZE_TCP);
if (size_payload > 0) {
size_payload = ip_len - (size_ip + tcp_size);
if ((int32_t)size_payload > 0) {
// Get packet payload
msg_payload = malloc(size_payload + 1);
memset(msg_payload, 0, size_payload + 1);
memcpy(msg_payload, (u_char *) (packet + size_link + size_ip + SIZE_TCP), size_payload);
memcpy(msg_payload, (u_char *) (packet + size_link + size_ip + tcp_size), size_payload);
}
// Total packet size
size_packet = size_link + size_ip + SIZE_TCP + size_payload;
size_packet = size_link + size_ip + tcp_size + size_payload;
#ifdef WITH_OPENSSL
if (!msg_payload || !strstr((const char*) msg_payload, "SIP/2.0")) {
if (capture_get_keyfile()) {
......@@ -556,7 +586,7 @@ is_local_address(in_addr_t address)
for (device = capinfo.devices; device; device = device->next) {
for (dev_addr = device->addresses; dev_addr; dev_addr = dev_addr->next)
if (((struct sockaddr_in*)dev_addr)->sin_addr.s_addr == address)
if (dev_addr->addr && dev_addr->addr->sa_family == AF_INET && ((struct sockaddr_in*)dev_addr->addr)->sin_addr.s_addr == address)
return 1;
}
return 0;
......
......@@ -40,10 +40,13 @@
#include <time.h>
#if defined(__linux__)
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#ifndef __FAVOR_BSD
#define __FAVOR_BSD
#endif
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#endif
#if defined(BSD) || defined (__OpenBSD__)
......@@ -52,12 +55,16 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#endif
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
//! Capture modes
enum capture_status {
CAPTURE_ONLINE = 0,
......@@ -122,50 +129,6 @@ struct capture_info {
pthread_t capture_t;
};
//! UDP headers are always exactly 8 bytes
#define SIZE_UDP 8
//! TCP headers size
#define SIZE_TCP TH_OFF(tcp)*4
/**
* @brief UDP data structure
*/
struct nread_udp {
//! source port
u_short udp_sport;
//! destination port
u_short udp_dport;
//! UDP header length
u_short udp_hlen;
//! UDP Checksum
u_short udp_chksum;
};
/* TCP header */
typedef u_int tcp_seq;
struct nread_tcp {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_char th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
};
/**
* @brief Online capture function
*
......
......@@ -150,7 +150,24 @@ tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr,
void
tls_connection_destroy(struct SSLConnection *conn)
{
// TODO
struct SSLConnection *c;
// Remove connection from connections list
if (conn == connections) {
connections = conn->next;
} else {
for (c = connections; c; c = c->next) {
if (c->next == conn) {
c->next = conn->next;
break;
}
}
}
// Deallocate connection memory
SSL_CTX_free(conn->ssl_ctx);
SSL_free(conn->ssl);
free(conn);
}
/**
......@@ -209,15 +226,25 @@ tls_connection_find(struct in_addr addr, u_short port)
}
int
tls_process_segment(const struct ip *ip, uint8 **out, int *outl)
tls_process_segment(const struct ip *ip, uint8 **out, uint32_t *outl)
{
struct SSLConnection *conn;
struct nread_tcp *tcp;
struct tcphdr *tcp;
uint16_t tcp_size;
const uint8 *payload;
uint16_t ip_off;
uint8_t ip_frag;
uint16_t ip_frag_off;
int len;
// Process IP offset
ip_off = ntohs(ip->ip_off);
ip_frag = ip_off & (IP_MF | IP_OFFMASK);
ip_frag_off = (ip_frag) ? (ip_off & IP_OFFMASK) * 8 : 0;
// Get TCP header
tcp = (struct nread_tcp *) ((uint8 *) ip + (ip->ip_hl * 4));
tcp = (struct tcphdr *) ((uint8 *) ip + (ip->ip_hl * 4));
tcp_size = (ip_frag_off) ? 0 : (tcp->th_off * 4);
// Try to find a session for this ip
if ((conn = tls_connection_find(ip->ip_src, tcp->th_sport))) {
......@@ -239,9 +266,10 @@ tls_process_segment(const struct ip *ip, uint8 **out, int *outl)
case TCP_STATE_ACK:
case TCP_STATE_ESTABLISHED:
// Process data segment!
payload = (uint8 *) tcp + SIZE_TCP;
len = ntohs(ip->ip_len) - (ip->ip_hl * 4) - SIZE_TCP;
tls_process_record(conn, payload, len, out, outl);
payload = (uint8 *) tcp + tcp_size;
len = ntohs(ip->ip_len) - (ip->ip_hl * 4) - tcp_size;
if (tls_process_record(conn, payload, len, out, outl) != 0)
return 1;
break;
case TCP_STATE_FIN:
case TCP_STATE_CLOSED:
......@@ -261,7 +289,7 @@ tls_process_segment(const struct ip *ip, uint8 **out, int *outl)
int
tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int len, uint8 **out,
int *outl)
uint32_t *outl)
{
struct TLSPlaintext *record;
int record_len;
......@@ -283,7 +311,8 @@ tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int l
switch (record->type) {
case handshake:
// Hanshake Record, Try to get MasterSecret data
tls_process_record_handshake(conn, fragment);
if (tls_process_record_handshake(conn, fragment) != 0)
return 1;
break;
case change_cipher_spec:
// From now on, this connection will be encrypted using MasterSecret
......@@ -304,7 +333,7 @@ tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int l
if (len > record_len)
return tls_process_record(conn, payload + record_len, len - record_len, out, outl);
return *outl;
return 0;
}
int
......@@ -335,6 +364,7 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
if (!(clienthello->client_version.major == 0x03
&& clienthello->client_version.minor == 0x01)) {
tls_connection_destroy(conn);
return 1;
}
break;
case server_hello:
......@@ -346,8 +376,10 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
body + sizeof(struct ServerHello) + serverhello->session_id_length,
sizeof(uint16));
// Check if we have a handled cipher
if (tls_connection_load_cipher(conn) != 0)
if (tls_connection_load_cipher(conn) != 0) {
tls_connection_destroy(conn);
return 1;
}
break;
case certificate:
case certificate_request:
......@@ -401,7 +433,7 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
if (conn->encrypted) {
// Encrypted Hanshake Message
unsigned char *decoded = malloc(48);
int decodedlen;
uint32_t decodedlen;
tls_process_record_data(conn, fragment, 48, &decoded, &decodedlen);
free(decoded);
}
......@@ -414,7 +446,7 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
int
tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len,
uint8 **out, int *outl)
uint8 **out, uint32_t *outl)
{
EVP_CIPHER_CTX *evp;
unsigned char pad;
......
......@@ -352,7 +352,7 @@ tls_connection_find(struct in_addr addr, u_short port);
* @return 0 in all cases
*/
int
tls_process_segment(const struct ip *ip, uint8 **out, int *outl);
tls_process_segment(const struct ip *ip, uint8 **out, uint32_t *outl);
/**
* @brief Process TLS record data
......@@ -370,7 +370,7 @@ tls_process_segment(const struct ip *ip, uint8 **out, int *outl);
*/
int
tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int len, uint8 **out,
int *outl);
uint32_t *outl);
/**
* @brief Process TLS Handshake record types
......@@ -400,7 +400,7 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
*/
int
tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len,
uint8 **out, int *outl);
uint8 **out, uint32_t *outl);
/**
......
......@@ -33,7 +33,7 @@
#include "filter.h"
//! Storage of filter information
filter_t filters[FILTER_COUNT];
filter_t filters[FILTER_COUNT] = {};
int
filter_set(int type, const char *expr)
......
......@@ -30,6 +30,7 @@
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "ui_manager.h"
#include "option.h"
#include "keybinding.h"
......@@ -64,7 +65,7 @@ key_bindings_init()
key_bind_action(ACTION_BEGIN, KEY_CTRL('A'));
key_bind_action(ACTION_END, KEY_END);
key_bind_action(ACTION_END, KEY_CTRL('E'));
key_bind_action(ACTION_PREV_FIELD, KEY_TAB);
key_bind_action(ACTION_PREV_FIELD, KEY_UP);
key_bind_action(ACTION_NEXT_FIELD, KEY_TAB);
key_bind_action(ACTION_NEXT_FIELD, KEY_DOWN);
key_bind_action(ACTION_RESIZE_SCREEN, KEY_RESIZE);
......
......@@ -83,6 +83,7 @@ init_options()
set_option_value("cf.splitcallid", "off");
set_option_value("cf.highlight", "bold");
set_option_value("cf.scrollstep", "4");
set_option_value("cf.localhighlight", "on");
// Default options for Call Raw screen
set_option_value("cr.scrollstep", "10");
......@@ -102,14 +103,7 @@ init_options()
set_option_value("capture.lookup", "off");
// Set default filter options
set_option_value("filter.enable", "off");
set_option_value("filter.REGISTER", "on");
set_option_value("filter.INVITE", "on");
set_option_value("filter.SUBSCRIBE", "on");
set_option_value("filter.NOTIFY", "on");
set_option_value("filter.OPTIONS", "on");
set_option_value("filter.PUBLISH", "on");
set_option_value("filter.MESSAGE", "on");
set_option_value("filter.methods", "REGISTER,INVITE,SUBSCRIBE,NOTIFY,OPTIONS,PUBLISH,MESSAGE");
// Print defualt keys in bottom bar
set_option_value("hintkeyalt", "off");
......
......@@ -65,7 +65,7 @@ sip_init(int limit, int only_calls, int no_incomplete)
// Initialize calls lock
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#if defined(PTHREAD_MUTEX_RECURSIVE) || defined(__FreeBSD__)
#if defined(PTHREAD_MUTEX_RECURSIVE) || defined(__FreeBSD__) || defined(BSD) || defined (__OpenBSD__)
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#else
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
......@@ -74,14 +74,15 @@ sip_init(int limit, int only_calls, int no_incomplete)
// Initialize payload parsing regexp
match_flags = REG_EXTENDED | REG_ICASE | REG_NEWLINE;
regcomp(&calls.reg_callid, "^(Call-ID|i): (.+)\r$", match_flags);
regcomp(&calls.reg_xcallid, "^(X-Call-ID|X-CID): (.+)\r$", match_flags);
regcomp(&calls.reg_response, "^SIP/2.0 (([0-9]{3}) .+)\r$", match_flags);
regcomp(&calls.reg_cseq, "CSeq: ([0-9]+) (.+)\r$", match_flags);
regcomp(&calls.reg_from, "(From|f): [^:]*:(([^@]+)@?[^\r>;]+)", match_flags);
regcomp(&calls.reg_to, "(To|t): [^:]*:(([^@]+)@?[^\r>;]+)", match_flags);
regcomp(&calls.reg_sdp_addr, "^c=[^[:space:]]+ [^[:space:]]+ (.+)\r$", match_flags);
regcomp(&calls.reg_sdp_port, "^m=[^[:space:]]+ ([0-9]+)", match_flags);
regcomp(&calls.reg_method, "^([a-zA-Z]+) sip:\\S+ SIP/2.0\r", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_callid, "^(Call-ID|i):\\s*(\\S+)\r$", match_flags);
regcomp(&calls.reg_xcallid, "^(X-Call-ID|X-CID):\\s*(\\S+)\r$", match_flags);
regcomp(&calls.reg_response, "^SIP/2.0\\s*(([0-9]{3}) [^\r]+)\r", match_flags & ~REG_NEWLINE);
regcomp(&calls.reg_cseq, "^CSeq:\\s*([0-9]+) .+\r$", match_flags);
regcomp(&calls.reg_from, "^(From|f):\\s*[^:]*:(([^@]+)@?[^\r>;]+)", match_flags);
regcomp(&calls.reg_to, "^(To|t):\\s*[^:]*:(([^@]+)@?[^\r>;]+)", match_flags);
regcomp(&calls.reg_sdp_addr, "^c=\\S+ \\S+ (.+)\r$", match_flags);
regcomp(&calls.reg_sdp_port, "^m=\\S+ ([0-9]+)", match_flags);
}
......@@ -234,6 +235,15 @@ sip_load_message(const struct pcap_pkthdr *header, const char *src, u_short spor
return NULL;
}
// Get Method and request for the following checks
// There is no need to parse all payload at this point
// If no response or request code is found, this is not a SIP message
if (!msg_get_reqresp(msg)) {
// Deallocate message memory
sip_msg_destroy(msg);
return NULL;
}
// Store sorce address. Prefix too long IPv6 addresses with two dots
if (strlen(src) > 15) {
sprintf(msg->src, "..%s", src + strlen(src) - 13);
......@@ -268,10 +278,6 @@ sip_load_message(const struct pcap_pkthdr *header, const char *src, u_short spor
return NULL;
}
// Get Method and request for the following checks
// There is no need to parse all payload at this point
msg_get_reqresp(msg);
// User requested only INVITE starting dialogs
if (calls.only_calls) {
if (msg->reqresp != SIP_METHOD_INVITE) {
......@@ -567,7 +573,7 @@ int
msg_get_reqresp(sip_msg_t *msg)
{
regmatch_t pmatch[3];
char reqresp[20], cseq[11];
char reqresp[20];
const char *payload = msg->payload;
// If not already parsed
......@@ -576,10 +582,8 @@ msg_get_reqresp(sip_msg_t *msg)
memset(reqresp, 0, sizeof(reqresp));
// Method & CSeq
if (regexec(&calls.reg_cseq, payload, 3, pmatch, 0) == 0) {
sprintf(cseq, "%.*s", pmatch[1].rm_eo - pmatch[1].rm_so, payload + pmatch[1].rm_so);
msg->cseq = atoi(cseq);
sprintf(reqresp, "%.*s", pmatch[2].rm_eo - pmatch[2].rm_so, payload + pmatch[2].rm_so);
if (regexec(&calls.reg_method, payload, 2, pmatch, 0) == 0) {
sprintf(reqresp, "%.*s", pmatch[1].rm_eo - pmatch[1].rm_so, payload + pmatch[1].rm_so);
msg_set_attribute(msg, SIP_ATTR_METHOD, reqresp);
}
......@@ -600,7 +604,7 @@ int
msg_parse_payload(sip_msg_t *msg, const char *payload)
{
regmatch_t pmatch[4];
char date[12], time[20];
char date[12], time[20], cseq[11];
// If message has already been parsed, we've finished
if (msg->parsed)
......@@ -609,6 +613,12 @@ msg_parse_payload(sip_msg_t *msg, const char *payload)
// Get Method and request for the following checks
msg_get_reqresp(msg);
// CSeq
if (regexec(&calls.reg_cseq, payload, 2, pmatch, 0) == 0) {
sprintf(cseq, "%.*s", pmatch[1].rm_eo - pmatch[1].rm_so, payload + pmatch[1].rm_so);
msg->cseq = atoi(cseq);
}
// X-Call-Id
if (regexec(&calls.reg_xcallid, payload, 3, pmatch, 0) == 0) {
msg_set_attribute(msg, SIP_ATTR_XCALLID, "%.*s", pmatch[2].rm_eo - pmatch[2].rm_so, payload + pmatch[2].rm_so);
......@@ -894,6 +904,14 @@ sip_method_str(enum sip_methods method)
return "BYE";
case SIP_METHOD_ACK:
return "ACK";
case SIP_METHOD_PRACK:
return "PRACK";
case SIP_METHOD_INFO:
return "INFO";
case SIP_METHOD_REFER:
return "REFER";
case SIP_METHOD_UPDATE:
return "UPDATE";
case SIP_METHOD_SENTINEL:
return "";
}
......
......@@ -55,6 +55,10 @@ enum sip_methods {
SIP_METHOD_CANCEL,
SIP_METHOD_BYE,
SIP_METHOD_ACK,
SIP_METHOD_PRACK,
SIP_METHOD_INFO,
SIP_METHOD_REFER,
SIP_METHOD_UPDATE,
SIP_METHOD_SENTINEL,
};
......@@ -172,6 +176,7 @@ struct sip_call_list {
int match_invert;
//! Regexp for payload matching
regex_t reg_method;
regex_t reg_callid;
regex_t reg_xcallid;
regex_t reg_response;
......
......@@ -227,6 +227,7 @@ call_flow_draw_columns(PANEL *panel)
sip_msg_t *msg;
int flow_height, flow_width;
const char *coltext;
char address[50], *end;
// Get panel information
info = call_flow_info(panel);
......@@ -246,8 +247,17 @@ call_flow_draw_columns(PANEL *panel)
mvwvline(info->flow_win, 0, 20 + 30 * column->colpos, ACS_VLINE, flow_height);
mvwhline(win, 3, 10 + 30 * column->colpos, ACS_HLINE, 20);
mvwaddch(win, 3, 20 + 30 * column->colpos, ACS_TTEE);
// Set bold to this address if it's local
strcpy(address, column->addr);
if ((end = strchr(address, ':')))
*end = '\0';
if (is_local_address_str(address) && is_option_enabled("cf.localhighlight"))
wattron(win, A_BOLD);
coltext = (is_option_enabled("sngrep.displayhost")) ? column->host : column->addr;
mvwprintw(win, 2, 10 + 30 * column->colpos + (22 - strlen(coltext)) / 2, "%s", coltext);
wattroff(win, A_BOLD);
}
return 0;
......
......@@ -236,6 +236,9 @@ column_select_handle_key_menu(PANEL *panel, int key)
form_driver(info->form, REQ_VALIDATION);
curs_set(1);
break;
case ACTION_CONFIRM:
column_select_update_columns(panel);
return 27;
default:
// Parse next action
continue;
......
......@@ -128,7 +128,7 @@ filter_create()
// Get Method filter
if (!(method = filter_get(FILTER_METHOD)))
method = "";
method = get_option_value("filter.methods");
// Set Default field values
set_field_buffer(info->fields[FLD_FILTER_SIPFROM], 0, filter_get(FILTER_SIPFROM));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment