Esempio n. 1
0
/* Broadcast a message to all the descriptors in fds. Returns -1 if any of the
   sends failed. */
int ncat_broadcast(fd_set *fds, const fd_list_t *fdlist, const char *msg, size_t size)
{
    struct fdinfo *fdn;
    int i, ret;

    if (o.recvonly)
        return 0;

    ret = 0;
    for (i = 0; i <= fdlist->fdmax; i++) {
        if (!FD_ISSET(i, fds))
            continue;

        fdn = get_fdinfo(fdlist, i);
        if (fdinfo_send(fdn, msg, size) <= 0) {
	    if (o.debug > 1)
		logdebug("Error sending to fd %d: %s.\n", i, socket_strerror(socket_errno()));
	    ret = -1;
        }
    }

    ncat_log_send(msg, size);

    return ret;
}
/* If we are sending a large amount of data, we might momentarily run out of send
   space and get an EAGAIN when we send. Temporarily convert a socket to
   blocking more, do the send, and unblock it again. Assumes that the socket was
   in nonblocking mode to begin with; it has the side effect of leaving the
   socket nonblocking on return. */
static int blocking_fdinfo_send(struct fdinfo *fdn, const char *buf, size_t size)
{
    int ret;

    block_socket(fdn->fd);
    ret = fdinfo_send(fdn, buf, size);
    unblock_socket(fdn->fd);

    return ret;
}
Esempio n. 3
0
int ncat_send(struct fdinfo *fdn, const char *buf, size_t size)
{
    int n;

    if (o.recvonly)
        return size;

    n = fdinfo_send(fdn, buf, size);
    if (n <= 0)
	return n;

    ncat_log_send(buf, size);

    return n;
}
/* Do a GET, HEAD, or POST transaction. */
static int do_transaction(struct http_request *request,
    struct socket_buffer *client_sock, struct socket_buffer *server_sock)
{
    char buf[BUFSIZ];
    struct http_response response;
    char *line;
    char *request_str, *response_str;
    size_t len;
    int code, n;

    /* We don't handle the chunked transfer encoding, which in the absence of a
       Content-Length is the only way we know the end of a request body. RFC
       2616, section 4.4 says, "If a request contains a message-body and a
       Content-Length is not given, the server SHOULD respond with 400 (bad
       request) if it cannot determine the length of the message, or with 411
       (length required) if it wishes to insist on receiving a valid
       Content-Length." */
    if (strcmp(request->method, "POST") == 0 && request->content_length == 0) {
        if (o.debug)
            logdebug("POST request with no Content-Length.\n");
        return 400;
    }

    /* The version we use to talk to the server. */
    request->version = HTTP_10;

    /* Remove headers that only apply to our connection with the client. */
    code = http_header_remove_hop_by_hop(&request->header);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error removing hop-by-hop headers.\n");
        return code;
    }

    /* Build the Host header. */
    if (request->uri.port == -1 || request->uri.port == 80)
        n = Snprintf(buf, sizeof(buf), "%s", request->uri.host);
    else
        n = Snprintf(buf, sizeof(buf), "%s:%hu", request->uri.host, request->uri.port);
    if (n < 0 || n >= sizeof(buf)) {
        /* Request Entity Too Large. */
        return 501;
    }
    request->header = http_header_set(request->header, "Host", buf);

    request->header = http_header_set(request->header, "Connection", "close");

    /* Send the request to the server. */
    request_str = http_request_to_string(request, &len);
    n = send(server_sock->fdn.fd, request_str, len, 0);
    free(request_str);
    if (n < 0)
        return 504;
    /* Send the request body, if any. Count up to Content-Length. */
    while (request->bytes_transferred < request->content_length) {
        n = socket_buffer_read(client_sock, buf, MIN(sizeof(buf), request->content_length - request->bytes_transferred));
        if (n < 0)
            return 504;
        if (n == 0)
            break;
        request->bytes_transferred += n;
        n = send(server_sock->fdn.fd, buf, n, 0);
        if (n < 0)
            return 504;
    }
    if (o.debug && request->bytes_transferred < request->content_length)
        logdebug("Received only %lu request body bytes (Content-Length was %lu).\n", request->bytes_transferred, request->content_length);


    /* Read the response. */
    code = http_read_status_line(server_sock, &line);
    if (o.debug > 1)
        logdebug("Status-Line: %s", line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading Status-Line.\n");
        return 0;
    }
    code = http_parse_status_line(line, &response);
    free(line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing Status-Line.\n");
        return 0;
    }

    code = http_read_header(server_sock, &line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading header.\n");
        return 0;
    }
    if (o.debug > 1)
        logdebug("Response header:\n%s", line);

    code = http_response_parse_header(&response, line);
    free(line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing response header.\n");
        return 0;
    }


    /* The version we use to talk to the client. */
    response.version = HTTP_10;

    /* Remove headers that only apply to our connection with the server. */
    code = http_header_remove_hop_by_hop(&response.header);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error removing hop-by-hop headers.\n");
        return code;
    }

    response.header = http_header_set(response.header, "Connection", "close");

    /* Send the response to the client. */
    response_str = http_response_to_string(&response, &len);
    n = fdinfo_send(&client_sock->fdn, response_str, len);
    free(response_str);
    if (n < 0) {
        http_response_free(&response);
        return 504;
    }
    /* If the Content-Length is 0, read until the connection is closed.
       Otherwise read until the Content-Length. At this point it's too late to
       return our own error code so return 0 in case of any error. */
    while (response.content_length == 0
        || response.bytes_transferred < response.content_length) {
        size_t remaining = response.content_length - response.bytes_transferred;
        size_t count;

        count = sizeof(buf);
        if (response.content_length > 0 && remaining < count)
            count = remaining;
        n = socket_buffer_read(server_sock, buf, count);
        if (n <= 0)
            break;
        response.bytes_transferred += n;
        n = fdinfo_send(&client_sock->fdn, buf, n);
        if (n < 0)
            break;
    }

    http_response_free(&response);

    return 0;
}
static int handle_connect(struct socket_buffer *client_sock,
    struct http_request *request)
{
    union sockaddr_u su;
    size_t sslen = sizeof(su.storage);
    int maxfd, s, rc;
    char *line;
    size_t len;
    fd_set m, r;

    if (request->uri.port == -1) {
        if (o.verbose)
            logdebug("No port number in CONNECT URI.\n");
        return 400;
    }
    if (o.debug > 1)
        logdebug("CONNECT to %s:%hu.\n", request->uri.host, request->uri.port);

    rc = resolve(request->uri.host, request->uri.port, &su.storage, &sslen, o.af);
    if (rc != 0) {
        if (o.debug) {
            logdebug("Can't resolve name \"%s\": %s.\n",
                request->uri.host, gai_strerror(rc));
        }
        return 504;
    }

    s = Socket(su.storage.ss_family, SOCK_STREAM, IPPROTO_TCP);

    if (connect(s, &su.sockaddr, sslen) == -1) {
        if (o.debug)
            logdebug("Can't connect to %s.\n", inet_socktop(&su));
        Close(s);
        return 504;
    }

    send_string(&client_sock->fdn, http_code2str(200));

    /* Clear out whatever is left in the socket buffer. The client may have
       already sent the first part of its request to the origin server. */
    line = socket_buffer_remainder(client_sock, &len);
    if (send(s, line, len, 0) < 0) {
        if (o.debug)
            logdebug("Error sending %lu leftover bytes: %s.\n", (unsigned long) len, strerror(errno));
        Close(s);
        return 0;
    }

    maxfd = client_sock->fdn.fd < s ? s : client_sock->fdn.fd;
    FD_ZERO(&m);
    FD_SET(client_sock->fdn.fd, &m);
    FD_SET(s, &m);

    errno = 0;

    while (!socket_errno() || socket_errno() == EINTR) {
        char buf[DEFAULT_TCP_BUF_LEN];
        int len, rc;

        r = m;

        fselect(maxfd + 1, &r, NULL, NULL, NULL);

        zmem(buf, sizeof(buf));

        if (FD_ISSET(client_sock->fdn.fd, &r)) {
            do {
                do {
                    len = fdinfo_recv(&client_sock->fdn, buf, sizeof(buf));
                } while (len == -1 && socket_errno() == EINTR);
                if (len <= 0)
                    goto end;

                do {
                    rc = send(s, buf, len, 0);
                } while (rc == -1 && socket_errno() == EINTR);
                if (rc == -1)
                    goto end;
            } while (fdinfo_pending(&client_sock->fdn));
        }

        if (FD_ISSET(s, &r)) {
            do {
                len = recv(s, buf, sizeof(buf), 0);
            } while (len == -1 && socket_errno() == EINTR);
            if (len <= 0)
                goto end;

            do {
                rc = fdinfo_send(&client_sock->fdn, buf, len);
            } while (rc == -1 && socket_errno() == EINTR);
            if (rc == -1)
                goto end;
        }
    }
end:

    close(s);

    return 0;
}
/* send a '\0'-terminated string. */
static int send_string(struct fdinfo *fdn, const char *s)
{
    return fdinfo_send(fdn, s, strlen(s));
}