Example #1
0
/* Send a packet */
void
sendpkt (
	SOCKET rsock,
	sockaddr_u *dest,
	struct pkt *pkt,
	int len
	)
{
	int cc;

#ifdef DEBUG
	printf("sntp sendpkt: Packet data:\n");
	pkt_output(pkt, len, stdout);
#endif

	if (ENABLED_OPT(NORMALVERBOSE)) {
		getnameinfo(&dest->sa, SOCKLEN(dest), adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);
		printf("sntp sendpkt: Sending packet to %s... ", adr_buf);
	}

	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, SOCKLEN(dest));
	if (cc == SOCKET_ERROR) {
#ifdef DEBUG
		printf("\n sntp sendpkt: Socket error: %i. Couldn't send packet!\n", cc);
#endif
		if (errno != EWOULDBLOCK && errno != ENOBUFS) {
			/* oh well */
		}
	} else if (ENABLED_OPT(NORMALVERBOSE)) {
		printf("Packet sent.\n");
	}
}
Example #2
0
/* Send a packet */
int
sendpkt (
	SOCKET rsock,
	sockaddr_u *dest,
	struct pkt *pkt,
	int len
	)
{
	int cc;

#ifdef DEBUG
	printf("sntp sendpkt: Packet data:\n");
	pkt_output(pkt, len, stdout);
#endif

	if (ENABLED_OPT(NORMALVERBOSE)) {
		getnameinfo(&dest->sa, SOCKLEN(dest), adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);

		printf("sntp sendpkt: Sending packet to %s... ", adr_buf);
	}

	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, SOCKLEN(dest));

	if (cc == SOCKET_ERROR) {
		printf("\n sntp sendpkt: sendto error: %s. Couldn't send packet!\n", strerror(errno));
		return -1;
	} else if (ENABLED_OPT(NORMALVERBOSE))
		printf("Packet sent.\n");
	return 0;
}
Example #3
0
/*
 * Check to see if this is a valid local address, meaning that we can
 * legally bind to it.
 */
static int address_is_local(const union sock_addr *addr)
{
    union sock_addr sa1, sa2;
    int sockfd = -1;
    int e;
    int rv = 0;
    socklen_t addrlen;

    memcpy(&sa1, addr, sizeof sa1);

    /* Multicast or universal broadcast address? */
    if (sa1.sa.sa_family == AF_INET) {
        if (ntohl(sa1.si.sin_addr.s_addr) >= (224UL << 24))
            return 0;
	sa1.si.sin_port = 0;	/* Any port */
    }
#ifdef HAVE_IPV6
    else if (sa1.sa.sa_family == AF_INET6) {
        if (IN6_IS_ADDR_MULTICAST(&sa1.s6.sin6_addr))
            return 0;
	sa1.s6.sin6_port = 0;	/* Any port */
    }
#endif
    else
        return 0;

    sockfd = socket(sa1.sa.sa_family, SOCK_DGRAM, 0);
    if (sockfd < 0)
        goto err;

    if (bind(sockfd, &sa1.sa, SOCKLEN(&sa1)))
        goto err;

    addrlen = SOCKLEN(addr);
    if (getsockname(sockfd, (struct sockaddr *)&sa2, &addrlen))
        goto err;

    if (sa1.sa.sa_family != sa2.sa.sa_family)
	goto err;

    if (sa2.sa.sa_family == AF_INET)
        rv = sa1.si.sin_addr.s_addr == sa2.si.sin_addr.s_addr;
#ifdef HAVE_IPV6
    else if (sa2.sa.sa_family == AF_INET6)
        rv = IN6_ARE_ADDR_EQUAL(&sa1.s6.sin6_addr, &sa2.s6.sin6_addr);
#endif
    else
        rv = 0;

err:
    e = errno;

    if (sockfd >= 0)
        close(sockfd);

    errno = e;
    return rv;
}
Example #4
0
/* Send a packet */
int
sendpkt (
	SOCKET rsock,
	sockaddr_u *dest,
	struct pkt *pkt,
	int len
	)
{
	int cc;

#ifdef DEBUG
	if (debug > 2) {
		printf("sntp sendpkt: Packet data:\n");
		pkt_output(pkt, len, stdout);
	}
#endif
	TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n",
		  sptoa(dest)));

	cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, 
		    SOCKLEN(dest));
	if (cc == SOCKET_ERROR) {
		msyslog(LOG_ERR, "Send to %s failed, %m",
			sptoa(dest));
		return FALSE;
	}
	TRACE(1, ("Packet sent.\n"));

	return TRUE;
}
Example #5
0
/*
 * Send a nak packet (error message).
 * Error code passed in is one of the
 * standard TFTP codes, or a UNIX errno
 * offset by 100.
 */
static void nak(int f, union sock_addr *peeraddr,
		int error, const char *msg)
{
    struct tftphdr *tp;
    int length;

    tp = (struct tftphdr *)ackbuf;
    tp->th_opcode = htons((u_short) ERROR);
    tp->th_code = htons((u_short) error);

    if (error >= 100) {
        /* This is a Unix errno+100 */
        if (!msg)
            msg = strerror(error - 100);
        error = EUNDEF;
    } else {
        if ((unsigned)error >= ERR_CNT)
            error = EUNDEF;

        if (!msg)
            msg = errmsgs[error];
    }

    tp->th_code = htons((u_short) error);

    length = strlen(msg) + 1;
    memcpy(tp->th_msg, msg, length);
    length += 4;                /* Add space for header */

    if (trace)
        tpacket("sent", tp, length);
    if (sendto(f, ackbuf, length, 0, &(peeraddr->sa),
               SOCKLEN(peeraddr)) != length)
        perror("nak");
}
Example #6
0
/*
 * getnetnum - given a host name, return its net number
 *	       and (optional) full name
 */
static int
getnetnum(
	const char *hname,
	sockaddr_u *num,
	char *fullhost,
	int af
	)
{
	struct addrinfo hints, *ai = NULL;

	ZERO(hints);
	hints.ai_flags = AI_CANONNAME;
#ifdef AI_ADDRCONFIG
	hints.ai_flags |= AI_ADDRCONFIG;
#endif
	
	/*
	 * decodenetnum only works with addresses, but handles syntax
	 * that getaddrinfo doesn't:  [2001::1]:1234
	 */
	if (decodenetnum(hname, num)) {
		if (fullhost != NULL)
			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
				    LENHOSTNAME, NULL, 0, 0);
		return 1;
	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
		INSIST(sizeof(*num) >= ai->ai_addrlen);
		memcpy(num, ai->ai_addr, ai->ai_addrlen);
		if (fullhost != NULL) {
			if (ai->ai_canonname != NULL)
				strlcpy(fullhost, ai->ai_canonname,
					LENHOSTNAME);
			else
				getnameinfo(&num->sa, SOCKLEN(num),
					    fullhost, LENHOSTNAME, NULL,
					    0, 0);
		}
		return 1;
	}
	fprintf(stderr, "***Can't find host %s\n", hname);

	return 0;
}
Example #7
0
char *
socktohost(
	struct sockaddr_storage* sock
	)
{
	register char *buffer;

	LIB_GETBUF(buffer);
	if (getnameinfo((struct sockaddr *)sock, SOCKLEN(sock), buffer,
	    LIB_BUFLENGTH /* NI_MAXHOST*/, NULL, 0, 0))
		return stoa(sock);

  	return buffer;
}
Example #8
0
/*
 * is_reachable - check to see if we have a route to given destination
 */
int
is_reachable (
	struct addrinfo *dst
	)
{
	SOCKET sockfd = socket(dst->ai_family, SOCK_DGRAM, 0);

	if (-1 == sockfd) {
#ifdef DEBUG
		printf("is_reachable: Couldn't create socket\n");
#endif
		return 0;
	}
	if (connect(sockfd, dst->ai_addr, SOCKLEN((sockaddr_u *)dst->ai_addr))) {
		closesocket(sockfd);
		return 0;
	}
	closesocket(sockfd);
	return 1;
}
Example #9
0
int pick_port_bind(int sockfd, union sock_addr *myaddr,
                   unsigned int port_range_from,
                   unsigned int port_range_to)
{
    unsigned int port, firstport;
    int port_range = 0;

    if (port_range_from != 0 && port_range_to != 0) {
        port_range = 1;
    }

    firstport = port_range
        ? port_range_from + rand() % (port_range_to - port_range_from + 1)
        : 0;

    port = firstport;

    do {
        sa_set_port(myaddr, htons(port));
        if (bind(sockfd, &myaddr->sa, SOCKLEN(myaddr)) < 0) {
            /* Some versions of Linux return EINVAL instead of EADDRINUSE */
            if (!(port_range && (errno == EINVAL || errno == EADDRINUSE)))
                return -1;

            /* Normally, we shouldn't have to loop, but some situations involving
               aborted transfers make it possible. */
        } else {
            return 0;
        }

        port++;
        if (port > port_range_to)
            port = port_range_from;
    } while (port != firstport);

    return -1;
}
Example #10
0
static int
do_nodename(
	const char *nodename,
	struct addrinfo *ai,
	const struct addrinfo *hints)
{
	struct hostent *hp = NULL;
	struct sockaddr_in *sockin;
	struct sockaddr_in6 *sockin6;
	int errval;

	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
	if (ai->ai_addr == NULL)
		return (EAI_MEMORY);

	/*
	 * For an empty node name just use the wildcard.
	 * NOTE: We need to assume that the address family is
	 * set elsewhere so that we can set the appropriate wildcard
	 */
	if (nodename == NULL) {
		ai->ai_addrlen = sizeof(struct sockaddr_storage);
		if (ai->ai_family == AF_INET)
		{
			sockin = (struct sockaddr_in *)ai->ai_addr;
			sockin->sin_family = (short) ai->ai_family;
			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
		}
		else
		{
			sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
			sockin6->sin6_family = (short) ai->ai_family;
			/*
			 * we have already zeroed out the address
			 * so we don't actually need to do this
			 * This assignment is causing problems so
			 * we don't do what this would do.
			 sockin6->sin6_addr = in6addr_any;
			 */
		}
#ifdef ISC_PLATFORM_HAVESALEN
		ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
#endif

		return (0);
	}

	/*
	 * See if we have an IPv6 address
	 */
	if(strchr(nodename, ':') != NULL) {
		if (inet_pton(AF_INET6, nodename,
		    &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
			((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
			ai->ai_family = AF_INET6;
			ai->ai_addrlen = sizeof(struct sockaddr_in6);
			return (0);
		}
	}

	/*
	 * See if we have an IPv4 address
	 */
	if (inet_pton(AF_INET, nodename,
	    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
		((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
		ai->ai_family = AF_INET;
		ai->ai_addrlen = sizeof(struct sockaddr_in);
		return (0);
	}

	/*
	 * If the numeric host flag is set, don't attempt resolution
	 */
	if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
		return (EAI_NONAME);

	/*
	 * Look for a name
	 */

	errval = DNSlookup_name(nodename, AF_INET, &hp);

	if (hp == NULL) {
		if (errval == TRY_AGAIN || errval == EAI_AGAIN)
			return (EAI_AGAIN);
		else if (errval == EAI_NONAME) {
			if (inet_pton(AF_INET, nodename,
			    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
				((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
				ai->ai_family = AF_INET;
				ai->ai_addrlen = sizeof(struct sockaddr_in);
				return (0);
			}
			return (errval);
		}
		else
		{
			return (errval);
		}
	}
	ai->ai_family = hp->h_addrtype;
	ai->ai_addrlen = sizeof(struct sockaddr);
	sockin = (struct sockaddr_in *)ai->ai_addr;
	memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
	ai->ai_addr->sa_family = hp->h_addrtype;
#ifdef ISC_PLATFORM_HAVESALEN
	ai->ai_addr->sa_len = sizeof(struct sockaddr);
#endif
	if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
		ai->ai_canonname = estrdup(hp->h_name);
	return (0);
}
Example #11
0
const char *
socktohost(
	const sockaddr_u *sock
	)
{
	const char		svc[] = "ntp";
	char *			pbuf;
	char *			pliar;
	int			gni_flags;
	struct addrinfo		hints;
	struct addrinfo *	alist;
	struct addrinfo *	ai;
	sockaddr_u		addr;
	size_t			octets;
	int			a_info;

	/* reverse the address to purported DNS name */
	LIB_GETBUF(pbuf);
	gni_flags = NI_DGRAM | NI_NAMEREQD;
	if (getnameinfo(&sock->sa, SOCKLEN(sock), pbuf, LIB_BUFLENGTH,
			NULL, 0, gni_flags))
		return stoa(sock);	/* use address */

	TRACE(1, ("%s reversed to %s\n", stoa(sock), pbuf));

	/*
	 * Resolve the reversed name and make sure the reversed address
	 * is among the results.
	 */
	ZERO(hints);
	hints.ai_family = AF(sock);
	hints.ai_protocol = IPPROTO_UDP;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_flags = 0;
	alist = NULL;

	a_info = getaddrinfo(pbuf, svc, &hints, &alist);
	if (a_info == EAI_NONAME
#ifdef EAI_NODATA
	    || a_info == EAI_NODATA
#endif
	   ) {
		hints.ai_flags = AI_CANONNAME;
#ifdef AI_ADDRCONFIG
		hints.ai_flags |= AI_ADDRCONFIG;
#endif
		a_info = getaddrinfo(pbuf, svc, &hints, &alist);	
	}
#ifdef AI_ADDRCONFIG
	/* Some older implementations don't like AI_ADDRCONFIG. */
	if (a_info == EAI_BADFLAGS) {
		hints.ai_flags &= ~AI_ADDRCONFIG;
		a_info = getaddrinfo(pbuf, svc, &hints, &alist);	
	}
#endif
	if (a_info)
		goto forward_fail;

	NTP_INSIST(alist != NULL);

	for (ai = alist; ai != NULL; ai = ai->ai_next) {
		/*
		 * Make a convenience sockaddr_u copy from ai->ai_addr
		 * because casting from sockaddr * to sockaddr_u * is
		 * risking alignment problems on platforms where
		 * sockaddr_u has stricter alignment than sockaddr,
		 * such as sparc.
		 */
		ZERO_SOCK(&addr);
		octets = min(sizeof(addr), ai->ai_addrlen);
		memcpy(&addr, ai->ai_addr, octets);
		if (SOCK_EQ(sock, &addr))
			break;
	}
	freeaddrinfo(alist);

	if (ai != NULL)
		return pbuf;	/* forward check passed */

    forward_fail:
	TRACE(1, ("%s forward check lookup fail: %s\n", pbuf,
		  gai_strerror(a_info)));
	LIB_GETBUF(pliar);
	snprintf(pliar, LIB_BUFLENGTH, "%s (%s)", stoa(sock), pbuf);

	return pliar;
}
Example #12
0
/* Receive data from broadcast. Couldn't finish that. Need to do some digging
 * here, especially for protocol independence and IPv6 multicast */
int 
recv_bcst_data (
	SOCKET rsock,
	char *rdata,
	int rdata_len,
	sockaddr_u *sas,
	sockaddr_u *ras
	)
{
	char *buf;
	int btrue = 1;
	int recv_bytes = 0;
	int rdy_socks;
	GETSOCKNAME_SOCKLEN_TYPE ss_len;
	struct timeval timeout_tv;
	fd_set bcst_fd;
#ifdef MCAST
	struct ip_mreq mdevadr;
	TYPEOF_IP_MULTICAST_LOOP mtrue = 1;
#endif
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
	struct ipv6_mreq mdevadr6;
#endif

	setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue));
	if (IS_IPV4(sas)) {
		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE))
				printf("sntp recv_bcst_data: Couldn't bind() address %s:%d.\n",
				       stoa(sas), SRCPORT(sas));
		}

#ifdef MCAST
		if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &mtrue, sizeof(mtrue)) < 0) {
			/* some error message regarding setting up multicast loop */
			return BROADCAST_FAILED;
		}
		mdevadr.imr_multiaddr.s_addr = NSRCADR(sas); 
		mdevadr.imr_interface.s_addr = htonl(INADDR_ANY);
		if (mdevadr.imr_multiaddr.s_addr == ~(unsigned)0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				printf("sntp recv_bcst_data: %s:%d is not a broad-/multicast address, aborting...\n",
				       stoa(sas), SRCPORT(sas));
			}
			return BROADCAST_FAILED;
		}
		if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas);
				printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf);
				free(buf);
			}
		}
#endif	/* MCAST */
	}
#ifdef ISC_PLATFORM_HAVEIPV6
	else if (IS_IPV6(sas)) {
		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE))
				printf("sntp recv_bcst_data: Couldn't bind() address.\n");
		}
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) {
			/* some error message regarding setting up multicast loop */
			return BROADCAST_FAILED;
		}
		memset(&mdevadr6, 0, sizeof(mdevadr6));
		mdevadr6.ipv6mr_multiaddr = SOCK_ADDR6(sas);
		if (!IN6_IS_ADDR_MULTICAST(&mdevadr6.ipv6mr_multiaddr)) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas); 
				printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
				free(buf);
			}
			return BROADCAST_FAILED;
		}
		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
			       &mdevadr6, sizeof(mdevadr6)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas); 
				printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf);
				free(buf);
			}
		}
#endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
	}
#endif	/* ISC_PLATFORM_HAVEIPV6 */
	FD_ZERO(&bcst_fd);
	FD_SET(rsock, &bcst_fd);
	if (ENABLED_OPT(TIMEOUT)) 
		timeout_tv.tv_sec = (int) atol(OPT_ARG(TIMEOUT));
	else 
		timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
	timeout_tv.tv_usec = 0;
	rdy_socks = select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv);
	switch (rdy_socks) {
	case -1: 
		if (ENABLED_OPT(NORMALVERBOSE)) 
			perror("sntp recv_bcst_data: select()");
		return BROADCAST_FAILED;
		break;
	case 0:
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n", 
			       (unsigned)timeout_tv.tv_sec);
		return BROADCAST_FAILED;
		break;
	default:
		ss_len = sizeof(*ras);
		recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len);
		break;
	}
	if (recv_bytes == -1) {
		if (ENABLED_OPT(NORMALVERBOSE))
			perror("sntp recv_bcst_data: recvfrom:");
		recv_bytes = BROADCAST_FAILED;
	}
#ifdef MCAST
	if (IS_IPV4(sas)) 
		setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue));
#endif
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
	if (IS_IPV6(sas))
		setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue));
#endif
	return recv_bytes;
}
Example #13
0
/*
** open sockets and make them non-blocking
*/
void
open_sockets(
	void
	)
{
	sockaddr_u	name;

	if (-1 == sock4) {
		sock4 = socket(PF_INET, SOCK_DGRAM, 0);
		if (-1 == sock4) {
			/* error getting a socket */
			msyslog(LOG_ERR, "open_sockets: socket(PF_INET) failed: %m");
			exit(1);
		}
		/* Make it non-blocking */
		make_socket_nonblocking(sock4);

		/* Let's try using a wildcard... */
		ZERO(name);
		AF(&name) = AF_INET;
		SET_ADDR4N(&name, INADDR_ANY);
		SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0));

		if (-1 == bind(sock4, &name.sa,
			       SOCKLEN(&name))) {
			msyslog(LOG_ERR, "open_sockets: bind(sock4) failed: %m");
			exit(1);
		}

		/* Register an NTP callback for recv/timeout */
		ev_sock4 = event_new(base, sock4,
				     EV_TIMEOUT | EV_READ | EV_PERSIST,
				     &sock_cb, NULL);
		if (NULL == ev_sock4) {
			msyslog(LOG_ERR,
				"open_sockets: event_new(base, sock4) failed!");
		} else {
			event_add(ev_sock4, &wakeup_tv);
		}
	}

	/* We may not always have IPv6... */
	if (-1 == sock6 && ipv6_works) {
		sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
		if (-1 == sock6 && ipv6_works) {
			/* error getting a socket */
			msyslog(LOG_ERR, "open_sockets: socket(PF_INET6) failed: %m");
			exit(1);
		}
		/* Make it non-blocking */
		make_socket_nonblocking(sock6);

		/* Let's try using a wildcard... */
		ZERO(name);
		AF(&name) = AF_INET6;
		SET_ADDR6N(&name, in6addr_any);
		SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0));

		if (-1 == bind(sock6, &name.sa,
			       SOCKLEN(&name))) {
			msyslog(LOG_ERR, "open_sockets: bind(sock6) failed: %m");
			exit(1);
		}
		/* Register an NTP callback for recv/timeout */
		ev_sock6 = event_new(base, sock6,
				     EV_TIMEOUT | EV_READ | EV_PERSIST,
				     &sock_cb, NULL);
		if (NULL == ev_sock6) {
			msyslog(LOG_ERR,
				"open_sockets: event_new(base, sock6) failed!");
		} else {
			event_add(ev_sock6, &wakeup_tv);
		}
	}
	
	return;
}
Example #14
0
/*
 * Send the requested file.
 */
int tftp_sendfile(int f, union sock_addr *peeraddr,
		   int fd, const char *name, const char *mode)
{
    struct tftphdr *ap;         /* data and ack packets */
    struct tftphdr *dp;
    int n;
    volatile int is_request;
    volatile u_short block;
    volatile int size, convert;
    volatile off_t amount;
    union sock_addr from;
    socklen_t fromlen;
    FILE *file;
    u_short ap_opcode, ap_block;

    startclock();               /* start stat's clock */
    dp = r_init();              /* reset fillbuf/read-ahead code */
    ap = (struct tftphdr *)ackbuf;
    convert = !strcmp(mode, "netascii");
    file = fdopen(fd, convert ? "rt" : "rb");
    block = 0;
    is_request = 1;             /* First packet is the actual WRQ */
    amount = 0;

    bsd_signal(SIGALRM, timer);
    do {
        if (is_request) {
            size = makerequest(WRQ, name, dp, mode) - 4;
        } else {
            /*      size = read(fd, dp->th_data, SEGSIZE);   */
            size = readit(file, &dp, convert);
            if (size < 0) {
                nak(f, peeraddr, errno + 100, NULL);
                break;
            }
            dp->th_opcode = htons((u_short) DATA);
            dp->th_block = htons((u_short) block);
        }
        timeout = 0;
        (void)sigsetjmp(timeoutbuf, 1);

        if (trace)
            tpacket("sent", dp, size + 4);
        n = sendto(f, dp, size + 4, 0,
                   &(peeraddr->sa), SOCKLEN(peeraddr));
        if (n != size + 4) {
            perror("tftp: sendto");
            goto abort;
        }
        read_ahead(file, convert);
        for (;;) {
            alarm(rexmtval);
            do {
                fromlen = sizeof(from);
                n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
                             &from.sa, &fromlen);
            } while (n <= 0);
            alarm(0);
            if (n < 0) {
                perror("tftp: recvfrom");
                goto abort;
            }
            sa_set_port(peeraddr, SOCKPORT(&from));  /* added */
            if (trace)
                tpacket("received", ap, n);
            /* should verify packet came from server */
            ap_opcode = ntohs((u_short) ap->th_opcode);
            ap_block = ntohs((u_short) ap->th_block);
            if (ap_opcode == ERROR) {
                printf("Error code %d: %s\n", ap_block, ap->th_msg);
                goto abort;
            }
            if (ap_opcode == ACK) {
                int j;

                if (ap_block == block) {
                    break;
                }
                /* On an error, try to synchronize
                 * both sides.
                 */
                j = synchnet(f);
                if (j && trace) {
                    printf("discarded %d packets\n", j);
                }
                /*
                 * RFC1129/RFC1350: We MUST NOT re-send the DATA
                 * packet in response to an invalid ACK.  Doing so
                 * would cause the Sorcerer's Apprentice bug.
                 */
            }
        }
        if (!is_request)
            amount += size;
        is_request = 0;
        block++;
    } while (size == SEGSIZE || block == 1);
  abort:
    fclose(file);
    stopclock();
    //if (amount > 0)
    //    printstats("Sent", amount);
    return amount;
}
Example #15
0
/*
 * Receive a file.
 */
int tftp_recvfile(int f, union sock_addr *peeraddr,
		   int fd, const char *name, const char *mode)
{
    struct tftphdr *ap;
    struct tftphdr *dp;
    int n;
    volatile u_short block;
    volatile int size, firsttrip;
    volatile unsigned long amount;
    union sock_addr from;
    socklen_t fromlen;
    FILE *file;
    volatile int convert;       /* true if converting crlf -> lf */
    u_short dp_opcode, dp_block;

    startclock();
    dp = w_init();
    ap = (struct tftphdr *)ackbuf;
    convert = !strcmp(mode, "netascii");
    file = fdopen(fd, convert ? "wt" : "wb");
    block = 1;
    firsttrip = 1;
    amount = 0;

    bsd_signal(SIGALRM, timer);
    do {
        if (firsttrip) {
            size = makerequest(RRQ, name, ap, mode);
            firsttrip = 0;
        } else {
            ap->th_opcode = htons((u_short) ACK);
            ap->th_block = htons((u_short) block);
            size = 4;
            block++;
        }
        timeout = 0;
        (void)sigsetjmp(timeoutbuf, 1);
      send_ack:
        if (trace)
            tpacket("sent", ap, size);
        if (sendto(f, ackbuf, size, 0, &(peeraddr->sa),
                   SOCKLEN(peeraddr)) != size) {
            alarm(0);
            perror("tftp: sendto");
            goto abort;
        }
        write_behind(file, convert);
        for (;;) {
            alarm(rexmtval);
            do {
                fromlen = sizeof(from);
                n = recvfrom(f, dp, PKTSIZE, 0,
                             &from.sa, &fromlen);
            } while (n <= 0);
            alarm(0);
            if (n < 0) {
                perror("tftp: recvfrom");
                goto abort;
            }
            sa_set_port(peeraddr, SOCKPORT(&from));  /* added */
            if (trace)
                tpacket("received", dp, n);
            /* should verify client address */
            dp_opcode = ntohs((u_short) dp->th_opcode);
            dp_block = ntohs((u_short) dp->th_block);
            if (dp_opcode == ERROR) {
                printf("Error code %d: %s\n", dp_block, dp->th_msg);
                goto abort;
            }
            if (dp_opcode == DATA) {
                int j;

                if (dp_block == block) {
                    break;      /* have next packet */
                }
                /* On an error, try to synchronize
                 * both sides.
                 */
                j = synchnet(f);
                if (j && trace) {
                    printf("discarded %d packets\n", j);
                }
                if (dp_block == (block - 1)) {
                    goto send_ack;      /* resend ack */
                }
            }
        }
        /*      size = write(fd, dp->th_data, n - 4); */
        size = writeit(file, &dp, n - 4, convert);
        if (size < 0) {
            nak(f, peeraddr, errno + 100, NULL);
            break;
        }
        amount += size;
    } while (size == SEGSIZE);
  abort:                       /* ok to ack, since user */
    ap->th_opcode = htons((u_short) ACK);       /* has seen err msg */
    ap->th_block = htons((u_short) block);
    (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)peeraddr,
                 SOCKLEN(peeraddr));
    write_behind(file, convert);        /* flush last buffer */
    fclose(file);
    stopclock();
    //if (amount > 0)
    //    printstats("Received", amount);
    return amount;
}
Example #16
0
/*
 * findhostaddr - resolve a host name into an address (Or vice-versa)
 *
 * Given one of {ce_peeraddr,ce_name}, find the other one.
 * It returns 1 for "success" and 0 for an uncorrectable failure.
 * Note that "success" includes try again errors.  You can tell that you
 *  got a "try again" since {ce_peeraddr,ce_name} will still be zero.
 */
static int
findhostaddr(
	struct conf_entry *entry
	)
{
	static int eai_again_seen = 0;
	struct addrinfo *addr;
	struct addrinfo hints;
	int again;
	int error;

	checkparent();		/* make sure our guy is still running */

	if (entry->ce_name != NULL && !SOCK_UNSPEC(&entry->peer_store)) {
		/* HMS: Squawk? */
		msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined...");
		return 1;
	}

	if (entry->ce_name == NULL && SOCK_UNSPEC(&entry->peer_store)) {
		msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
		return 0;
	}

	if (entry->ce_name) {
		DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
			entry->ce_name));

		memset(&hints, 0, sizeof(hints));
		hints.ai_family = entry->type;
		hints.ai_socktype = SOCK_DGRAM;
		hints.ai_protocol = IPPROTO_UDP;
		/*
		 * If IPv6 is not available look only for v4 addresses
		 */
		if (!ipv6_works)
			hints.ai_family = AF_INET;
		error = getaddrinfo(entry->ce_name, NULL, &hints, &addr);
		if (error == 0) {
			entry->peer_store = *((sockaddr_u *)(addr->ai_addr));
			if (IS_IPV4(&entry->peer_store)) {
				entry->ce_peeraddr =
				    NSRCADR(&entry->peer_store);
				entry->ce_config.v6_flag = 0;
			} else {
				entry->ce_peeraddr6 =
				    SOCK_ADDR6(&entry->peer_store);
				entry->ce_config.v6_flag = 1;
			}
			freeaddrinfo(addr);
		}
	} else {
		DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
			stoa(&entry->peer_store)));

		entry->ce_name = emalloc(MAXHOSTNAMELEN);
		error = getnameinfo((const struct sockaddr *)&entry->peer_store,
				   SOCKLEN(&entry->peer_store),
				   (char *)&entry->ce_name, MAXHOSTNAMELEN,
				   NULL, 0, 0);
	}

	if (0 == error) {

		/* again is our return value, for success it is 1 */
		again = 1;

		DPRINTF(2, ("findhostaddr: %s resolved.\n", 
			(entry->ce_name) ? "name" : "address"));
	} else {
		/*
		 * If the resolver failed, see if the failure is
		 * temporary. If so, return success.
		 */
		again = 0;

		switch (error) {

		case EAI_FAIL:
			again = 1;
			break;

		case EAI_AGAIN:
			again = 1;
			eai_again_seen = 1;
			break;

		case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
		case EAI_NODATA:
#endif
			msyslog(LOG_ERR, "host name not found%s%s: %s",
				(EAI_NONAME == error) ? "" : " EAI_NODATA",
				(eai_again_seen) ? " (permanent)" : "",
				entry->ce_name);
			again = !eai_again_seen;
			break;

#ifdef EAI_SYSTEM
		case EAI_SYSTEM:
			/* 
			 * EAI_SYSTEM means the real error is in errno.  We should be more
			 * discriminating about which errno values require retrying, but
			 * this matches existing behavior.
			 */
			again = 1;
			DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
				errno, strerror(errno)));
			break;
#endif
		}

		/* do this here to avoid perturbing errno earlier */
		DPRINTF(2, ("intres: got error status of: %d\n", error));
	}

	return again;
}