/* rov: clasifica un anuncio contra una lista de VRPs, como manda el RFC 6811.
 *
 *   ./rov <archivo-de-vrps> <prefijo/largo> <as-de-origen>
 *
 * Un VRP es un ROA ya validado: prefijo, largo máximo y AS autorizado.
 * Solo IPv4, para que se lea el algoritmo.
 */
#include <arpa/inet.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct prefix {
    uint32_t address; /* en orden de host */
    int length;
};

static int parse_prefix(const char *text, struct prefix *out)
{
    char copy[32];
    if (strlen(text) >= sizeof copy)
        return -1;
    strcpy(copy, text);
    char *slash = strchr(copy, '/');
    if (slash == NULL)
        return -1;
    *slash = '\0';

    char *end;
    errno = 0;
    long length = strtol(slash + 1, &end, 10);
    if (errno != 0 || *end != '\0' || end == slash + 1 || length < 0 || length > 32)
        return -1;

    struct in_addr address;
    if (inet_pton(AF_INET, copy, &address) != 1)
        return -1;
    out->address = ntohl(address.s_addr);
    out->length = (int)length;
    return 0;
}

/* ¿Los primeros `length` bits de las dos direcciones son iguales? */
static int same_bits(uint32_t a, uint32_t b, int length)
{
    if (length == 0)
        return 1;
    uint32_t mask = 0xFFFFFFFFu << (32 - length);
    return (a & mask) == (b & mask);
}

/* Covered: el VRP es igual o más corto que la ruta y sus bits coinciden. */
static int covers(const struct prefix *vrp, const struct prefix *route)
{
    return vrp->length <= route->length && same_bits(vrp->address, route->address, vrp->length);
}

int main(int argc, char *argv[])
{
    if (argc != 4) {
        fprintf(stderr, "uso: %s <archivo-de-vrps> <prefijo/largo> <as-de-origen>\n", argv[0]);
        return 2;
    }

    struct prefix route;
    if (parse_prefix(argv[2], &route) != 0) {
        fprintf(stderr, "prefijo inválido: %s\n", argv[2]);
        return 2;
    }
    char *end;
    errno = 0;
    unsigned long origin = strtoul(argv[3], &end, 10);
    if (errno != 0 || *end != '\0' || end == argv[3] || origin > UINT32_MAX) {
        fprintf(stderr, "AS inválido: %s\n", argv[3]);
        return 2;
    }

    FILE *file = fopen(argv[1], "r");
    if (file == NULL) {
        perror(argv[1]);
        return 2;
    }

    int covered = 0, matched = 0;
    char line[256];
    while (fgets(line, sizeof line, file) != NULL) {
        char *comment = strchr(line, '#');
        if (comment != NULL)
            *comment = '\0';
        char text[64];
        int max_length;
        unsigned long asn;
        int fields = sscanf(line, "%63s %d %lu", text, &max_length, &asn);
        if (fields == EOF || fields == 0)
            continue;
        struct prefix vrp;
        if (fields != 3 || parse_prefix(text, &vrp) != 0) {
            fprintf(stderr, "línea inválida: %s", line);
            fclose(file);
            return 2;
        }
        if (!covers(&vrp, &route))
            continue;
        covered = 1;
        int length_ok = route.length <= max_length;
        /* AS 0 nunca autoriza a nadie: un ROA con AS 0 dice "esto no se anuncia". */
        int origin_ok = asn != 0 && origin == asn;
        printf("  cubierto por %s max %d AS %lu: largo %s, origen %s\n", text, max_length, asn,
               length_ok ? "ok" : "demasiado largo", origin_ok ? "ok" : "no coincide");
        if (length_ok && origin_ok)
            matched = 1;
    }
    if (ferror(file)) {
        perror(argv[1]);
        fclose(file);
        return 2;
    }
    if (fclose(file) != 0) {
        perror(argv[1]);
        return 2;
    }

    puts(matched ? "valid" : covered ? "invalid" : "not found");
    return 0;
}
