bool probe_write_payload_ext(probe_t * probe, const void * bytes, size_t num_bytes, size_t offset) { layer_t * payload_layer; if (!(payload_layer = probe_get_layer_payload(probe))) { goto ERR_PROBE_GET_LAYER_PAYLOAD; } if (num_bytes > probe_get_payload_size(probe)) { if(!probe_payload_resize(probe, num_bytes)) { goto ERR_PROBE_PAYLOAD_RESIZE; } } if (!layer_write_payload_ext(payload_layer, bytes, num_bytes, offset)) { goto ERR_LAYER_WRITE_PAYLOAD_EXT; } return true; ERR_LAYER_WRITE_PAYLOAD_EXT: ERR_PROBE_PAYLOAD_RESIZE: ERR_PROBE_GET_LAYER_PAYLOAD: return false; }
bool network_tag_probe(network_t * network, probe_t * probe) { uint16_t tag, // Network-side endianness checksum; // Host-side endianness size_t payload_size = probe_get_payload_size(probe); size_t tag_size = sizeof(uint16_t); size_t num_layers = probe_get_num_layers(probe); // For probes having a payload of size 0 and a "body" field (like icmp) layer_t * last_layer; bool tag_in_body = false; /* The probe gets assigned a unique tag. Currently we encode it in the UDP * checksum, but I guess the tag will be protocol dependent. Also, since the * tag changes the probe, the user has no direct control of what is sent on * the wire, since typically a packet is tagged just before sending, after * scheduling, to maximize the number of probes in flight. Available space * in the headers is used for tagging, + encoding some information... */ /* XXX hardcoded XXX */ /* 1) Set payload = tag : this is only possible if both the payload and the * checksum have not been set by the user. * We need a list of used tags = in flight... + an efficient way to get a * free one... Also, we need to share tags between several instances ? * randomized tags ? Also, we need to determine how much size we have to * encode information. */ if (num_layers < 2 || !(last_layer = probe_get_layer(probe, num_layers - 2))) { fprintf(stderr, "network_tag_probe: not enough layer (num_layers = %d)\n", (unsigned int)num_layers); goto ERR_GET_LAYER; } // The last layer is the payload, the previous one is the last protocol layer. // If this layer has a "body" field like icmp, we have no payload and // we use the body field. if (last_layer->protocol && protocol_get_field(last_layer->protocol, "body")) { tag_in_body = true; } tag = htons(network_get_available_tag(network)); // Write the tag at offset zero of the payload if (tag_in_body) { probe_write_field(probe, "body", &tag, tag_size); } else { if (payload_size < tag_size) { fprintf(stderr, "Payload too short (payload_size = %u tag_size = %u)\n", (unsigned int)payload_size, (unsigned int)tag_size); goto ERR_INVALID_PAYLOAD; } if (!(probe_write_payload(probe, &tag, tag_size))) { goto ERR_PROBE_WRITE_PAYLOAD; } } // Fix checksum to get a well-formed packet if (!(probe_update_checksum(probe))) { fprintf(stderr, "Can't update fields\n"); goto ERR_PROBE_UPDATE_FIELDS; } // Retrieve the checksum of UDP/TCP/ICMP checksum (host-side endianness) if (!(probe_extract_tag(probe, &checksum))) { fprintf(stderr, "Can't extract tag\n"); goto ERR_PROBE_EXTRACT_CHECKSUM; } // Write the probe ID in the UDP/TCP/ICMP checksum if (!(probe_set_tag(probe, ntohs(tag)))) { fprintf(stderr, "Can't set tag\n"); goto ERR_PROBE_SET_TAG; } // Write the tag using the network-side endianness in the payload checksum = htons(checksum); if (tag_in_body) { if (!(probe_write_field(probe, "body", &checksum, tag_size))) { fprintf(stderr, "Can't set body\n"); goto ERR_PROBE_SET_FIELD; } } else { if (!probe_write_payload(probe, &checksum, tag_size)) { fprintf(stderr, "Can't write payload (2)\n"); goto ERR_BUFFER_WRITE_BYTES2; } } return true; ERR_PROBE_SET_FIELD: ERR_BUFFER_WRITE_BYTES2: ERR_PROBE_SET_TAG: ERR_PROBE_EXTRACT_CHECKSUM: ERR_PROBE_UPDATE_FIELDS: ERR_PROBE_WRITE_PAYLOAD: ERR_INVALID_PAYLOAD: ERR_GET_LAYER: return false; }