Ejemplo n.º 1
0
bool probe_update_fields(probe_t * probe)
{
    return probe_finalize(probe)
        && probe_update_protocol(probe)
        && probe_update_length(probe)
        && probe_update_checksum(probe);
}
Ejemplo n.º 2
0
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;
}