sip_msg_t * call_group_get_next_msg(sip_call_group_t *group, sip_msg_t *msg) { sip_msg_t *next = NULL; sip_msg_t *cand; vector_iter_t msgs; sip_call_t *call; int i; for (i = 0; i < vector_count(group->calls); i++) { call = vector_item(group->calls, i); msgs = vector_iterator(call->msgs); if (msg && call == msg_get_call(msg)) vector_iterator_set_current(&msgs, msg->index); if (group->sdp_only) vector_iterator_set_filter(&msgs, msg_has_sdp); cand = NULL; while ((cand = vector_iterator_next(&msgs))) { // candidate must be between msg and next if (msg_is_older(cand, msg) && (!next || !msg_is_older(cand, next))) { next = cand; break; } } } return sip_parse_msg(next); }
void capture_close() { capture_info_t *capinfo; // Nothing to close if (vector_count(capture_cfg.sources) == 0) return; // Stop all captures vector_iter_t it = vector_iterator(capture_cfg.sources); while ((capinfo = vector_iterator_next(&it))) { //Close PCAP file if (capinfo->handle) { pcap_breakloop(capinfo->handle); pthread_join(capinfo->capture_t, NULL); pcap_close(capinfo->handle); } } // Close dump file if (capture_cfg.pd) { dump_close(capture_cfg.pd); } }
rtp_stream_t * call_group_get_next_stream(sip_call_group_t *group, rtp_stream_t *stream) { rtp_stream_t *next = NULL; rtp_stream_t *cand; sip_call_t *call; vector_iter_t streams; int i; for (i = 0; i < vector_count(group->calls); i++) { call = vector_item(group->calls, i); streams = vector_iterator(call->streams); while ( (cand = vector_iterator_next(&streams))) { if (!stream_get_count(cand)) continue; // candidate must be between msg and next if (stream_is_older(cand, stream) && (!next || stream_is_older(next, cand))) { next = cand; } } } return next; }
int iterator_erase(Vector* vector, Iterator* iterator) { size_t index = iterator_index(vector, iterator); if (vector_erase(vector, index) == VECTOR_ERROR) { return VECTOR_ERROR; } *iterator = vector_iterator(vector, index); return VECTOR_SUCCESS; }
void dump_packet(pcap_dumper_t *pd, const packet_t *packet) { if (!pd || !packet) return; vector_iter_t it = vector_iterator(packet->frames); frame_t *frame; while ((frame = vector_iterator_next(&it))) { pcap_dump((u_char*) pd, frame->header, frame->data); } pcap_dump_flush(pd); }
const char * media_get_format(sdp_media_t *media, uint32_t code) { sdp_media_fmt_t *format; vector_iter_t iter; iter = vector_iterator(media->formats); while ((format = vector_iterator_next(&iter))) { if (format->id == code) return format->format; } return "Unassigned"; }
sip_stats_t sip_calls_stats() { sip_stats_t stats; vector_iter_t it = vector_iterator(calls.list); // Total number of calls without filtering stats.total = vector_iterator_count(&it); // Total number of calls after filtering vector_iterator_set_filter(&it, filter_check_call); stats.displayed = vector_iterator_count(&it); return stats; }
char *test_iterator_empty() { vector_p vector = vector_create(sizeof(int)); int iterations = 0;; iterator_p iterator = vector_iterator(vector); while(iterator_next(iterator)) { iterations++; } mu_assert(iterations == 0, "should not have iterated"); return NULL; }
void sip_calls_rotate() { sip_call_t *call; vector_iter_t it = vector_iterator(calls.list); while ((call = vector_iterator_next(&it))) { if (!call->locked) { // Remove from callids hash htable_remove(calls.callids, call->callid); // Remove first call from active and call lists vector_remove(calls.active, call); vector_remove(calls.list, call); return; } } }
int call_msg_is_retrans(sip_msg_t *msg) { sip_msg_t *prev = NULL; vector_iter_t it; // Get previous message in call with same origin and destination it = vector_iterator(msg->call->msgs); vector_iterator_set_current(&it, vector_index(msg->call->msgs, msg)); while ((prev = vector_iterator_prev(&it))) { if (!strcmp(SRC(prev), SRC(msg)) && !strcmp(DST(prev), DST(msg))) break; } return (prev && !strcasecmp(msg_get_payload(msg), msg_get_payload(prev))); }
int call_group_msg_count(sip_call_group_t *group) { sip_call_t *call; vector_iter_t msgs; int msgcnt = 0, i; for (i = 0; i < vector_count(group->calls); i++) { call = vector_item(group->calls, i); msgs = vector_iterator(call->msgs); if (group->sdp_only) { vector_iterator_set_filter(&msgs, msg_has_sdp); } msgcnt += vector_iterator_count(&msgs); } return msgcnt; }
int call_msg_is_retrans(sip_msg_t *msg) { sip_msg_t *prev = NULL; vector_iter_t it; // Get previous message in call with same origin and destination it = vector_iterator(msg->call->msgs); vector_iterator_set_current(&it, vector_index(msg->call->msgs, msg)); while ((prev = vector_iterator_prev(&it))) { if (addressport_equals(prev->packet->src, msg->packet->src) && addressport_equals(prev->packet->dst, msg->packet->dst)) break; } return (prev && !strcasecmp(msg_get_payload(msg), msg_get_payload(prev))); }
int capture_launch_thread(capture_info_t *capinfo) { //! capture thread attributes pthread_attr_t attr; pthread_attr_init(&attr); // Start all captures threads vector_iter_t it = vector_iterator(capture_cfg.sources); while ((capinfo = vector_iterator_next(&it))) { if (pthread_create(&capinfo->capture_t, &attr, (void *) capture_thread, capinfo)) { return 1; } } pthread_attr_destroy(&attr); return 0; }
int capture_set_bpf_filter(const char *filter) { vector_iter_t it = vector_iterator(capture_cfg.sources); capture_info_t *capinfo; // Apply the given filter to all sources while ((capinfo = vector_iterator_next(&it))) { //! Check if filter compiles if (pcap_compile(capinfo->handle, &capture_cfg.fp, filter, 0, capinfo->mask) == -1) return 1; // Set capture filter if (pcap_setfilter(capinfo->handle, &capture_cfg.fp) == -1) return 1; } return 0; }
void sip_calls_clear_soft() { // Create again the callid hash table htable_destroy(calls.callids); calls.callids = htable_create(calls.limit); // Repopulate list applying current filter calls.list = vector_copy_if(sip_calls_vector(), filter_check_call); calls.active = vector_copy_if(sip_active_calls_vector(), filter_check_call); // Repopulate callids based on filtered list sip_call_t *call; vector_iter_t it = vector_iterator(calls.list); while ((call = vector_iterator_next(&it))) { htable_insert(calls.callids, call->callid, call); } }
char *test_iterator() { vector_p vector = vector_create(sizeof(int)); vector_add(vector, test_data(10)); vector_add(vector, test_data(20)); int total = 0; int iterations = 0; iterator_p iterator = vector_iterator(vector); while(iterator_next(iterator)) { total += *(int*)iterator->current; iterations++; } mu_assert(total == 30, "should have visited each item in the vector"); mu_assert(iterations == 2, "should have visited 2 items"); vector_free(vector); return NULL; }
vector_t * vector_clone(vector_t *original) { vector_t *clone; vector_iter_t it; void *item; // Check we have a valid vector pointer if (!original) return NULL; // Create a new vector structure clone = vector_create(original->limit, original->step); vector_set_destroyer(clone, original->destroyer); vector_set_sorter(clone, original->sorter); // Fill the clone vector with the same elements it = vector_iterator(original); while ((item = vector_iterator_next(&it))) vector_append(clone, item); // Return the cloned vector return clone; }
packet_t * capture_packet_reasm_tcp(packet_t *packet, struct tcphdr *tcp, u_char *payload, int size_payload) { vector_iter_t it = vector_iterator(capture_cfg.tcp_reasm); packet_t *pkt; u_char *new_payload; //! Assembled if ((int32_t) size_payload <= 0) return packet; while ((pkt = vector_iterator_next(&it))) { if (addressport_equals(pkt->src, packet->src) && addressport_equals(pkt->dst, packet->dst)) { break; } } // If we already have this packet stored if (pkt) { frame_t *frame; // Append this frames to the original packet vector_iter_t frames = vector_iterator(packet->frames); while ((frame = vector_iterator_next(&frames))) packet_add_frame(pkt, frame->header, frame->data); // Destroy current packet as its frames belong to the stored packet packet_destroy(packet); } else { // First time this packet has been seen pkt = packet; // Add To the possible reassembly list vector_append(capture_cfg.tcp_reasm, packet); } // Store firt tcp sequence if (pkt->tcp_seq == 0) { pkt->tcp_seq = ntohl(tcp->th_seq); } // If the first frame of this packet if (vector_count(pkt->frames) == 1) { // Set initial payload packet_set_payload(pkt, payload, size_payload); } else { // Check payload length. Dont handle too big payload packets if (pkt->payload_len + size_payload > MAX_CAPTURE_LEN) { packet_destroy(pkt); vector_remove(capture_cfg.tcp_reasm, pkt); return NULL; } new_payload = sng_malloc(pkt->payload_len + size_payload); if (pkt->tcp_seq < ntohl(tcp->th_seq)) { // Append payload to the existing pkt->tcp_seq = ntohl(tcp->th_seq); memcpy(new_payload, pkt->payload, pkt->payload_len); memcpy(new_payload + pkt->payload_len, payload, size_payload); } else { // Prepend payload to the existing memcpy(new_payload, payload, size_payload); memcpy(new_payload + size_payload, pkt->payload, pkt->payload_len); } packet_set_payload(pkt, new_payload, pkt->payload_len + size_payload); sng_free(new_payload); } // This packet is ready to be parsed int valid = sip_validate_packet(pkt); if (valid == VALIDATE_COMPLETE_SIP) { // Full SIP packet! vector_remove(capture_cfg.tcp_reasm, pkt); return pkt; } else if (valid == VALIDATE_NOT_SIP) { vector_remove(capture_cfg.tcp_reasm, pkt); return pkt; } // An incomplete SIP Packet return NULL; }
int save_to_file(ui_t *ui) { char savepath[256]; char savefile[256]; char fullfile[512]; sip_call_t *call = NULL; sip_msg_t *msg = NULL; pcap_dumper_t *pd = NULL; FILE *f = NULL; int cur = 0, total = 0; WINDOW *progress; vector_iter_t calls, msgs, rtps, packets; packet_t *packet; vector_t *sorted; // Get panel information save_info_t *info = save_info(ui); // Get current path field value. memset(savepath, 0, sizeof(savepath)); strcpy(savepath, field_buffer(info->fields[FLD_SAVE_PATH], 0)); strtrim(savepath); if (strlen(savepath)) strcat(savepath, "/"); // Get current file field value. memset(savefile, 0, sizeof(savefile)); strcpy(savefile, field_buffer(info->fields[FLD_SAVE_FILE], 0)); strtrim(savefile); if (!strlen(savefile)) { dialog_run("Please enter a valid filename"); return 1; } if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) { if (!strstr(savefile, ".pcap")) strcat(savefile, ".pcap"); } else { if (!strstr(savefile, ".txt")) strcat(savefile, ".txt"); } // Absolute filename sprintf(fullfile, "%s%s", savepath, savefile); if (access(fullfile, R_OK) == 0) { if (dialog_confirm("Overwrite confirmation", "Selected file already exits.\n Do you want to overwrite it?", "Yes,No") != 0) return 1; } // Don't allow to save no packets! if (info->savemode == SAVE_SELECTED && call_group_msg_count(info->group) == 0) { dialog_run("Unable to save: No selected dialogs."); return 1; } if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) { // Open dump file pd = dump_open(fullfile); if (access(fullfile, W_OK) != 0) { dialog_run(capture_last_error()); return 1; } } else { // Open a text file if (!(f = fopen(fullfile, "w"))) { dialog_run("Error: %s", strerror(errno)); return 0; } } // Get calls iterator switch (info->savemode) { case SAVE_ALL: // Get calls iterator calls = sip_calls_iterator(); break; case SAVE_SELECTED: // Save selected packets to file calls = vector_iterator(info->group->calls); break; case SAVE_DISPLAYED: // Set filtering for this iterator calls = sip_calls_iterator(); vector_iterator_set_filter(&calls, filter_check_call); break; default: break; } if (info->savemode == SAVE_MESSAGE) { if (info->saveformat == SAVE_TXT) { // Save selected message to file save_msg_txt(f, info->msg); } else { // Save selected message packet to pcap dump_packet(pd, info->msg->packet); } } else if (info->saveformat == SAVE_TXT) { // Save selected packets to file while ((call = vector_iterator_next(&calls))) { msgs = vector_iterator(call->msgs); // Save SIP message content while ((msg = vector_iterator_next(&msgs))) { save_msg_txt(f, msg); } } } else { // Store all messages in a time sorted vector sorted = vector_create(100, 50); vector_set_sorter(sorted, capture_packet_time_sorter); // Count packages for progress bar while ((call = vector_iterator_next(&calls))) { total += vector_count(call->msgs); if (info->saveformat == SAVE_PCAP_RTP) total += vector_count(call->rtp_packets); } vector_iterator_reset(&calls); progress = dialog_progress_run("Saving packets..."); dialog_progress_set_value(progress, 0); // Save selected packets to file while ((call = vector_iterator_next(&calls))) { msgs = vector_iterator(call->msgs); // Save SIP message content while ((msg = vector_iterator_next(&msgs))) { // Update progress bar dialog dialog_progress_set_value(progress, (++cur * 100) / total); vector_append(sorted, msg->packet); } // Save RTP packets if (info->saveformat == SAVE_PCAP_RTP) { rtps = vector_iterator(call->rtp_packets); while ((packet = vector_iterator_next(&rtps))) { // Update progress bar dialog dialog_progress_set_value(progress, (++cur * 100) / total); vector_append(sorted, packet); } } } // Save sorted packets packets = vector_iterator(sorted); while ((packet = vector_iterator_next(&packets))) { dump_packet(pd, packet); } dialog_progress_destroy(progress); } // Close saved file if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) { dump_close(pd); } else { fclose(f); } // Show success popup if (info->savemode == SAVE_MESSAGE) { dialog_run("Successfully saved selected SIP message to %s", savefile); } else { dialog_run("Successfully saved %d dialogs to %s", vector_iterator_count(&calls), savefile); } return 0; }
vector_iter_t sip_active_calls_iterator() { return vector_iterator(calls.active); }
vector_iter_t sip_calls_iterator() { return vector_iterator(calls.list); }
/* Iterators */ Iterator vector_begin(Vector* vector) { return vector_iterator(vector, 0); }
packet_t * capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *header, u_char *packet, uint32_t *size, uint32_t *caplen) { // IP header data struct ip *ip4; #ifdef USE_IPV6 // IPv6 header data struct ip6_hdr *ip6; #endif // IP version uint32_t ip_ver; // IP protocol uint8_t ip_proto; // IP header size uint32_t ip_hl = 0; // Fragment offset uint16_t ip_off = 0; // IP content len uint16_t ip_len = 0; // Fragmentation flag uint16_t ip_frag = 0; // Fragmentation identifier uint32_t ip_id = 0; // Fragmentation offset uint16_t ip_frag_off = 0; //! Source Address address_t src = { }; //! Destination Address address_t dst = { }; //! Common interator for vectors vector_iter_t it; //! Packet containers packet_t *pkt; //! Storage for IP frame frame_t *frame; uint32_t len_data = 0; // Get IP header ip4 = (struct ip *) (packet + capinfo->link_hl); #ifdef USE_IPV6 // Get IPv6 header ip6 = (struct ip6_hdr *) (packet + capinfo->link_hl); #endif // Get IP version ip_ver = ip4->ip_v; switch (ip_ver) { case 4: ip_hl = ip4->ip_hl * 4; ip_proto = ip4->ip_p; ip_off = ntohs(ip4->ip_off); ip_len = ntohs(ip4->ip_len); ip_frag = ip_off & (IP_MF | IP_OFFMASK); ip_frag_off = (ip_frag) ? (ip_off & IP_OFFMASK) * 8 : 0; ip_id = ntohs(ip4->ip_id); inet_ntop(AF_INET, &ip4->ip_src, src.ip, sizeof(src.ip)); inet_ntop(AF_INET, &ip4->ip_dst, dst.ip, sizeof(dst.ip)); break; #ifdef USE_IPV6 case 6: ip_hl = sizeof(struct ip6_hdr); ip_proto = ip6->ip6_nxt; ip_len = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen) + ip_hl; if (ip_proto == IPPROTO_FRAGMENT) { struct ip6_frag *ip6f = (struct ip6_frag *) (ip6 + ip_hl); ip_frag_off = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK); ip_id = ntohl(ip6f->ip6f_ident); } inet_ntop(AF_INET6, &ip6->ip6_src, src.ip, sizeof(src.ip)); inet_ntop(AF_INET6, &ip6->ip6_dst, dst.ip, sizeof(dst.ip)); break; #endif default: return NULL; } // Fixup VSS trailer in ethernet packets *caplen = capinfo->link_hl + ip_len; // Remove IP Header length from payload *size = *caplen - capinfo->link_hl - ip_hl; // If no fragmentation if (ip_frag == 0) { // Just create a new packet with given network data pkt = packet_create(ip_ver, ip_proto, src, dst, ip_id); packet_add_frame(pkt, header, packet); return pkt; } // Look for another packet with same id in IP reassembly vector it = vector_iterator(capture_cfg.ip_reasm); while ((pkt = vector_iterator_next(&it))) { if (addressport_equals(pkt->src, src) && addressport_equals(pkt->dst, dst) && pkt->ip_id == ip_id) { break; } } // If we already have this packet stored, append this frames to existing one if (pkt) { packet_add_frame(pkt, header, packet); } else { // Add To the possible reassembly list pkt = packet_create(ip_ver, ip_proto, src, dst, ip_id); packet_add_frame(pkt, header, packet); vector_append(capture_cfg.ip_reasm, pkt); return NULL; } // If no more fragments if ((ip_off & IP_MF) == 0) { // TODO Dont check the flag, check the holes // Calculate assembled IP payload data it = vector_iterator(pkt->frames); while ((frame = vector_iterator_next(&it))) { struct ip *frame_ip = (struct ip *) (frame->data + capinfo->link_hl); len_data += frame->header->caplen - capinfo->link_hl - frame_ip->ip_hl * 4; } // Check packet content length if (len_data > MAX_CAPTURE_LEN) return NULL; // Initialize memory for the assembly packet memset(packet, 0, capinfo->link_hl + ip_hl + len_data); it = vector_iterator(pkt->frames); while ((frame = vector_iterator_next(&it))) { // Get IP header struct ip *frame_ip = (struct ip *) (frame->data + capinfo->link_hl); memcpy(packet + capinfo->link_hl + ip_hl + (ntohs(frame_ip->ip_off) & IP_OFFMASK) * 8, frame->data + capinfo->link_hl + frame_ip->ip_hl * 4, frame->header->caplen - capinfo->link_hl - frame_ip->ip_hl * 4); } *caplen = capinfo->link_hl + ip_hl + len_data; *size = len_data; // Return the assembled IP packet vector_remove(capture_cfg.ip_reasm, pkt); return pkt; } return NULL; }
Iterator vector_end(Vector* vector) { return vector_iterator(vector, vector->size); }