Esempio n. 1
0
/******************************************************************************
 * This is the mail loop when running over sockets, receiving packets and
 * sending responses.
 ******************************************************************************/
void
sockets_thread(struct Core *conf)
{
    int err;
    SOCKET fd;
    struct sockaddr_in6 sin;
    static const unsigned port = 53;
    
    /*
     * This software obtains its speed by bypassing the operating system
     * stack. Thus, running on top of 'sockets' is going to be a lot 
     * slower
     */
    fprintf(stderr, "WARNING: running in slow 'sockets' mode\n");
    
    
    /*
     * Legacy Windows is legacy.
     */
#if defined(WIN32)
    {WSADATA x; WSAStartup(0x201, &x);}
#endif
    
    /*
     * Create a socket for incoming UDP packets. By specifying IPv6, we are
     * actually going to allow both IPv4 and IPv6.
     */
    fd = socket(AF_INET6, SOCK_DGRAM, 0);
    if (fd <= 0) {
        LOG(0, "FAIL: couldn't create socket %u\n", WSAGetLastError());
        return;
    }
    
    /*
     * Set the 'reuse' feature of the socket, otherwise restarting the process
     * requires a wait before binding back to the same port number
     */
    {
        int on = 1;
        err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,sizeof(on));
        if (err < 0) {
            perror("setsockopt(SO_REUSEADDR) failed");
            exit(1); 
        }
    }

    /*
     * Enable both IPv4 and IPv6 to be used on the same sockets. This appears to
     * be needed for Windows, but not needed for Mac OS X.
     */
    {
        int on = 0;
        err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)); 
        if (err < 0) {
            perror("setsockopt(IPV6_V6ONLY) failed");
            exit(1); 
        }
    }
    
    
    /*
     * Listen on any IPv4 or IPv6 address in the system
     */
    memset(&sin, 0, sizeof(sin));
    sin.sin6_family = AF_INET6;
    sin.sin6_addr = in6addr_any;
    sin.sin6_port = htons(port);
    err = bind(fd, (struct sockaddr*)&sin, sizeof(sin));
    if (err) {
        switch (WSAGetLastError()) {
            case WSA(EACCES):
                LOG(0, "FAIL: couldn't bind to port %u: %s\n", port, 
                    "access denied");
                if (port <= 1024)
                    LOG(0, "  hint... need to be root for ports below 1024\n");
                break;
            case WSA(EADDRINUSE):
                LOG(0, "FAIL: couldn't bind to port %u: %s\n", port, 
                    "address in use");
                LOG(0, "  hint... some other server is running on that port\n");
                break;
            default:
                LOG(0, "FAIL: couldn't bind to port %u: %u\n", port,
                    WSAGetLastError());
        }
        exit(1);
    } else {
        fprintf(stderr, "UDP port: %u\n", port);
    }
    
    /*
     * Sit in loop processing incoming UDP packets
     */
    for (;;) {
        unsigned char buf[2048];
        int bytes_received;
        socklen_t sizeof_sin = sizeof(sin);
        struct DNS_Incoming request[1];
        struct DNS_OutgoingResponse response[1];
        struct Packet pkt;
        unsigned char buf2[2048];
        
        /*
         * 1. receive 'packet'
         */
        bytes_received = recvfrom(fd, 
                                  (char*)buf, sizeof(buf),
                                  0, 
                                  (struct sockaddr*)&sin, &sizeof_sin);
        if (bytes_received == 0)
            continue;

        
        /*
         * 2. parse 'packet' into a 'request'
         */
        proto_dns_parse(request, buf, 0, bytes_received);
        if (!request->is_valid)
            continue;


        /*
         * 3. resolve 'request' into a 'repsonse'
         */
        resolver_init(response, 
                      request->query_name.name, 
                      request->query_name.length, 
                      request->query_type,
                      request->id,
                      request->opcode);
            
        resolver_algorithm(conf->db, response, request);
            

        /*
         * 4. format the 'response' into a 'packet'
         */
        pkt.buf = buf2;
        pkt.max = sizeof(buf2);
        pkt.offset = 0;
        dns_format_response(response, &pkt);
            
        /*
         * 5. Transmit the 'packet'
         */
        if (pkt.offset < pkt.max) {
            sendto(fd, 
                   (char*)pkt.buf, pkt.offset, 0,
                   (struct sockaddr*)&sin,
                   sizeof_sin);
        }
    }
}
Esempio n. 2
0
/*
 * Read a character from a connection w/ timeout
 */
ssize_t
_fetch_read(conn_t *conn, char *buf, size_t len)
{
	struct timeval now, timeout, wait;
	fd_set readfds;
	ssize_t rlen, total;
	int r;

	if (fetchTimeout) {
		FD_ZERO(&readfds);
		gettimeofday(&timeout, NULL);
		timeout.tv_sec += fetchTimeout;
	}

	total = 0;
	while (len > 0) {
		while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
			FD_SET(conn->sd, &readfds);
			gettimeofday(&now, NULL);
			wait.tv_sec = timeout.tv_sec - now.tv_sec;
			wait.tv_usec = timeout.tv_usec - now.tv_usec;
			if (wait.tv_usec < 0) {
				wait.tv_usec += 1000000;
				wait.tv_sec--;
			}
			if (wait.tv_sec < 0) {
				errno = WSA(ETIMEDOUT);
				_fetch_syserr();
				return (-1);
			}
			errno = 0;
			r = select(conn->sd + 1, &readfds, NULL, NULL, &wait);
			if (r == -1) {
				if (errno == EINTR && fetchRestartCalls)
					continue;
				_fetch_syserr();
				return (-1);
			}
		}
#ifdef WITH_SSL
		if (conn->ssl != NULL)
			rlen = SSL_read(conn->ssl, buf, len);
		else
#endif
#ifdef flagWIN32
			rlen = recv(conn->sd, buf, len, 0);
#else
			rlen = read(conn->sd, buf, len);
#endif
		if (rlen == 0)
			break;
		if (rlen < 0) {
			if (errno == EINTR && fetchRestartCalls)
				continue;
			return (-1);
		}
		len -= rlen;
		buf += rlen;
		total += rlen;
	}
	return (total);
}
Esempio n. 3
0
/*
 * Write a vector to a connection w/ timeout
 * Note: can modify the iovec.
 */
ssize_t
_fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
{
	struct timeval now, timeout, wait;
	fd_set writefds;
	ssize_t wlen, total;
	int r;

	if (fetchTimeout) {
		FD_ZERO(&writefds);
		gettimeofday(&timeout, NULL);
		timeout.tv_sec += fetchTimeout;
	}

	total = 0;
	while (iovcnt > 0) {
		while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
			FD_SET(conn->sd, &writefds);
			gettimeofday(&now, NULL);
			wait.tv_sec = timeout.tv_sec - now.tv_sec;
			wait.tv_usec = timeout.tv_usec - now.tv_usec;
			if (wait.tv_usec < 0) {
				wait.tv_usec += 1000000;
				wait.tv_sec--;
			}
			if (wait.tv_sec < 0) {
				errno = WSA(ETIMEDOUT);
				_fetch_syserr();
				return (-1);
			}
			errno = 0;
			r = select(conn->sd + 1, NULL, &writefds, NULL, &wait);
			if (r == -1) {
				if (errno == WSA(EINTR) && fetchRestartCalls)
					continue;
				return (-1);
			}
		}
		errno = 0;
#ifdef WITH_SSL
		if (conn->ssl != NULL)
			wlen = SSL_write(conn->ssl,
			    iov->iov_base, iov->iov_len);
		else
#endif
#ifdef flagWIN32
			wlen = send(conn->sd, iov->iov_base, iov->iov_len, 0);
#else
			wlen = writev(conn->sd, iov, iovcnt);
#endif
		if (wlen == 0) {
			/* we consider a short write a failure */
			errno = EPIPE;
			_fetch_syserr();
			return (-1);
		}
		if (wlen < 0) {
			if (errno == EINTR && fetchRestartCalls)
				continue;
			return (-1);
		}
		total += wlen;
		while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
			wlen -= iov->iov_len;
			iov++;
			iovcnt--;
		}
		if (iovcnt > 0) {
			iov->iov_len -= wlen;
			iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
		}
	}
Esempio n. 4
0
/*
 * Set error code according to errno
 */
void
_fetch_syserr(void)
{
	switch (errno) {
	case 0:
		fetchLastErrCode = FETCH_OK;
		break;
	case EPERM:
	case WSA(EACCES):
	case EROFS:
#ifndef flagWIN32
	case EAUTH:
	case ENEEDAUTH:
#endif
		fetchLastErrCode = FETCH_AUTH;
		break;
	case ENOENT:
	case EISDIR: /* XXX */
		fetchLastErrCode = FETCH_UNAVAIL;
		break;
	case ENOMEM:
		fetchLastErrCode = FETCH_MEMORY;
		break;
	case EBUSY:
	case EAGAIN:
		fetchLastErrCode = FETCH_TEMP;
		break;
	case EEXIST:
		fetchLastErrCode = FETCH_EXISTS;
		break;
	case ENOSPC:
		fetchLastErrCode = FETCH_FULL;
		break;
	case WSA(EADDRINUSE):
	case WSA(EADDRNOTAVAIL):
	case WSA(ENETDOWN):
	case WSA(ENETUNREACH):
	case WSA(ENETRESET):
	case WSA(EHOSTUNREACH):
		fetchLastErrCode = FETCH_NETWORK;
		break;
	case WSA(ECONNABORTED):
	case WSA(ECONNRESET):
		fetchLastErrCode = FETCH_ABORT;
		break;
	case WSA(ETIMEDOUT):
		fetchLastErrCode = FETCH_TIMEOUT;
		break;
	case WSA(ECONNREFUSED):
	case WSA(EHOSTDOWN):
		fetchLastErrCode = FETCH_DOWN;
		break;
default:
		fetchLastErrCode = FETCH_UNKNOWN;
	}
	snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno));
}