Commit Graph

97 Commits

Author SHA1 Message Date
Simon Kelley
ee09f0655c Optimise tftp.
This change attempts to optimse TFTP perfomance.

It reads the next block immediately after sending a block,
in order to reduce latency between receiving an ACK and sending
the next block. Is also suppresses lseek() calls when reading
successive blocks.

This improves performance when doing transfers without windowing
and when only a single transfer is in progress at one time.
2025-09-01 22:35:02 +01:00
Simon Kelley
9a566c0913 Tweak recently altered TFTP code. 2025-08-21 16:19:58 +01:00
Simon Kelley
d81b1d76a0 Fix TFTP problems with large files.
TFTP fails with a timeout when the transfer exceeds 128K blocks.
The block field in an ACK packet is 16 bits, so large transfers
need to deal with this field wrapping. Testing failure meant
that it worked for the first wrap, but not for subsequent ones.

Having fixed the block number problem, file size calculations
accidentally being done in 32 bits not 64 bits then broke
transfers larger than 2G or maybe 4G.

The first problem was probably introduced in commit
ebef27f321 and has not appeared
in a stable release. The second appears to have been there forever.
Clearly, nobody is mad enough to transfer multi-gigabyte files
over TFTP.

Thanks to Jean-François JUBLIN for spotting this and supplying
useful packet dumps that made it easy to diagnose.
2025-08-21 12:49:09 +01:00
Simon Kelley
e7b87dee85 Tftp code tweaks. 2025-05-24 21:15:02 +01:00
Simon Kelley
ebef27f321 Add TFTP options windowsize (RFC 7440) and timeout (RFC 2349). 2025-05-24 14:41:40 +01:00
Simon Kelley
baf3c57af5 Fix compiler warnings. 2025-05-18 18:22:48 +01:00
Simon Kelley
d1008215dc Better error message when rejecting a TFTP transfer. 2025-05-14 21:15:17 +01:00
Paul Donald
b0b4d90b6a Multiple typo and spelling fixes. 2025-03-29 21:41:40 +00:00
Simon Kelley
9df1bd0cc1 Revert 368ceff6e0 and fix correct problem.
The next() function is broken for any TFTP packet with padding
which doesn't end with a zero.

Rewrite to handle such packets.

Thanks to Helge Deller <deller@gmx.de> for persisting in finding the
actual problem and proposing a solution. This patch is modelled on his,
but rewritten for personal preference by Simon Kelley, who is
responsible for all bugs.
2025-03-01 22:43:23 +00:00
Helge Deller
368ceff6e0 TFTP off-by-2 bugfix
Some of my PA-RISC UNIX machines boot remotely via tftp, but dnsmasq
randomly fails to deliver (the identical file) to some of the machines.

I traced the issue and basically dnsmasq fails with error "unsupported
request from IP.x.y.z" (line 366 in tftp.c).

Here is an example package which is sent (516 hex bytes):
76 6d 6c 69 6e 75 78 00 6f 63 74 65 74 00 12 74 10 3c 00 00 00 00 00 01
a9 24 00 00 00 00 00 00 1e 38 00 00 00 00 00 00 1c a0 00 00 00 00 00 00
1d 08 00 00 00 00 00 00 1d 28 00 00 00 00 00 00 08 00 00 00 00 00 00 00
03 d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1d 30 00 00 00 02 ff e0
00 00 00 00 03 60 a8 49 55 93 00 00 00 01 f0 d4 21 e4 00 00 00 00 00 00
1d 78 00 00 00 f0 f0 d8 51 38 00 00 00 f0 f0 d4 21 c0 00 00 00 00 00 00
00 00 00 00 00 00 00 01 aa b8 00 00 00 f0 f0 e9 62 7c 00 00 00 00 00 00
03 01 ff ff ff ff ff ff 03 00 ff ff ff ff ff ff ff ff 00 00 00 00 00 00
00 03 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 04 ff ff ff ff ff ff
ff ff 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 00 00
00 05 00 00 00 00 00 00 1e 38 00 00 00 00 00 00 00 60 00 00 00 00 00 01
a6 68 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 ff 00 00 00 00 00 00
00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00
00 00 00 00 00 f0 f0 d8 4f 30 00 00 00 00 00 00 00 01 00 00 00 00 00 00
00 00 00 00 00 00 00 01 ae ec 00 00 00 00 00 00 1f 70 00 00 00 00 00 00
1e b8 00 00 03 60 a8 49 55 93 00 00 00 02 18 71 1a 00 00 00 00 00 00 00
00 03 00 00 00 00 00 00 00 03 00 00 00 00 00 00 1e 38 00 00 00 00 00 00
00 07 00 00 00 00 00 00 00 00 00 00 00 f0 f0 d2 f0 70 00 00 00 00 00 00
1f c0 00 00 00 f0 f0 d4 0b e8 00 00 00 00 00 00 00 01 00 00 00 00 00 00
00 60 ff ff ff fc 00 60 18 00 00 00 00 00 00 00 00 00 00 00 00 f0 f0 d8
8f d0 00 00 00 00 00 00 1f f8 00 00 00 00 00 00 00 00 00 00 00 f0 f0 d8
8d b8 00 00 00 00 00 00 1e e8 00 00

Please note the last 3 bytes: "e8 00 00".
If the 3rd last byte is "00", then dnsmasq works and it fails it it's "e8".

So, the bug is in line 366 of tftp.c:
   filename = next(&p, end)
Here filename gets the value NULL from next(), because the "end" variable is off-by-2.
The fix is to change line 363 to add an offset of 2:
  end = packet + 2 + len;

Signed-off-by: Helge Deller <deller@gmx.de>
Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2293793
2025-02-06 17:04:06 +00:00
Simon Kelley
6e6a45a7d9 Bump copyrights to 2025. 2025-01-23 17:08:39 +00:00
Simon Kelley
32a8f3e009 Finesse TCP timeouts for upstream connections.
Timeouts for TCP connections to non-responive servers are very long.
This in not appropriate for DNS connections.

Set timeouts for connection setup, sending data and recieving data.
The timeouts for connection setup and sending data are set at 5 seconds.
For recieving the reply this is doubled, to take into account the
time for usptream to actually get the answer.

Thanks to Petr Menšík for pointing out this problem, and finding a better
and more portable solution than the one in place heretofore.
2024-11-25 23:18:07 +00:00
Simon Kelley
b5820d1fd8 Bump copyright to 2024. 2024-01-13 22:20:04 +00:00
Simon Kelley
77ef9b2603 Fix crash when DNS disabled, introduced in 416390f996 2023-11-10 23:13:46 +00:00
Simon Kelley
bd188e306a Fix paren blunder in aaba66efbd
Thanks to Dominik Derigs for spotting this.
2023-04-17 16:23:06 +01:00
Simon Kelley
aaba66efbd Add --no-dhcpv4-interface and --no-dhcpv6-interface options. 2023-04-12 22:55:14 +01:00
Simon Kelley
df242de5c6 Bump copyrights to 2023. 2023-04-05 12:34:34 +01:00
Taylor R Campbell
137ae2e9cf Avoid undefined behaviour with the ctype(3) functions.
As defined in the C standard:

	In all cases the argument is an int, the value of which shall
	be representable as an unsigned char or shall equal the value
	of the macro EOF.  If the argument has any other value, the
	behavior is undefined.

This is because they're designed to work with the int values returned
by getc or fgetc; they need extra work to handle a char value.

If EOF is -1 (as it almost always is), with 8-bit bytes, the allowed
inputs to the ctype(3) functions are:

	{-1, 0, 1, 2, 3, ..., 255}.

However, on platforms where char is signed, such as x86 with the
usual ABI, code like

	char *arg = ...;
	... isspace(*arg) ...

may pass in values in the range:

	{-128, -127, -126, ..., -2, -1, 0, 1, ..., 127}.

This has two problems:

1. Inputs in the set {-128, -127, -126, ..., -2} are forbidden.

2. The non-EOF byte 0xff is conflated with the value EOF = -1, so
   even though the input is not forbidden, it may give the wrong
   answer.

Casting char to int first before passing the result to ctype(3)
doesn't help: inputs like -128 are unchanged by this cast.  It is
necessary to cast char inputs to unsigned char first; you can then
cast to int if you like but there's no need because the functions
will always convert the argument to int by definition.  So the above
fragment needs to be:

	char *arg = ...;
	... isspace((unsigned char)*arg) ...

This patch inserts unsigned char casts where necessary, and changes
int casts to unsigned char casts where the input is char.

I left alone int casts where the input is unsigned char already --
they're not immediately harmful, although they would have the effect
of suppressing some compiler warnings if the input is ever changed to
be char instead of unsigned char, so it might be better to remove
those casts too.

I also left alone calls where the input is int to begin with because
it came from getc; casting to unsigned char here would be wrong, of
course.
2023-02-27 14:56:25 +00:00
Simon Kelley
ce372917fe Tweak packet dump code to make port numbers more accurate.
Also add query-ids with log-queries=extra.
2022-09-05 18:04:35 +01:00
Simon Kelley
fc664d114d Extend packet-dump system to DHCP and TFTP. 2022-01-29 15:55:04 +00:00
Simon Kelley
c6d4c33d61 Bump copyright to 2022. 2022-01-24 15:19:00 +00:00
Simon Kelley
41adecad14 Include client address if TFTP file-not-found errors. 2022-01-01 22:15:16 +00:00
Petr Menšík
50d75ae514 Retry on interrupted error in tftp
Interrupt might arrive when sending error reply. Retry if possible.

Wrong Check of Return Value

10. dnsmasq-2.85/src/tftp.c:603: check_return: Calling "sendto(transfer->sockfd, dnsmasq_daemon->packet, len, 0, __CONST_SOCKADDR_ARG({.__sockaddr__ = &peer.sa}), sa_len(&peer))" without checking return value. This library function may fail and return an error code.
 #   601|   		  prettyprint_addr(&peer, daemon->addrbuff);
 #   602|   		  len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
 #   603|-> 		  sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer));
 #   604|   		}
 #   605|   	    }
2021-09-11 14:39:36 +01:00
Kevin Darbyshire-Bryant
767d9cbd96 Add --quiet-tftp. 2021-07-09 22:48:49 +01:00
Simon Kelley
dfb1f7ccf1 TFTP tweak.
Check sender of all received packets, as specified in RFC 1350 para 4.

My understanding of the example in the RFC is that it in fact only
applies to server-to-client packets, and packet loss or duplication
cannot result in a client sending from more than one port to a server.
This check is not, therefore, strictly needed on the server side.
It's still useful, and adds a little security against packet
spoofing. (though if you're running TFTP on a public network with
bad actors, nothing can really save you.)
2021-03-30 21:32:07 +01:00
Simon Kelley
023ace8e54 Merge branch 'random-port' 2021-03-17 20:42:21 +00:00
Simon Kelley
74d4fcd756 Use random source ports where possible if source addresses/interfaces in use.
CVE-2021-3448 applies.

It's possible to specify the source address or interface to be
used when contacting upstream nameservers: server=8.8.8.8@1.2.3.4
or server=8.8.8.8@1.2.3.4#66 or server=8.8.8.8@eth0, and all of
these have, until now, used a single socket, bound to a fixed
port. This was originally done to allow an error (non-existent
interface, or non-local address) to be detected at start-up. This
means that any upstream servers specified in such a way don't use
random source ports, and are more susceptible to cache-poisoning
attacks.

We now use random ports where possible, even when the
source is specified, so server=8.8.8.8@1.2.3.4 or
server=8.8.8.8@eth0 will use random source
ports. server=8.8.8.8@1.2.3.4#66 or any use of --query-port will
use the explicitly configured port, and should only be done with
understanding of the security implications.
Note that this change changes non-existing interface, or non-local
source address errors from fatal to run-time. The error will be
logged and communiction with the server not possible.
2021-03-17 20:39:33 +00:00
Petr Menšík
484bd75ce4 tftp warning fix.
At least on Fedora 32 with GCC 10.2.1, dnsmasq compilation emits warning:

tftp.c: In function ‘tftp_request’:
tftp.c:754:3: warning: ‘strcpy’ source argument is the same as
destination [-Wrestrict]
  754 |   strcpy(daemon->namebuff, file);

And indeed it is the same source always on line 477, sometimes also on
571 in tftp.c

Attached patch fixes the warning and possible undefined behaviour on
tftp error.
2021-03-17 14:40:04 +00:00
Simon Kelley
c8e8f5c204 Bump copyright notices for 2021. Happy New Year! 2021-01-24 21:59:37 +00:00
Petr Menšík
1c1b925052 Remove duplicate address family from listener
Since address already contain family, remove separate family from
listener. Use now family from address itself.
2020-04-29 00:06:57 +01:00
Petr Mensik
51cdd1a227 Explicitly mark address port not used
On many places return value is ignored. Usually it means port is always
the same and not needed to be displayed. Unify warnings.
2020-04-29 00:04:04 +01:00
Simon Kelley
980b14f174 Compiler warning. 2020-03-05 18:01:48 +00:00
Simon Kelley
c7a44c4690 Revert tftp block number overflow check. Wrapping block nos is fine. 2020-01-07 20:30:16 +00:00
Simon Kelley
2ac4cf0146 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.
2020-01-06 23:39:33 +00:00
Simon Kelley
2a8710ac2f Update copyrights to 2020. 2020-01-05 16:40:06 +00:00
Simon Kelley
66f62650c3 Add --tftp-single-port option. 2020-01-05 16:21:24 +00:00
Simon Kelley
936bd82755 Fix too small control array in tftp code on BSD and SOLARIS
This causes tftp to fail on some BSD versions, for sure. It
works by chance on others.

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=241068
2019-10-12 23:29:59 +01:00
Simon Kelley
cc921df9ce Remove nested struct/union in cache records and all_addr. 2019-01-02 22:48:59 +00:00
Simon Kelley
ee8750451b Remove ability to compile without IPv6 support.
This was the source of a large number of #ifdefs, originally
included for use with old embedded libc versions. I'm
sure no-one wants or needs IPv6-free code these days, so this
is a move towards more maintainable code.
2018-10-23 22:10:17 +01:00
Petr Menšík
47b45b2967 Fix lengths of interface names
Use helper function similar to copy correctly limited names into
buffers.
2018-09-04 22:47:58 +01:00
Simon Kelley
d1ced3ae38 Update copyrights to 2018. 2018-01-01 22:18:03 +00:00
Rosen Penev
cbd29e5da8 Printf related fixes. 2017-06-27 22:29:51 +01:00
Rosen Penev
50a2841d34 Fix function declarations. 2017-06-27 22:27:02 +01:00
Simon Kelley
50ca85504c Bump year in copyrights. 2017-06-24 22:43:18 +01:00
Floris Bos
503c609149 --dhcp-reply-delay option to workaround PXE client bugs.
Adds option to delay replying to DHCP packets by one or more seconds.
This provides a workaround for a PXE boot firmware implementation
that has a bug causing it to fail if it receives a (proxy) DHCP
reply instantly.

On Linux it looks up the exact receive time of the UDP packet with
the SIOCGSTAMP ioctl to prevent multiple delays if multiple packets
come in around the same time.
2017-04-09 23:07:13 +01:00
Floris Bos
60704f5e2e Add support for unique TFTP root per MAC.
It is currently only possible to let the TFTP server serve a different
folder depending on the client's IP address.
However it isn't always possible to predict what the client's
IP address will be, especially in situations in which we are not
responsible for handing them out (e.g. proxy dhcp setups).

Extend the current --tftp-unique-root parameter to support having a
separate folder per MAC address instead.
2017-04-09 22:22:49 +01:00
Josh Soref
730c6745f0 Comprehensive spelling/typo fixes.
Thanks to Josh Soref for generating these fixes.
2017-02-06 16:14:04 +00:00
Simon Kelley
fa78573778 Zero packet buffers before building output, to reduce risk of information leakage. 2016-07-22 20:56:01 +01:00
Simon Kelley
294d36df47 Calculate length of TFTP error reply correctly. 2016-07-06 21:30:25 +01:00
Simon Kelley
d1377fa3c4 Account for TFTP packet headers in IPv6 correctly. 2016-03-04 21:32:21 +00:00