Exemplo n.º 1
0
struct packet *new_udp_packet(int address_family,
			       enum direction_t direction,
			       u16 udp_payload_bytes,
			       char **error)
{
	struct packet *packet = NULL;  /* the newly-allocated result packet */
	struct header *udp_header = NULL;  /* the UDP header info */
	/* Calculate lengths in bytes of all sections of the packet */
	const int ip_option_bytes = 0;
	const int ip_header_bytes = (ip_header_min_len(address_family) +
				     ip_option_bytes);
	const int udp_header_bytes = sizeof(struct udp);
	const int ip_bytes =
		 ip_header_bytes + udp_header_bytes + udp_payload_bytes;

	/* Sanity-check all the various lengths */
	if (ip_option_bytes & 0x3) {
		asprintf(error, "IP options are not padded correctly "
			 "to ensure IP header is a multiple of 4 bytes: "
			 "%d excess bytes", ip_option_bytes & 0x3);
		return NULL;
	}
	assert((udp_header_bytes & 0x3) == 0);
	assert((ip_header_bytes & 0x3) == 0);

	if (ip_bytes > MAX_UDP_DATAGRAM_BYTES) {
		asprintf(error, "UDP datagram too large");
		return NULL;
	}

	/* Allocate and zero out a packet object of the desired size */
	packet = packet_new(ip_bytes);
	memset(packet->buffer, 0, ip_bytes);

	packet->direction = direction;
	packet->flags = 0;
	packet->ecn = ECN_NONE;

	/* Set IP header fields */
	set_packet_ip_header(packet, address_family, ip_bytes,
			     packet->ecn, IPPROTO_UDP);

	udp_header = packet_append_header(packet, HEADER_UDP,
					  sizeof(struct udp));
	udp_header->total_bytes = udp_header_bytes + udp_payload_bytes;

	/* Find the start of UDP section of the packet */
	packet->udp = (struct udp *) (ip_start(packet) + ip_header_bytes);

	/* Set UDP header fields */
	packet->udp->src_port	= htons(0);
	packet->udp->dst_port	= htons(0);
	packet->udp->len	= htons(udp_header_bytes + udp_payload_bytes);
	packet->udp->check	= 0;

	packet->ip_bytes = ip_bytes;
	return packet;
}
Exemplo n.º 2
0
struct packet *new_tcp_packet(int socket_fd,
				   int address_family,
			       enum direction_t direction,
			       enum ip_ecn_t ecn,
			       const char *flags,
			       u32 start_sequence,
			       u16 tcp_payload_bytes,
			       u32 ack_sequence,
			       s32 window,
			       const struct tcp_options *tcp_options,
			       char **error)
{
	struct packet *packet = NULL;  /* the newly-allocated result packet */
	/* Calculate lengths in bytes of all sections of the packet */
	const int ip_option_bytes = 0;
	const int tcp_option_bytes = tcp_options ? tcp_options->length : 0;
	const int ip_header_bytes = (ip_header_len(address_family) +
				     ip_option_bytes);
	const int tcp_header_bytes = sizeof(struct tcp) + tcp_option_bytes;
	const int ip_bytes =
		 ip_header_bytes + tcp_header_bytes + tcp_payload_bytes;

	/* Sanity-check all the various lengths */
	if (ip_option_bytes & 0x3) {
		asprintf(error, "IP options are not padded correctly "
			 "to ensure IP header is a multiple of 4 bytes: "
			 "%d excess bytes", ip_option_bytes & 0x3);

		printf("1\n");

		return NULL;
	}
	if (tcp_option_bytes & 0x3) {
		asprintf(error,
			 "TCP options are not padded correctly "
			 "to ensure TCP header is a multiple of 4 bytes: "
			 "%d excess bytes", tcp_option_bytes & 0x3);

		printf("2\n");

		return NULL;
	}
	assert((tcp_header_bytes & 0x3) == 0);
	assert((ip_header_bytes & 0x3) == 0);

	if (tcp_header_bytes > MAX_TCP_HEADER_BYTES) {
		asprintf(error, "TCP header too large");
		return NULL;
	}

	if (ip_bytes > MAX_TCP_DATAGRAM_BYTES) {
		asprintf(error, "TCP segment too large");
		return NULL;
	}

	if (!is_tcp_flags_spec_valid(flags, error)){
		return NULL;
	}

	/* Allocate and zero out a packet object of the desired size */
	packet = packet_new(ip_bytes);
	memset(packet->buffer, 0, ip_bytes);
	packet->ip_bytes = ip_bytes;

	packet->direction = direction;
	packet->socket_script_fd = socket_fd;
	packet->flags = 0;
	packet->ecn = ecn;

	/* Set IP header fields */
	set_packet_ip_header(packet, address_family, ip_bytes, direction, ecn,
			     IPPROTO_TCP);

	/* Find the start of TCP sections of the packet */
	packet->tcp = (struct tcp *) (packet_start(packet) + ip_header_bytes);
	u8 *tcp_option_start = (u8 *) (packet->tcp + 1);

	/* Set TCP header fields */
	packet->tcp->src_port = htons(0);
	packet->tcp->dst_port = htons(0);
	packet->tcp->seq = htonl(start_sequence);
	packet->tcp->ack_seq = htonl(ack_sequence);
	packet->tcp->doff = tcp_header_bytes / 4;
	if (window == -1) {
		if (direction == DIRECTION_INBOUND) {
			asprintf(error, "window must be specified"
				 " for inbound packets");
			return NULL;
		}
		packet->tcp->window = 0;
		packet->flags |= FLAG_WIN_NOCHECK;
	} else {
		packet->tcp->window = htons(window);
	}
	packet->tcp->check = 0;
	packet->tcp->urg_ptr = 0;
	packet->tcp->fin = is_tcp_flag_set('F', flags);
	packet->tcp->syn = is_tcp_flag_set('S', flags);
	packet->tcp->rst = is_tcp_flag_set('R', flags);
	packet->tcp->psh = is_tcp_flag_set('P', flags);
	packet->tcp->ack = is_tcp_flag_set('.', flags);
	packet->tcp->urg = 0;
	packet->tcp->ece = is_tcp_flag_set('E', flags);
	packet->tcp->cwr = is_tcp_flag_set('W', flags);

	if (tcp_options == NULL) {
		packet->flags |= FLAG_OPTIONS_NOCHECK;
	} else if (tcp_options->length > 0) {
		/* Copy TCP options into packet */
		memcpy(tcp_option_start, tcp_options->data,
		       tcp_options->length);
	}

	return packet;
}
Exemplo n.º 3
0
struct packet *new_icmp_packet(int address_family,
				enum direction_t direction,
				const char *type_string,
				const char *code_string,
				int protocol,
				u32 tcp_start_sequence,
				u32 payload_bytes,
				s64 mtu,
				char **error)
{
	s32 type = -1;	/* bad type; means "unknown so far" */
	s32 code = -1;	/* bad code; means "unknown so far" */

	struct packet *packet = NULL;  /* the newly-allocated result packet */
	/* Calculate lengths in bytes of all sections of the packet.
	 * For now we only support the most common ICMP message
	 * format, which includes at the end the original outgoing IP
	 * header and the first 8 bytes after that (which will
	 * typically have the port info needed to demux the message).
	 */
	const int ip_fixed_bytes = ip_header_len(address_family);
	const int ip_option_bytes = 0;
	const int ip_header_bytes = ip_fixed_bytes + ip_option_bytes;
	const int echoed_bytes = ip_fixed_bytes + ICMP_ECHO_BYTES;
	const int icmp_bytes = icmp_header_len(address_family) + echoed_bytes;
	const int ip_bytes = ip_header_bytes + icmp_bytes;

	/* Sanity-check all the various lengths */
	if (ip_option_bytes & 0x3) {
		asprintf(error, "IP options are not padded correctly "
			 "to ensure IP header is a multiple of 4 bytes: "
			 "%d excess bytes", ip_option_bytes & 0x3);
		goto error_out;
	}
	assert((ip_header_bytes & 0x3) == 0);

	/* Parse the ICMP type and code */
	if (parse_icmp_type_and_code(address_family, type_string, code_string,
				     &type, &code, error))
		goto error_out;
	assert(is_valid_u8(type));
	assert(is_valid_u8(code));

	/* Allocate and zero out a packet object of the desired size */
	packet = packet_new(ip_bytes);
	memset(packet->buffer, 0, ip_bytes);
	packet->ip_bytes = ip_bytes;

	packet->direction = direction;
	packet->flags = 0;
	packet->ecn = 0;

	/* Set IP header fields */
	const enum ip_ecn_t ecn = ECN_NONE;
	set_packet_ip_header(packet, address_family, ip_bytes, direction, ecn,
			     icmp_protocol(address_family));

	/* Find the start of the ICMP header and then populate common fields. */
	void *icmp_header = packet_start(packet) + ip_header_bytes;
	if (set_packet_icmp_header(packet, icmp_header, address_family,
				   type, code, mtu, error))
		goto error_out;

	/* All ICMP message types currently supported by this tool
	 * include a copy of the outbound IP header and the first few
	 * bytes inside. To ensure that the inbound ICMP message gets
	 * demuxed to the correct socket in the kernel, here we
	 * construct enough of a basic IP header and during test
	 * execution we fill in the port numbers and (if specified)
	 * TCP sequence number in the TCP header.
	 */
	u8 *echoed_ip = packet_echoed_ip_header(packet);
	const int echoed_ip_bytes = (ip_fixed_bytes +
				     layer4_header_len(protocol) +
				     payload_bytes);
	set_ip_header(echoed_ip, address_family, echoed_ip_bytes,
		      reverse_direction(direction), ecn, protocol);
	if (protocol == IPPROTO_TCP) {
		u32 *seq = packet_echoed_tcp_seq(packet);
		*seq = htonl(tcp_start_sequence);
	}

	return packet;

error_out:
	if (packet != NULL)
		packet_free(packet);
	return NULL;
}