Beispiel #1
0
int
main(void)
{
    int flag, status;
    socklen_t flaglen;
    struct addrinfo *ai4, *ai6;
    struct addrinfo hints;
    char addr[INET6_ADDRSTRLEN];
    char *p;
    socket_type fd;
    static const char *port = "119";
    static const char *ipv6_addr = "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210";

#ifndef HAVE_INET6
    skip_all("IPv6 not supported");
#endif

    /* Set up the plan. */
    plan(34);

    /* Get IPv4 and IPv6 sockaddrs to use for subsequent tests. */
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_NUMERICHOST;
    hints.ai_socktype = SOCK_STREAM;
    status = getaddrinfo("127.0.0.1", port, &hints, &ai4);
    if (status != 0)
        bail("getaddrinfo on 127.0.0.1 failed: %s", gai_strerror(status));
    status = getaddrinfo(ipv6_addr, port, &hints, &ai6);
    if (status != 0)
        bail("getaddr on %s failed: %s", ipv6_addr, gai_strerror(status));

    /* Test network_sockaddr_sprint. */
    ok(network_sockaddr_sprint(addr, sizeof(addr), ai6->ai_addr),
       "sprint of IPv6 address");
    for (p = addr; *p != '\0'; p++)
        if (islower((unsigned char) *p))
            *p = toupper((unsigned char) *p);
    is_string(ipv6_addr, addr, "...with right results");

    /* Test network_sockaddr_port. */
    is_int(119, network_sockaddr_port(ai6->ai_addr), "sockaddr_port IPv6");

    /* Test network_sockaddr_equal. */
    ok(network_sockaddr_equal(ai6->ai_addr, ai6->ai_addr),
       "sockaddr_equal IPv6");
    ok(!network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr),
       "...and not equal to IPv4");
    ok(!network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr),
       "...other way around");
    freeaddrinfo(ai6);

    /* Test IPv4 mapped addresses. */
    status = getaddrinfo("::ffff:7f00:1", NULL, &hints, &ai6);
    if (status != 0)
        bail("getaddr on ::ffff:7f00:1 failed: %s", gai_strerror(status));
    ok(network_sockaddr_sprint(addr, sizeof(addr), ai6->ai_addr),
       "sprint of IPv4-mapped address");
    is_string("127.0.0.1", addr, "...with right IPv4 result");
    ok(network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr),
       "sockaddr_equal of IPv4-mapped address");
    ok(network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr),
       "...and other way around");
    freeaddrinfo(ai4);
    status = getaddrinfo("127.0.0.2", NULL, &hints, &ai4);
    if (status != 0)
        bail("getaddrinfo on 127.0.0.2 failed: %s", gai_strerror(status));
    ok(!network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr),
       "...but not some other address");
    ok(!network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr),
       "...and the other way around");
    freeaddrinfo(ai6);
    freeaddrinfo(ai4);

    /* Tests for network_addr_compare. */
    is_addr_compare(1, ipv6_addr,   ipv6_addr,     NULL);
    is_addr_compare(1, ipv6_addr,   ipv6_addr,     "128");
    is_addr_compare(1, ipv6_addr,   ipv6_addr,     "60");
    is_addr_compare(1, "::127",     "0:0::127",    "128");
    is_addr_compare(1, "::127",     "0:0::128",    "120");
    is_addr_compare(0, "::127",     "0:0::128",    "128");
    is_addr_compare(0, "::7fff",    "0:0::8000",   "113");
    is_addr_compare(1, "::7fff",    "0:0::8000",   "112");
    is_addr_compare(0, "::3:ffff",  "::2:ffff",    "120");
    is_addr_compare(0, "::3:ffff",  "::2:ffff",    "119");
    is_addr_compare(0, "ffff::1",   "7fff::1",     "1");
    is_addr_compare(1, "ffff::1",   "7fff::1",     "0");
    is_addr_compare(0, "fffg::1",   "fffg::1",     NULL);
    is_addr_compare(0, "ffff::1",   "7fff::1",     "-1");
    is_addr_compare(0, "ffff::1",   "ffff::1",     "-1");
    is_addr_compare(0, "ffff::1",   "ffff::1",     "129");

    /* Test setting various socket options. */
    fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_IP);
    if (fd == INVALID_SOCKET)
        sysbail("cannot create socket");
    network_set_reuseaddr(fd);
#ifdef SO_REUSEADDR
    flag = 0;
    flaglen = sizeof(flag);
    is_int(0, getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, &flaglen),
           "Getting SO_REUSEADDR works");
    ok(flag, "...and it is set");
#else
    skip_block(2, "SO_REUSEADDR not supported");
#endif
    network_set_v6only(fd);
#ifdef IPV6_V6ONLY
    flag = 0;
    flaglen = sizeof(flag);
    is_int(0, getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, &flaglen),
           "Getting IPV6_V6ONLY works");
    ok(flag, "...and it is set");
#else
    skip_block(2, "IPV6_V6ONLY not supported");
#endif
    network_set_freebind(fd);
#ifdef IP_FREEBIND
    flag = 0;
    flaglen = sizeof(flag);
    is_int(0, getsockopt(fd, IPPROTO_IP, IP_FREEBIND, &flag, &flaglen),
           "Getting IP_FREEBIND works");
    ok(flag, "...and it is set");
#else
    skip_block(2, "IP_FREEBIND not supported");
#endif
    close(fd);

    return 0;
}
Beispiel #2
0
Datei: lbcd.c Projekt: rra/lbcd
/*
 * Receive request packet and verify the integrity and format of the reply.
 * This routine is REQUIRED to sanitize the request packet.  All other program
 * routines can expect that the packet is safe to read once it is passed on.
 *
 * Returns a newly-allocated lbcd_request struct on success and NULL on
 * failure.
 */
static struct request *
request_recv(struct lbcd_config *config, socket_type fd)
{
    struct sockaddr_storage addr;
    struct sockaddr *sockaddr;
    socklen_t addrlen;
    ssize_t result;
    char raw[LBCD_MAXMESG];
    char source[INET6_ADDRSTRLEN] = "UNKNOWN";
    struct lbcd_request *packet;
    unsigned int protocol, id, operation, nservices, i;
    size_t expected;
    struct request *request;
    char *service;

    /* Receive the UDP packet from the wire. */
    addrlen = sizeof(addr);
    sockaddr = (struct sockaddr *) &addr;
    result = recvfrom(fd, raw, sizeof(raw), 0, sockaddr, &addrlen);
    if (result <= 0) {
        syswarn("cannot receive packet");
        return NULL;
    }

    /* Format the client address for logging. */
    if (!network_sockaddr_sprint(source, sizeof(source), sockaddr))
        syswarn("cannot convert client address to string");

    /* Ensure the packet is large enough to contain the header. */
    if ((size_t) result < sizeof(struct lbcd_header)) {
        warn("client %s: short packet received (length %lu)", source,
             (unsigned long) result);
        return NULL;
    }

    /* Extract the header fields. */
    packet = (struct lbcd_request *) raw;
    protocol  = ntohs(packet->h.version);
    id        = ntohs(packet->h.id);
    operation = ntohs(packet->h.op);
    nservices = ntohs(packet->h.status);

    /* Now, ensure the request packet is exactly the correct size. */
    expected = sizeof(struct lbcd_header);
    if (protocol == 3) {
        if (nservices > LBCD_MAX_SERVICES) {
            warn("client %s: too many services in request (%u)", source,
                 nservices);
            return NULL;
        }
        expected += nservices * sizeof(lbcd_name_type);
    }
    if ((size_t) result != expected) {
        warn("client %s: incorrect packet size (%lu != %lu)", source,
             (unsigned long) result, (unsigned long) expected);
        return NULL;
    }

    /* The packet appears valid.  Create the request struct. */
    request = xcalloc(1, sizeof(struct request));
    request->source    = xstrdup(source);
    request->addrlen   = addrlen;
    request->addr      = xmalloc(addrlen);
    memcpy(request->addr, &addr, addrlen);
    request->protocol  = protocol;
    request->id        = id;
    request->operation = operation;
    request->services  = vector_new();

    /* Check protocol number. */
    if (protocol != 2 && protocol != 3) {
        warn("client %s: protocol version %u unsupported", source, protocol);
        send_status(request, fd, LBCD_STATUS_VERSION);
        goto fail;
    }

    /*
     * Protocol version 3 takes a client-supplied list of services, with the
     * number of client-provided services given in the otherwise-unused status
     * field of the request header.
     */
    if (request->protocol == 3)
        for (i = 0; i < nservices; i++) {
            service = xstrndup(packet->names[i], sizeof(lbcd_name_type));
            if (!service_allowed(config, service)) {
                warn("client %s: service %s not allowed", source, service);
                send_status(request, fd, LBCD_STATUS_ERROR);
                free(service);
                goto fail;
            }
            vector_add(request->services, service);
            free(service);
        }
    return request;

fail:
    request_free(request);
    return NULL;
}