static int decode_ftp(packet_t *p, const _uint8 *bytes, size_t len) { header_t *h = packet_append_header(p, PROTO_NAME_FTP, (void *)bytes, len); packet_set_payload(p, h); return DECODE_OK; }
int sip_validate_packet(packet_t *packet) { uint32_t plen = packet_payloadlen(packet); u_char payload[MAX_SIP_PAYLOAD]; regmatch_t pmatch[3]; char cl_header[10]; int content_len; int bodylen; // Max SIP payload allowed if (plen == 0 || plen > MAX_SIP_PAYLOAD) return VALIDATE_NOT_SIP; // Get payload from packet(s) memset(payload, 0, MAX_SIP_PAYLOAD); memcpy(payload, packet_payload(packet), plen); // Initialize variables memset(cl_header, 0, sizeof(cl_header)); // Check if the first line follows SIP request or response format if (regexec(&calls.reg_valid, (const char *) payload, 2, pmatch, 0) != 0) { // Not a SIP message AT ALL return VALIDATE_NOT_SIP; } // Check if we have Content Length header if (regexec(&calls.reg_cl, (const char *) payload, 4, pmatch, 0) != 0) { // Not a SIP message or not complete return VALIDATE_PARTIAL_SIP; } strncpy(cl_header, (const char *)payload + pmatch[2].rm_so, (int)pmatch[2].rm_eo - pmatch[2].rm_so); content_len = atoi(cl_header); // Check if we have Body separator field if (regexec(&calls.reg_body, (const char *) payload, 2, pmatch, 0) != 0) { // Not a SIP message or not complete return VALIDATE_PARTIAL_SIP; } // Get the SIP message body length bodylen = (int) pmatch[1].rm_eo - pmatch[1].rm_so; // The SDP body of the SIP message ends in another packet if (content_len > bodylen) { return VALIDATE_PARTIAL_SIP; } if (content_len < bodylen) { // We got more than one SIP message in the same packet packet_set_payload(packet, payload, pmatch[1].rm_so + content_len); return VALIDATE_MULTIPLE_SIP; } // We got all the SDP body of the SIP message return VALIDATE_COMPLETE_SIP; }
int capture_ws_check_packet(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 = packet_payloadlen(packet); payload = packet_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 packet_set_payload(packet, newpayload, size_payload); // Free the new payload sng_free(newpayload); if (packet->type == PACKET_SIP_TLS) { packet_set_type(packet, PACKET_SIP_WSS); } else { packet_set_type(packet, PACKET_SIP_WS); } return 1; }
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; }
void parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packet) { // Capture info capture_info_t *capinfo = (capture_info_t *) info; // 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 data u_char data[MAX_CAPTURE_LEN]; // Packet payload data u_char *payload = NULL; // Whole packet size uint32_t size_capture = header->caplen; // Packet payload size uint32_t size_payload = size_capture - capinfo->link_hl; // Captured packet info packet_t *pkt; // Ignore packets while capture is paused if (capture_paused()) return; // Check if we have reached capture limit if (capture_cfg.limit && sip_calls_count() >= capture_cfg.limit) return; // Check maximum capture length if (header->caplen > MAX_CAPTURE_LEN) return; // Copy packet payload memcpy(data, packet, header->caplen); // Check if we have a complete IP packet if (!(pkt = capture_packet_reasm_ip(capinfo, header, data, &size_payload, &size_capture))) return; // Only interested in UDP packets if (pkt->proto == IPPROTO_UDP) { // Get UDP header udp = (struct udphdr *)((u_char *)(data) + (size_capture - size_payload)); udp_off = sizeof(struct udphdr); // Set packet ports pkt->src.port = htons(udp->uh_sport); pkt->dst.port = htons(udp->uh_dport); // Remove UDP Header from payload size_payload -= udp_off; if ((int32_t)size_payload < 0) size_payload = 0; // Remove TCP Header from payload payload = (u_char *) (udp) + udp_off; // Complete packet with Transport information packet_set_type(pkt, PACKET_SIP_UDP); packet_set_payload(pkt, payload, size_payload); } else if (pkt->proto == IPPROTO_TCP) { // Get TCP header tcp = (struct tcphdr *)((u_char *)(data) + (size_capture - size_payload)); tcp_off = (tcp->th_off * 4); // Set packet ports pkt->src.port = htons(tcp->th_sport); pkt->dst.port = htons(tcp->th_dport); // Get actual payload size size_payload -= tcp_off; if ((int32_t)size_payload < 0) size_payload = 0; // Get payload start payload = (u_char *)(tcp) + tcp_off; // Complete packet with Transport information packet_set_type(pkt, PACKET_SIP_TCP); packet_set_payload(pkt, payload, size_payload); // Create a structure for this captured packet if (!(pkt = capture_packet_reasm_tcp(pkt, tcp, payload, size_payload))) return; #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) // Check if packet is TLS if (capture_cfg.keyfile) { tls_process_segment(pkt, tcp); } #endif // Check if packet is WS or WSS capture_ws_check_packet(pkt); } else { // Not handled protocol packet_destroy(pkt); return; } // Avoid parsing from multiples sources. // Avoid parsing while screen in being redrawn capture_lock(); // Check if we can handle this packet if (capture_packet_parse(pkt) == 0) { #ifdef USE_EEP // Send this packet through eep capture_eep_send(pkt); #endif // Store this packets in output file dump_packet(capture_cfg.pd, pkt); // If storage is disabled, delete frames payload if (capture_cfg.storage == 0) { packet_free_frames(pkt); } // Allow Interface refresh and user input actions capture_unlock(); return; } // Not an interesting packet ... packet_destroy(pkt); // Allow Interface refresh and user input actions capture_unlock(); }
packet_t * capture_eep_receive_v3() { struct hep_generic hg; hep_chunk_ip4_t src_ip4, dst_ip4; #ifdef USE_IPV6 hep_chunk_ip6_t src_ip6, dst_ip6; #endif hep_chunk_t payload_chunk; hep_chunk_t authkey_chunk; uint8_t family, proto; char password[100]; int password_len; unsigned char *payload = 0; uint32_t len, pos; char buffer[MAX_CAPTURE_LEN] ; //! Source and Destination Address address_t src, dst; //! EEP client data struct sockaddr eep_client; socklen_t eep_client_len; //! Packet header struct pcap_pkthdr header; //! New created packet pointer packet_t *pkt; /* Receive EEP generic header */ if (recvfrom(eep_cfg.server_sock, buffer, MAX_CAPTURE_LEN, 0, &eep_client, &eep_client_len) == -1) return NULL; /* Copy initial bytes to EEP Generic header */ memcpy(&hg, buffer, sizeof(struct hep_generic)); /* header check */ if (memcmp(hg.header.id, "\x48\x45\x50\x33", 4) != 0) return NULL; /* IP proto */ family = hg.ip_family.data; /* Proto ID */ proto = hg.ip_proto.data; len = ntohs(hg.header.length) - sizeof(struct hep_generic); pos = sizeof(struct hep_generic); /* IPv4 */ if (family == AF_INET) { /* SRC IP */ memcpy(&src_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4)); inet_ntop(AF_INET, &src_ip4.data, src.ip, sizeof(src.ip)); pos += sizeof(struct hep_chunk_ip4); /* DST IP */ memcpy(&dst_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4)); inet_ntop(AF_INET, &dst_ip4.data, dst.ip, sizeof(src.ip)); pos += sizeof(struct hep_chunk_ip4); } #ifdef USE_IPV6 /* IPv6 */ else if(family == AF_INET6) { /* SRC IPv6 */ memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6)); inet_ntop(AF_INET6, &src_ip6.data, src.ip, sizeof(src.ip)); pos += sizeof(struct hep_chunk_ip6); /* DST IP */ memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6)); inet_ntop(AF_INET6, &dst_ip6.data, dst.ip, sizeof(dst.ip)); pos += sizeof(struct hep_chunk_ip6); } #endif /* SRC PORT */ src.port = ntohs(hg.src_port.data); /* DST PORT */ dst.port = ntohs(hg.dst_port.data); /* TIMESTAMP*/ header.ts.tv_sec = ntohl(hg.time_sec.data); header.ts.tv_usec = ntohl(hg.time_usec.data); /* Protocol TYPE */ /* Capture ID */ /* auth key */ if (eep_cfg.capt_srv_password != NULL) { memcpy(&authkey_chunk, (void*) buffer + pos, sizeof(authkey_chunk)); pos += sizeof(authkey_chunk); password_len = ntohs(authkey_chunk.length) - sizeof(authkey_chunk); memcpy(password, (void*) buffer + pos, password_len); pos += password_len; // Validate the password if (strncmp(password, eep_cfg.capt_srv_password, password_len) != 0) return NULL; } /* Payload */ memcpy(&payload_chunk, (void*) buffer + pos, sizeof(payload_chunk)); pos += sizeof(payload_chunk); // Calculate payload size header.caplen = header.len = ntohs(payload_chunk.length) - sizeof(payload_chunk); // Receive packet payload payload = sng_malloc(header.caplen); memcpy(payload, (void*) buffer + pos, header.caplen); // Create a new packet pkt = packet_create((family == AF_INET)?4:6, proto, src, dst, 0); packet_add_frame(pkt, &header, payload); packet_set_type(pkt, PACKET_SIP_UDP); packet_set_payload(pkt, payload, header.caplen); /* FREE */ sng_free(payload); return pkt; }
packet_t * capture_eep_receive_v2() { uint8_t family, proto; unsigned char *payload = 0; uint32_t pos; char buffer[MAX_CAPTURE_LEN] ; //! Source Address address_t src; //! Destination address address_t dst; //! Packet header struct pcap_pkthdr header; //! New created packet pointer packet_t *pkt; //! EEP client data struct sockaddr eep_client; socklen_t eep_client_len; struct hep_hdr hdr; struct hep_timehdr hep_time; struct hep_iphdr hep_ipheader; #ifdef USE_IPV6 struct hep_ip6hdr hep_ip6header; #endif // Initialize buffer memset(buffer, 0, MAX_CAPTURE_LEN); /* Receive EEP generic header */ if (recvfrom(eep_cfg.server_sock, buffer, MAX_CAPTURE_LEN, 0, &eep_client, &eep_client_len) == -1) return NULL; /* Copy initial bytes to HEPv2 header */ memcpy(&hdr, buffer, sizeof(struct hep_hdr)); // Check HEP version if (hdr.hp_v != 2) return NULL; /* IP proto */ family = hdr.hp_f; /* Proto ID */ proto = hdr.hp_p; pos = sizeof(struct hep_hdr); /* IPv4 */ if (family == AF_INET) { memcpy(&hep_ipheader, (void*) buffer + pos, sizeof(struct hep_iphdr)); inet_ntop(AF_INET, &hep_ipheader.hp_src, src.ip, sizeof(src.ip)); inet_ntop(AF_INET, &hep_ipheader.hp_dst, dst.ip, sizeof(dst.ip)); pos += sizeof(struct hep_iphdr); } #ifdef USE_IPV6 /* IPv6 */ else if(family == AF_INET6) { memcpy(&hep_ip6header, (void*) buffer + pos, sizeof(struct hep_ip6hdr)); inet_ntop(AF_INET6, &hep_ip6header.hp6_src, src.ip, sizeof(src.ip)); inet_ntop(AF_INET6, &hep_ip6header.hp6_dst, dst.ip, sizeof(dst.ip)); pos += sizeof(struct hep_ip6hdr); } #endif /* PORTS */ src.port = ntohs(hdr.hp_sport); dst.port = ntohs(hdr.hp_dport); /* TIMESTAMP*/ memcpy(&hep_time, (void*) buffer + pos, sizeof(struct hep_timehdr)); pos += sizeof(struct hep_timehdr); header.ts.tv_sec = hep_time.tv_sec; header.ts.tv_usec = hep_time.tv_usec; /* Protocol TYPE */ /* Capture ID */ // Calculate payload size (Total size - headers size) header.caplen = header.len = ntohs(hdr.hp_l) - pos; // Copy packet payload payload = sng_malloc(header.caplen + 1); memcpy(payload, (void*) buffer + pos, header.caplen); // Create a new packet pkt = packet_create((family == AF_INET) ? 4 : 6, proto, src, dst, 0); packet_add_frame(pkt, &header, payload); packet_set_transport_data(pkt, src.port, dst.port); packet_set_type(pkt, PACKET_SIP_UDP); packet_set_payload(pkt, payload, header.caplen); /* FREE */ sng_free(payload); return pkt; }
int tls_process_segment(packet_t *packet, struct tcphdr *tcp) { struct SSLConnection *conn; const u_char *payload = packet_payload(packet); uint32_t size_payload = packet_payloadlen(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->src.port; uint16_t dport = packet->dst.port; // Convert addresses inet_pton(AF_INET, packet->src.ip, &ip_src); inet_pton(AF_INET, packet->dst.ip, &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) { packet_set_payload(packet, out, outl); packet_set_type(packet, 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; }