mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-20 02:38:32 +00:00
Tweaks to TFTP.
Fail on overlarge files (block numbers are limited to 16 bits) Honour tftp-max setting in single port mode. Tweak timeouts, and fix logic which suppresses errors if the last ACK is missing.
This commit is contained in:
@@ -956,10 +956,11 @@ int main (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
struct tftp_prefix *p;
|
struct tftp_prefix *p;
|
||||||
|
|
||||||
my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
|
my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s %s",
|
||||||
daemon->tftp_prefix ? _("root is ") : _("enabled"),
|
daemon->tftp_prefix ? _("root is ") : _("enabled"),
|
||||||
daemon->tftp_prefix ? daemon->tftp_prefix: "",
|
daemon->tftp_prefix ? daemon->tftp_prefix : "",
|
||||||
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
|
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "",
|
||||||
|
option_bool(OPT_SINGLE_PORT) ? _("single port mode") : "");
|
||||||
|
|
||||||
if (tftp_prefix_missing)
|
if (tftp_prefix_missing)
|
||||||
my_syslog(MS_TFTP | LOG_WARNING, _("warning: %s inaccessible"), daemon->tftp_prefix);
|
my_syslog(MS_TFTP | LOG_WARNING, _("warning: %s inaccessible"), daemon->tftp_prefix);
|
||||||
@@ -977,7 +978,7 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (max_fd < 0)
|
if (max_fd < 0)
|
||||||
max_fd = 5;
|
max_fd = 5;
|
||||||
else if (max_fd < 100)
|
else if (max_fd < 100 && !option_bool(OPT_SINGLE_PORT))
|
||||||
max_fd = max_fd/2;
|
max_fd = max_fd/2;
|
||||||
else
|
else
|
||||||
max_fd = max_fd - 20;
|
max_fd = max_fd - 20;
|
||||||
@@ -1707,6 +1708,7 @@ static int set_dns_listeners(time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
|
/* tftp == 0 in single-port mode. */
|
||||||
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
|
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
|
||||||
poll_listen(listener->tftpfd, POLLIN);
|
poll_listen(listener->tftpfd, POLLIN);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
60
src/tftp.c
60
src/tftp.c
@@ -242,23 +242,37 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
/* data transfer via server listening socket */
|
/* data transfer via server listening socket */
|
||||||
if (option_bool(OPT_SINGLE_PORT))
|
if (option_bool(OPT_SINGLE_PORT))
|
||||||
for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; up = &transfer->next, transfer = transfer->next)
|
{
|
||||||
if (sockaddr_isequal(&peer, &transfer->peer))
|
int tftp_cnt;
|
||||||
|
|
||||||
|
for (tftp_cnt = 0, transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; up = &transfer->next, transfer = transfer->next)
|
||||||
{
|
{
|
||||||
if (ntohs(*((unsigned short *)packet)) == OP_RRQ)
|
tftp_cnt++;
|
||||||
|
|
||||||
|
if (sockaddr_isequal(&peer, &transfer->peer))
|
||||||
{
|
{
|
||||||
/* Handle repeated RRQ or abandoned transfer from same host and port
|
if (ntohs(*((unsigned short *)packet)) == OP_RRQ)
|
||||||
by unlinking and reusing the struct transfer. */
|
{
|
||||||
*up = transfer->next;
|
/* Handle repeated RRQ or abandoned transfer from same host and port
|
||||||
break;
|
by unlinking and reusing the struct transfer. */
|
||||||
}
|
*up = transfer->next;
|
||||||
else
|
break;
|
||||||
{
|
}
|
||||||
handle_tftp(now, transfer, len);
|
else
|
||||||
return;
|
{
|
||||||
|
handle_tftp(now, transfer, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enforce simultaneous transfer limit. In non-single-port mode
|
||||||
|
this is doene by not listening on the server socket when
|
||||||
|
too many transfers are in progress. */
|
||||||
|
if (!transfer && tftp_cnt >= daemon->tftp_max)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (name)
|
if (name)
|
||||||
{
|
{
|
||||||
/* check for per-interface prefix */
|
/* check for per-interface prefix */
|
||||||
@@ -583,21 +597,28 @@ void check_tftp_listeners(time_t now)
|
|||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
/* timeout, retransmit */
|
/* timeout, retransmit */
|
||||||
transfer->timeout += 1 + (1<<transfer->backoff);
|
transfer->timeout += 1 + (1<<(transfer->backoff/2));
|
||||||
|
|
||||||
/* we overwrote the buffer... */
|
/* we overwrote the buffer... */
|
||||||
daemon->srv_save = NULL;
|
daemon->srv_save = NULL;
|
||||||
|
|
||||||
if ((len = get_block(daemon->packet, transfer)) == -1)
|
/* check for wrap of 16 bit block no. */
|
||||||
|
if (transfer->block == 0x10000)
|
||||||
|
{
|
||||||
|
len = tftp_err(ERR_ILL, daemon->packet, _("too many blocks"), NULL);
|
||||||
|
endcon = 1;
|
||||||
|
}
|
||||||
|
else if ((len = get_block(daemon->packet, transfer)) == -1)
|
||||||
{
|
{
|
||||||
len = tftp_err_oops(daemon->packet, transfer->file->filename);
|
len = tftp_err_oops(daemon->packet, transfer->file->filename);
|
||||||
endcon = 1;
|
endcon = 1;
|
||||||
}
|
}
|
||||||
/* don't complain about timeout when we're awaiting the last
|
else if (++transfer->backoff > 7)
|
||||||
ACK, some clients never send it */
|
|
||||||
else if (++transfer->backoff > 7 && len != 0)
|
|
||||||
{
|
{
|
||||||
endcon = 1;
|
/* don't complain about timeout when we're awaiting the last
|
||||||
|
ACK, some clients never send it */
|
||||||
|
if (len == transfer->blocksize + 4)
|
||||||
|
endcon = 1;
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,7 +741,8 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
|
|||||||
char *errstr = strerror(errno);
|
char *errstr = strerror(errno);
|
||||||
|
|
||||||
memset(packet, 0, daemon->packet_buff_sz);
|
memset(packet, 0, daemon->packet_buff_sz);
|
||||||
sanitise(file);
|
if (file)
|
||||||
|
sanitise(file);
|
||||||
|
|
||||||
mess->op = htons(OP_ERR);
|
mess->op = htons(OP_ERR);
|
||||||
mess->err = htons(err);
|
mess->err = htons(err);
|
||||||
|
|||||||
Reference in New Issue
Block a user