int tls_process_segment(capture_packet_t *packet, struct tcphdr *tcp) { struct SSLConnection *conn; const u_char *payload = capture_packet_get_payload(packet); uint32_t size_payload = capture_packet_get_payload_len(packet); uint8_t *out; uint32_t outl = packet->payload_len; out = sng_malloc(outl); struct in_addr ip_src, ip_dst; uint16_t sport = packet->sport; uint16_t dport = packet->dport; // Convert addresses inet_pton(AF_INET, packet->ip_src, &ip_src); inet_pton(AF_INET, packet->ip_dst, &ip_dst); // Try to find a session for this ip if ((conn = tls_connection_find(ip_src, sport))) { // Update last connection direction conn->direction = tls_connection_dir(conn, ip_src, sport); // Check current connection state switch (conn->state) { case TCP_STATE_SYN: // First SYN received, this package must be SYN/ACK if (tcp->th_flags & TH_SYN & ~TH_ACK) conn->state = TCP_STATE_SYN_ACK; break; case TCP_STATE_SYN_ACK: // We expect an ACK packet here if (tcp->th_flags & ~TH_SYN & TH_ACK) conn->state = TCP_STATE_ESTABLISHED; break; case TCP_STATE_ACK: case TCP_STATE_ESTABLISHED: // Process data segment! if (tls_process_record(conn, payload, size_payload, &out, &outl) == 0) { if ((int32_t) outl > 0) { capture_packet_set_payload(packet, out, outl); capture_packet_set_type(packet, CAPTURE_PACKET_SIP_TLS); return 0; } } break; case TCP_STATE_FIN: case TCP_STATE_CLOSED: // We can delete this connection tls_connection_destroy(conn); break; } } else { if (tcp->th_flags & TH_SYN & ~TH_ACK) { // New connection, store it status and leave tls_connection_create(ip_src, sport, ip_dst, dport); } } sng_free(out); return 0; }
void parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packet) { // IP header data struct ip *ip4; #ifdef WITH_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 uint32_t ip_off = 0; // Fragmentation flag uint8_t ip_frag = 0; // Fragmentation offset uint16_t ip_frag_off = 0; //! Source Address char ip_src[ADDRESSLEN]; //! Destination Address char ip_dst[ADDRESSLEN]; // Source and Destination Ports u_short sport, dport; // UDP header data struct udphdr *udp; // UDP header size uint16_t udp_off; // TCP header data struct tcphdr *tcp; // TCP header size uint16_t tcp_off; // Packet payload data u_char *payload = NULL; // Packet payload size uint32_t size_payload = header->caplen; // SIP message transport int transport; // Media structure for RTP packets rtp_stream_t *stream; // Captured packet info capture_packet_t *pkt; // Ignore packets while capture is paused if (capture_is_paused()) return; // Check if we have reached capture limit if (capinfo.limit && sip_calls_count() >= capinfo.limit) return; // Get IP header ip4 = (struct ip *) (packet + capinfo.link_hl); #ifdef WITH_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_frag = ip_off & (IP_MF | IP_OFFMASK); ip_frag_off = (ip_frag) ? (ip_off & IP_OFFMASK) * 8 : 0; // TODO Get fragment information inet_ntop(AF_INET, &ip4->ip_src, ip_src, sizeof(ip_src)); inet_ntop(AF_INET, &ip4->ip_dst, ip_dst, sizeof(ip_dst)); break; #ifdef WITH_IPV6 case 6: ip_hl = sizeof(struct ip6_hdr); ip_proto = ip6->ip6_nxt; 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); // TODO Get fragment information } inet_ntop(AF_INET6, &ip6->ip6_src, ip_src, sizeof(ip_src)); inet_ntop(AF_INET6, &ip6->ip6_dst, ip_dst, sizeof(ip_dst)); break; #endif default: return; } // Only interested in UDP packets if (ip_proto == IPPROTO_UDP) { // Get UDP header udp = (struct udphdr *)((u_char *)(ip4) + ip_hl); udp_off = (ip_frag_off) ? 0 : sizeof(struct udphdr); // Set packet ports sport = htons(udp->uh_sport); dport = htons(udp->uh_dport); // Get actual payload size size_payload -= capinfo.link_hl + ip_hl + udp_off; #ifdef WITH_IPV6 if (ip_ver == 6) size_payload -= ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); #endif // Get payload start payload = (u_char *) (udp) + udp_off; // Set transport UDP transport = CAPTURE_PACKET_SIP_UDP; } else if (ip_proto == IPPROTO_TCP) { // Get TCP header tcp = (struct tcphdr *)((u_char *)(ip4 )+ ip_hl); tcp_off = (ip_frag_off) ? 0 : (tcp->th_off * 4); // Set packet ports sport = htons(tcp->th_sport); dport = htons(tcp->th_dport); // Get actual payload size size_payload -= capinfo.link_hl + ip_hl + tcp_off; #ifdef WITH_IPV6 if (ip_ver == 6) size_payload -= ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); #endif // Get payload start payload = (u_char *)(tcp) + tcp_off; // Set transport TCP transport = CAPTURE_PACKET_SIP_TCP; } else { // Not handled protocol return; } if ((int32_t)size_payload < 0) size_payload = 0; // Create a structure for this captured packet pkt = capture_packet_create(header, packet, header->caplen); capture_packet_set_type(pkt, transport); // For TCP and UDP, use payload directly from the packet capture_packet_set_payload(pkt, NULL, size_payload); #ifdef WITH_OPENSSL // Check if packet is TLS if (capinfo.keyfile && transport == CAPTURE_PACKET_SIP_TCP) tls_process_segment(ip4, pkt); #endif // Check if packet is WS or WSS if (transport == CAPTURE_PACKET_SIP_TCP) capture_ws_check_packet(pkt); // We're only interested in packets with payload if (capture_packet_get_payload_len(pkt)) { // Parse this header and payload if (sip_load_message(pkt, ip_src, sport, ip_dst, dport)) { // Store this packets in output file dump_packet(capinfo.pd, header, packet); return; } // Check if this packet belongs to a RTP stream // TODO Store this packet in the stream if ((stream = rtp_check_stream(pkt, ip_src, sport, ip_dst, dport))) { // We have an RTP packet! capture_packet_set_type(pkt, CAPTURE_PACKET_RTP); // Store this pacekt if capture rtp is enabled if (capinfo.rtp_capture) { call_add_rtp_packet(stream_get_call(stream), pkt); } else { capture_packet_destroy(pkt); } // Store this packets in output file dump_packet(capinfo.pd, header, packet); return; } } // Not an interesting packet ... capture_packet_destroy(pkt); }
int capture_ws_check_packet(capture_packet_t *packet) { int ws_off = 0; u_char ws_fin; u_char ws_opcode; u_char ws_mask; uint8_t ws_len; u_char ws_mask_key[4]; u_char *payload, *newpayload; uint32_t size_payload; int i; /** * WSocket header definition according to RFC 6455 * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-------+-+-------------+-------------------------------+ * |F|R|R|R| opcode|M| Payload len | Extended payload length | * |I|S|S|S| (4) |A| (7) | (16/64) | * |N|V|V|V| |S| | (if payload len==126/127) | * | |1|2|3| |K| | | * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + * | Extended payload length continued, if payload len == 127 | * + - - - - - - - - - - - - - - - +-------------------------------+ * | |Masking-key, if MASK set to 1 | * +-------------------------------+-------------------------------+ * | Masking-key (continued) | Payload Data | * +-------------------------------- - - - - - - - - - - - - - - - + * : Payload Data continued ... : * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * | Payload Data continued ... | * +---------------------------------------------------------------+ */ // Get payload from packet(s) size_payload = capture_packet_get_payload_len(packet); payload = capture_packet_get_payload(packet); // Check we have payload if (size_payload == 0) return 0; // Flags && Opcode ws_fin = (*payload & WH_FIN) >> 4; ws_opcode = *payload & WH_OPCODE; ws_off++; // Only interested in Ws text packets if (ws_opcode != WS_OPCODE_TEXT) return 0; // Masked flag && Payload len ws_mask = (*(payload + ws_off) & WH_MASK) >> 4; ws_len = (*(payload + ws_off) & WH_LEN); ws_off++; // Skip Payload len switch (ws_len) { // Extended case 126: ws_off += 2; break; case 127: ws_off += 8; break; default: return 0; } // Get Masking key if mask is enabled if (ws_mask) { memcpy(ws_mask_key, (payload + ws_off), 4); ws_off += 4; } // Skip Websocket headers size_payload -= ws_off; if ((int32_t) size_payload <= 0) return 0; newpayload = sng_malloc(size_payload); memcpy(newpayload, payload + ws_off, size_payload); // If mask is enabled, unmask the payload if (ws_mask) { for (i = 0; i < size_payload; i++) newpayload[i] = newpayload[i] ^ ws_mask_key[i % 4]; } // Set new packet payload into the packet capture_packet_set_payload(packet, newpayload, size_payload); if (packet->type == CAPTURE_PACKET_SIP_TLS) { capture_packet_set_type(packet, CAPTURE_PACKET_SIP_WSS); } else { capture_packet_set_type(packet, CAPTURE_PACKET_SIP_WS); } return 1; }