--- embedaddon/dnsmasq/src/tftp.c 2013/07/29 19:37:40 1.1.1.1 +++ embedaddon/dnsmasq/src/tftp.c 2016/11/02 09:57:01 1.1.1.3 @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -49,9 +49,7 @@ void tftp_request(struct listener *listen, time_t now) struct iovec iov; struct ifreq ifr; int is_err = 1, if_index = 0, mtu = 0; -#ifdef HAVE_DHCP struct iname *tmp; -#endif struct tftp_transfer *transfer; int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */ #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) @@ -62,7 +60,12 @@ void tftp_request(struct listener *listen, time_t now) char *prefix = daemon->tftp_prefix; struct tftp_prefix *pref; struct all_addr addra; - +#ifdef HAVE_IPV6 + /* Can always get recvd interface for IPv6 */ + int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6; +#else + int check_dest = !option_bool(OPT_NOWILD); +#endif union { struct cmsghdr align; /* this ensures alignment */ #ifdef HAVE_IPV6 @@ -93,14 +96,17 @@ void tftp_request(struct listener *listen, time_t now) if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2) return; - - if (option_bool(OPT_NOWILD)) + + /* Can always get recvd interface for IPv6 */ + if (!check_dest) { if (listen->iface) { addr = listen->iface->addr; - mtu = listen->iface->mtu; name = listen->iface->name; + mtu = listen->iface->mtu; + if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu) + mtu = daemon->tftp_mtu; } else { @@ -198,26 +204,49 @@ void tftp_request(struct listener *listen, time_t now) addra.addr.addr6 = addr.in6.sin6_addr; #endif - if (!iface_check(listen->family, &addra, name, NULL)) + if (daemon->tftp_interfaces) { - if (!option_bool(OPT_CLEVERBIND)) - enumerate_interfaces(); - if (!loopback_exception(listen->tftpfd, listen->family, &addra, name)) + /* dedicated tftp interface list */ + for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next) + if (tmp->name && wildcard_match(tmp->name, name)) + break; + + if (!tmp) return; } - + else + { + /* Do the same as DHCP */ + if (!iface_check(listen->family, &addra, name, NULL)) + { + if (!option_bool(OPT_CLEVERBIND)) + enumerate_interfaces(0); + if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) && + !label_exception(if_index, listen->family, &addra) ) + return; + } + #ifdef HAVE_DHCP - /* allowed interfaces are the same as for DHCP */ - for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) - if (tmp->name && wildcard_match(tmp->name, name)) - return; + /* allowed interfaces are the same as for DHCP */ + for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) + if (tmp->name && wildcard_match(tmp->name, name)) + return; #endif - + } + strncpy(ifr.ifr_name, name, IF_NAMESIZE); if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1) - mtu = ifr.ifr_mtu; + { + mtu = ifr.ifr_mtu; + if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu) + mtu = daemon->tftp_mtu; + } } - + + /* Failed to get interface mtu - can use configured value. */ + if (mtu == 0) + mtu = daemon->tftp_mtu; + if (name) { /* check for per-interface prefix */ @@ -317,14 +346,15 @@ void tftp_request(struct listener *listen, time_t now) { if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK)) { + /* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */ + int overhead = (listen->family == AF_INET) ? 32 : 52; transfer->blocksize = atoi(opt); if (transfer->blocksize < 1) transfer->blocksize = 1; if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4) transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4; - /* 32 bytes for IP, UDP and TFTP headers */ - if (mtu != 0 && transfer->blocksize > (unsigned)mtu - 32) - transfer->blocksize = (unsigned)mtu - 32; + if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead) + transfer->blocksize = (unsigned)mtu - overhead; transfer->opt_blocksize = 1; transfer->block = 0; } @@ -483,7 +513,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t * return NULL; } -void check_tftp_listeners(fd_set *rset, time_t now) +void check_tftp_listeners(time_t now) { struct tftp_transfer *transfer, *tmp, **up; ssize_t len; @@ -499,7 +529,7 @@ void check_tftp_listeners(fd_set *rset, time_t now) prettyprint_addr(&transfer->peer, daemon->addrbuff); - if (FD_ISSET(transfer->sockfd, rset)) + if (poll_check(transfer->sockfd, POLLIN)) { /* we overwrote the buffer... */ daemon->srv_save = NULL; @@ -554,7 +584,7 @@ void check_tftp_listeners(fd_set *rset, time_t now) } /* don't complain about timeout when we're awaiting the last ACK, some clients never send it */ - else if (++transfer->backoff > 5 && len != 0) + else if (++transfer->backoff > 7 && len != 0) { endcon = 1; len = 0;