/* 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"); } }
/* 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; }
/* * 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; }
/* 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; }
/* * 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"); }
/* * 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; }
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; }
/* * 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; }
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; }
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); }
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; }
/* 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; }
/* ** 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; }
/* * 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; }
/* * 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; }
/* * 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; }