packet_t *packet_parse(uint8_t *data, size_t length, options_t options) { packet_t *packet = (packet_t*) safe_malloc(sizeof(packet_t)); buffer_t *buffer = buffer_create_with_data(BO_BIG_ENDIAN, data, length); /* Validate the size */ if(buffer_get_length(buffer) > MAX_PACKET_SIZE) { LOG_FATAL("Packet is too long: %zu bytes\n", buffer_get_length(buffer)); exit(1); } packet->packet_id = buffer_read_next_int16(buffer); packet->packet_type = (packet_type_t) buffer_read_next_int8(buffer); packet->session_id = buffer_read_next_int16(buffer); switch(packet->packet_type) { case PACKET_TYPE_SYN: packet->body.syn.seq = buffer_read_next_int16(buffer); packet->body.syn.options = buffer_read_next_int16(buffer); break; case PACKET_TYPE_MSG: if(options & OPT_CHUNKED_DOWNLOAD) { packet->body.msg.options.chunked.chunk = buffer_read_next_int32(buffer); } else { packet->body.msg.options.normal.seq = buffer_read_next_int16(buffer); packet->body.msg.options.normal.ack = buffer_read_next_int16(buffer); } packet->body.msg.data = buffer_read_remaining_bytes(buffer, &packet->body.msg.data_length, -1, FALSE); break; case PACKET_TYPE_FIN: packet->body.fin.reason = buffer_alloc_next_ntstring(buffer); break; case PACKET_TYPE_PING: packet->body.ping.data = buffer_alloc_next_ntstring(buffer); break; default: LOG_FATAL("Error: unknown message type (0x%02x)\n", packet->packet_type); exit(0); } buffer_destroy(buffer); return packet; }
/* Read data from the session that will be sent out across the network. This * will return up to read_length bytes (and will return the number of bytes * read in read_length as well). The memory returned has to be freed. * * If the session isn't found, NULL is returned. If no data is waiting, the * empty string is returned and read_length is set to 0. */ uint8_t *session_read(sessions_t *sessions, char *session_name, uint32_t *read_length) { uint32_t i = 0; buffer_t *incoming; buffer_t *response; session_t *session; session = session_get(sessions, session_name); if(!session) return NULL; if(session_is_closed(sessions, session_name)) return NULL; if(buffer_can_read_int8(sessions->buffer_data)) { incoming = sessions->buffer_data; } else { if(!session) return NULL; incoming = session->buffer; } response = buffer_create(BO_NETWORK); while(buffer_can_read_int8(incoming) && i < *read_length) { if(sessions->log) fputc(buffer_peek_next_int8(incoming), sessions->log); buffer_add_int8(response, buffer_read_next_int8(incoming)); i++; } /* Clear whichever buffer we're using if we're at the end. */ if(!buffer_can_read_int8(incoming)) buffer_clear(incoming); return buffer_create_string_and_destroy(response, read_length); }
static SELECT_RESPONSE_t recv_socket_callback(void *group, int s, uint8_t *data, size_t length, char *addr, uint16_t port, void *param) { /*driver_dns_t *driver_dns = param;*/ dns_t *dns = dns_create_from_packet(data, length); driver_dns_t *driver = (driver_dns_t*) param; LOG_INFO("DNS response received (%d bytes)", length); /* TODO */ if(dns->rcode != _DNS_RCODE_SUCCESS) { /* TODO: Handle errors more gracefully */ switch(dns->rcode) { case _DNS_RCODE_FORMAT_ERROR: LOG_ERROR("DNS: RCODE_FORMAT_ERROR"); break; case _DNS_RCODE_SERVER_FAILURE: LOG_ERROR("DNS: RCODE_SERVER_FAILURE"); break; case _DNS_RCODE_NAME_ERROR: LOG_ERROR("DNS: RCODE_NAME_ERROR"); break; case _DNS_RCODE_NOT_IMPLEMENTED: LOG_ERROR("DNS: RCODE_NOT_IMPLEMENTED"); break; case _DNS_RCODE_REFUSED: LOG_ERROR("DNS: RCODE_REFUSED"); break; default: LOG_ERROR("DNS: Unknown error code (0x%04x)", dns->rcode); break; } } else if(dns->question_count != 1) { LOG_ERROR("DNS returned the wrong number of response fields (question_count should be 1, was instead %d).", dns->question_count); LOG_ERROR("This is probably due to a DNS error"); } else if(dns->answer_count < 1) { LOG_ERROR("DNS didn't return an answer"); LOG_ERROR("This is probably due to a DNS error"); } else { size_t i; uint8_t *answer = NULL; size_t answer_length = 0; dns_type_t type = dns->answers[0].type; if(type == _DNS_TYPE_TEXT) { /* Get the answer. */ answer = dns->answers[0].answer->TEXT.text; answer_length = dns->answers[0].answer->TEXT.length; LOG_INFO("Received a TXT response (%zu bytes)", answer_length); /* Decode it. */ answer = buffer_decode_hex(answer, &answer_length); } else if(type == _DNS_TYPE_CNAME) { /* Get the answer. */ answer = remove_domain((char*)dns->answers[0].answer->CNAME.name, driver->domain); answer_length = strlen((char*)answer); LOG_INFO("Received a CNAME response (%zu bytes)", answer_length); /* Decode it. */ answer = buffer_decode_hex(answer, &answer_length); } else if(type == _DNS_TYPE_MX) { /* Get the answer. */ answer = remove_domain((char*)dns->answers[0].answer->MX.name, driver->domain); answer_length = strlen((char*)answer); LOG_INFO("Received a MX response (%zu bytes)", answer_length); /* Decode it. */ answer = buffer_decode_hex(answer, &answer_length); } else if(type == _DNS_TYPE_A) { buffer_t *buf = buffer_create(BO_BIG_ENDIAN); qsort(dns->answers, dns->answer_count, sizeof(answer_t), cmpfunc_a); for(i = 0; i < dns->answer_count; i++) buffer_add_bytes(buf, dns->answers[i].answer->A.bytes + 1, 3); answer_length = buffer_read_next_int8(buf); LOG_INFO("Received an A response (%zu bytes)", answer_length); answer = safe_malloc(answer_length); buffer_read_bytes_at(buf, 1, answer, answer_length); } #ifndef WIN32 else if(type == _DNS_TYPE_AAAA) { buffer_t *buf = buffer_create(BO_BIG_ENDIAN); qsort(dns->answers, dns->answer_count, sizeof(answer_t), cmpfunc_aaaa); for(i = 0; i < dns->answer_count; i++) buffer_add_bytes(buf, dns->answers[i].answer->AAAA.bytes + 1, 15); answer_length = buffer_read_next_int8(buf); LOG_INFO("Received an AAAA response (%zu bytes)", answer_length); answer = safe_malloc(answer_length); buffer_read_bytes_at(buf, 1, answer, answer_length); } #endif else { LOG_ERROR("Unknown DNS type returned: %d", type); answer = NULL; } if(answer) { /*LOG_WARNING("Received a %zu-byte DNS response: %s [0x%04x]", answer_length, answer, type);*/ /* Pass the buffer to the caller */ if(answer_length > 0) { /* Pass the data elsewhere. */ message_post_packet_in(answer, answer_length); } safe_free(answer); } } dns_destroy(dns); return SELECT_OK; }