Beispiel #1
0
int bind_peer(int fd, int fd_from)
{
    struct addrinfo from;
    struct sockaddr_storage ss;
    int res, trans = 1;

    memset(&from, 0, sizeof(from));
    from.ai_addr = (struct sockaddr*)&ss;
    from.ai_addrlen = sizeof(ss);

    /* getpeername can fail with ENOTCONN if connection was dropped before we
     * got here */
    res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen);
    CHECK_RES_RETURN(res, "getpeername");
#ifndef IP_BINDANY /* use IP_TRANSPARENT */
    res = setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &trans, sizeof(trans));
    CHECK_RES_DIE(res, "setsockopt");
#else
    if (from.ai_addr->sa_family==AF_INET) { /* IPv4 */
        res = setsockopt(fd, IPPROTO_IP, IP_BINDANY, &trans, sizeof(trans));
        CHECK_RES_RETURN(res, "setsockopt IP_BINDANY");
#ifdef IPV6_BINDANY
    } else { /* IPv6 */
        res = setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &trans, sizeof(trans));
        CHECK_RES_RETURN(res, "setsockopt IPV6_BINDANY");
#endif /* IPV6_BINDANY */
    }
#endif /* IP_TRANSPARENT / IP_BINDANY */
    res = bind(fd, from.ai_addr, from.ai_addrlen);
    CHECK_RES_RETURN(res, "bind");

    return 0;
}
Beispiel #2
0
int handle_connection(struct map_queue *q)
{
	char *buf = (char*)&q->port;
	ssize_t size_r, size_w;
	while(q->size_r < sizeof(q->port))
	{
		size_r = read(q->fd, buf + q->size_r, sizeof(q->port) - q->size_r);
		if (size_r == -1) {
			switch (errno) {
				case EAGAIN:
					return FD_NODATA;

				case ECONNRESET:
				case EPIPE:
					return FD_CNXCLOSED;
			}
		}
		CHECK_RES_RETURN(size_r, "read");
		if (size_r == 0)
			return FD_CNXCLOSED;
		q->size_r += size_r;
	}

	if (verbose) fprintf(stderr, "request fd %d: %d\n", q->fd, ntohs(q->port));

	if(q->ip == 0xFFFFFFFF)
		q->ip = htonl(get_ip(ntohs(q->port)));

	if (verbose) fprintf(stderr, "got ip %u associated with port %u\n", ntohl(q->ip), ntohs(q->port));

	buf = (char*)&q->ip;
	while(q->size_w < sizeof(q->ip))
	{
		size_w = write(q->fd, buf + q->size_w, sizeof(q->ip) - q->size_w);
		if (size_w == -1) {
			switch (errno) {
				case EAGAIN:
					return FD_STALLED;

				case ECONNRESET:
				case EPIPE:
					return FD_CNXCLOSED;
			}
		}
		CHECK_RES_RETURN(size_w, "write");
		q->size_w += size_w;
	}
	q->size_r = 0;
	q->size_w = 0;
	q->ip = 0xFFFFFFFF;
	return 1;
}
Beispiel #3
0
/* 
 * moves data from one fd to other
 *
 * returns number of bytes copied if success
 * returns 0 (FD_CNXCLOSED) if incoming socket closed
 * returns FD_NODATA if no data was available
 * returns FD_STALLED if data was read, could not be written, and has been
 * stored in temporary buffer.
 */
int fd2fd(struct queue *target_q, struct queue *from_q)
{
   char buffer[BUFSIZ];
   int target, from, size_r, size_w;

   target = target_q->fd;
   from = from_q->fd;

   size_r = read(from, buffer, sizeof(buffer));
   if (size_r == -1) {
       switch (errno) {
       case EAGAIN:
           if (verbose)
               fprintf(stderr, "reading 0 from %d\n", from);
           return FD_NODATA;

       case ECONNRESET:
       case EPIPE:
           return FD_CNXCLOSED;
       }
   }

   CHECK_RES_RETURN(size_r, "read");

   if (size_r == 0)
      return FD_CNXCLOSED;

   size_w = write(target, buffer, size_r);
   /* process -1 when we know how to deal with it */
   if (size_w == -1) {
       switch (errno) {
       case EAGAIN:
           /* write blocked: Defer data */
           defer_write(target_q, buffer, size_r);
           return FD_STALLED;

       case ECONNRESET:
       case EPIPE:
           /* remove end closed -- drop the connection */
           return FD_CNXCLOSED;
       }
   } else if (size_w < size_r) {
       /* incomplete write -- defer the rest of the data */
       defer_write(target_q, buffer + size_w, size_r - size_w);
       return FD_STALLED;
   }

   CHECK_RES_RETURN(size_w, "write");

   return size_w;
}
Beispiel #4
0
/* Connect to first address that works and returns a file descriptor, or -1 if
 * none work. 
 * If transparent proxying is on, use fd_from peer address on external address
 * of new file descriptor. */
int connect_addr(struct connection *cnx, int fd_from)
{
    struct addrinfo *a, from;
    struct sockaddr_storage ss;
    char buf[NI_MAXHOST];
    int fd, res;

    memset(&from, 0, sizeof(from));
    from.ai_addr = (struct sockaddr*)&ss;
    from.ai_addrlen = sizeof(ss);

    res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen);
    CHECK_RES_RETURN(res, "getpeername");

    for (a = cnx->proto->saddr; a; a = a->ai_next) {
        /* When transparent, make sure both connections use the same address family */
        if (transparent && a->ai_family != from.ai_addr->sa_family)
            continue;
        if (verbose) 
            fprintf(stderr, "connecting to %s family %d len %d\n", 
                    sprintaddr(buf, sizeof(buf), a),
                    a->ai_addr->sa_family, a->ai_addrlen);

        /* XXX Needs to match ai_family from fd_from when being transparent! */
        fd = socket(a->ai_family, SOCK_STREAM, 0);
        if (fd == -1) {
            log_message(LOG_ERR, "forward to %s failed:socket: %s\n",
                        cnx->proto->description, strerror(errno));
        } else {
            if (transparent) {
                res = bind_peer(fd, fd_from);
                CHECK_RES_RETURN(res, "bind_peer");
            }
            res = connect(fd, a->ai_addr, a->ai_addrlen);
            if (res == -1) {
                log_message(LOG_ERR, "forward to %s failed:connect: %s\n", 
                            cnx->proto->description, strerror(errno));
                close(fd);
            } else {
                return fd;
            }
        }
    }
    return -1;
}
Beispiel #5
0
/* libwrap (tcpd): check the connection is legal. This is necessary because
 * the actual server will only see a connection coming from localhost and can't
 * apply the rules itself.
 *
 * Returns -1 if access is denied, 0 otherwise
 */
int check_access_rights(int in_socket, const char* service)
{
#ifdef LIBWRAP
    union {
        struct sockaddr saddr;
        struct sockaddr_storage ss;
    } peer;
    socklen_t size = sizeof(peer);
    char addr_str[NI_MAXHOST], host[NI_MAXHOST];
    int res;

    res = getpeername(in_socket, &peer.saddr, &size);
    CHECK_RES_RETURN(res, "getpeername");

    /* extract peer address */
    res = getnameinfo(&peer.saddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
    if (res) {
        if (verbose)
            fprintf(stderr, "getnameinfo(NI_NUMERICHOST):%s\n", gai_strerror(res));
        strcpy(addr_str, STRING_UNKNOWN);
    }
    /* extract peer name */
    strcpy(host, STRING_UNKNOWN);
    if (!numeric) {
        res = getnameinfo(&peer.saddr, size, host, sizeof(host), NULL, 0, NI_NAMEREQD);
        if (res) {
            if (verbose)
                fprintf(stderr, "getnameinfo(NI_NAMEREQD):%s\n", gai_strerror(res));
        }
    }

    if (!hosts_ctl(service, host, addr_str, STRING_UNKNOWN)) {
        if (verbose)
            fprintf(stderr, "access denied\n");
        log_message(LOG_INFO, "connection from %s(%s): access denied", host, addr_str);
        close(in_socket);
        return -1;
    }
#endif
    return 0;
}