int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; if(!packet->iph /* IPv4 */) return(-1); if((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) || (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL)) { char certificate[64]; int rc; certificate[0] = '\0'; rc = getSSLcertificate(ndpi_struct, flow, certificate, sizeof(certificate)); packet->ssl_certificate_num_checks++; if(rc > 0) { packet->ssl_certificate_detected = 1; #ifdef CERTIFICATE_DEBUG printf("***** [SSL] %s\n", certificate); #endif if(ndpi_match_string_subprotocol(ndpi_struct, flow, certificate, strlen(certificate)) != NDPI_PROTOCOL_UNKNOWN) return(rc); /* Fix courtesy of Gianluca Costa <*****@*****.**> */ } if((packet->ssl_certificate_num_checks >= 2) && (certificate[0] != '\0') && flow->l4.tcp.seen_syn && flow->l4.tcp.seen_syn_ack && flow->l4.tcp.seen_ack) /* We have seen the 3-way handshake */ ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); } return(0); }
static void parseHttpSubprotocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { // int i = 0; struct ndpi_packet_struct *packet = &flow->packet; if(packet->iph /* IPv4 only */) { /* Twitter Inc. TWITTER-NETWORK (NET-199-59-148-0-1) 199.59.148.0 - 199.59.151.255 199.59.148.0/22 */ if(((ntohl(packet->iph->saddr) & 0xFFFFFC00 /* 255.255.252.0 */) == 0xC73B9400 /* 199.59.148.0 */) || ((ntohl(packet->iph->daddr) & 0xFFFFFC00 /* 255.255.252.0 */) == 0xC73B9400 /* 199.59.148.0 */)) { packet->detected_protocol_stack[0] = NDPI_PROTOCOL_TWITTER; return; } /* CIDR: 69.53.224.0/19 OriginAS: AS2906 NetName: NETFLIX-INC */ if(((ntohl(packet->iph->saddr) & 0xFFFFE000 /* 255.255.224.0 */) == 0x4535E000 /* 69.53.224.0 */) || ((ntohl(packet->iph->daddr) & 0xFFFFE000 /* 255.255.224.0 */) == 0x4535E000 /* 69.53.224.0 */)) { packet->detected_protocol_stack[0] = NDPI_PROTOCOL_NETFLIX; return; } } if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_HTTP) { /* Try matching subprotocols */ // ndpi_match_string_subprotocol(ndpi_struct, flow, (char*)packet->host_line.ptr, packet->host_line.len); ndpi_match_string_subprotocol(ndpi_struct, flow, flow->host_server_name, strlen(flow->host_server_name)); } }
int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; if(!packet->iph /* IPv4 */) return(-1); if((packet->payload_packet_len > 9) && (packet->payload[0] == 0x16 /* consider only specific SSL packets (handshake) */)) { if((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) || (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL)) { char certificate[64]; int rc; certificate[0] = '\0'; rc = getSSLcertificate(ndpi_struct, flow, certificate, sizeof(certificate)); packet->ssl_certificate_num_checks++; if(rc > 0) { packet->ssl_certificate_detected++; #ifdef CERTIFICATE_DEBUG printf("***** [SSL] %s\n", certificate); #endif if(ndpi_match_string_subprotocol(ndpi_struct, flow, certificate, strlen(certificate)) != NDPI_PROTOCOL_UNKNOWN) return(rc); /* Fix courtesy of Gianluca Costa <*****@*****.**> */ #ifdef NDPI_PROTOCOL_TOR if(ndpi_is_ssl_tor(ndpi_struct, flow, certificate) != 0) return(rc); #endif } if(((packet->ssl_certificate_num_checks >= 2) && flow->l4.tcp.seen_syn && flow->l4.tcp.seen_syn_ack && flow->l4.tcp.seen_ack /* We have seen the 3-way handshake */) || (flow->protos.ssl.server_certificate[0] != '\0') || (flow->protos.ssl.client_certificate[0] != '\0') ) ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); } } return(0); }
void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; u_int16_t dport = 0, sport = 0; #define NDPI_MAX_DNS_REQUESTS 16 NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "search DNS.\n"); if (packet->udp != NULL) { sport = ntohs(packet->udp->source), dport = ntohs(packet->udp->dest); NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "calculated dport over UDP.\n"); } else if(packet->tcp != NULL) { sport = ntohs(packet->tcp->source), dport = ntohs(packet->tcp->dest); NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "calculated dport over tcp.\n"); } if(((dport == 53) || (sport == 53)) && (packet->payload_packet_len > sizeof(struct dns_packet_header))) { int i = packet->tcp ? 2 : 0; struct dns_packet_header header, *dns = (struct dns_packet_header*)&packet->payload[i]; u_int8_t is_query, ret_code, is_dns = 0; u_int32_t a_record[NDPI_MAX_DNS_REQUESTS] = { 0 }, query_offset, num_a_records = 0; header.flags = ntohs(dns->flags); header.transaction_id = ntohs(dns->transaction_id); header.num_queries = ntohs(dns->num_queries); header.answer_rrs = ntohs(dns->answer_rrs); header.authority_rrs = ntohs(dns->authority_rrs); header.additional_rrs = ntohs(dns->additional_rrs); is_query = (header.flags & 0x8000) ? 0 : 1; ret_code = is_query ? 0 : (header.flags & 0x0F); i += sizeof(struct dns_packet_header); query_offset = i; if(is_query) { /* DNS Request */ if((header.num_queries > 0) && (header.num_queries <= NDPI_MAX_DNS_REQUESTS) && (header.answer_rrs == 0) && (header.authority_rrs == 0)) { /* This is a good query */ is_dns = 1; } } else { /* DNS Reply */ if((header.num_queries <= NDPI_MAX_DNS_REQUESTS) /* Don't assume that num_queries must be zero */ && (((header.answer_rrs > 0) && (header.answer_rrs <= NDPI_MAX_DNS_REQUESTS)) || ((header.authority_rrs > 0) && (header.authority_rrs <= NDPI_MAX_DNS_REQUESTS)) || ((header.additional_rrs > 0) && (header.additional_rrs <= NDPI_MAX_DNS_REQUESTS))) ) { /* This is a good reply */ is_dns = 1; i++; if(packet->payload[i] != '\0') { while((i < packet->payload_packet_len) && (packet->payload[i] != '\0')) { i++; } i++; } i += 4; if(header.answer_rrs > 0) { u_int16_t rsp_type, rsp_class; u_int16_t num; for(num = 0; num < header.answer_rrs; num++) { u_int16_t data_len; if((i+6) >= packet->payload_packet_len) { break; } if((data_len = getNameLength(i, packet->payload, packet->payload_packet_len)) == 0) { break; } else i += data_len; rsp_type = get16(&i, packet->payload); rsp_class = get16(&i, packet->payload); i += 4; data_len = get16(&i, packet->payload); if((data_len <= 1) || (data_len > (packet->payload_packet_len-i))) { break; } if(rsp_type == 1 /* A */) { if(data_len == 4) { u_int32_t v = ntohl(*((u_int32_t*)&packet->payload[i])); if(num_a_records < (NDPI_MAX_DNS_REQUESTS-1)) a_record[num_a_records++] = v; else break; /* One record is enough */ } } if(data_len == 0) { break; } i += data_len; } /* for */ } } if((header.num_queries <= NDPI_MAX_DNS_REQUESTS) && ((header.answer_rrs == 0) || (header.authority_rrs == 0) || (header.additional_rrs == 0)) && (ret_code != 0 /* 0 == OK */) ) { /* This is a good reply */ is_dns = 1; } } if(is_dns) { int j = 0; #ifdef DEBUG u_int16_t query_type, query_class; #endif i = query_offset+1; while((i < packet->payload_packet_len) && (j < (sizeof(flow->host_server_name)-1)) && (packet->payload[i] != '\0')) { flow->host_server_name[j] = tolower(packet->payload[i]); if(flow->host_server_name[j] < ' ') flow->host_server_name[j] = '.'; j++, i++; } if(a_record != 0) { char a_buf[32]; int i; for(i=0; i<num_a_records; i++) { j += snprintf(&flow->host_server_name[j], sizeof(flow->host_server_name)-1-j, "%s%s", (i == 0) ? "@" : ";", ndpi_intoa_v4(a_record[i], a_buf, sizeof(a_buf))); } } flow->host_server_name[j] = '\0'; if(j > 0) { #ifdef DEBUG printf("==> %s\n", flow->host_server_name); #endif if(ndpi_struct->match_dns_host_names) ndpi_match_string_subprotocol(ndpi_struct, flow, flow->host_server_name, strlen(flow->host_server_name)); } #ifdef DEBUG i++; memcpy(&query_type, &packet->payload[i], 2); query_type = ntohs(query_type), i += 2; memcpy(&query_class, &packet->payload[i], 2); query_class = ntohs(query_class), i += 2; printf("%s [type=%04X][class=%04X]\n", flow->host_server_name, query_type, query_class); #endif if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { /* Do not set the protocol with DNS if ndpi_match_string_subprotocol() has matched a subprotocol */ NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "found DNS.\n"); ndpi_int_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_DNS, NDPI_REAL_PROTOCOL); } } else { NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "exclude DNS.\n"); NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_DNS); } } }