The TFTP protocol has the following flow:
Client sends a RRQ or WRQ request from a randomly selected CTID port to port 69 on the server:
Client:CTID ------> Server:69
Server replies from a randomly selected STID port to the client's CTID:
Client:CTID <------ Server:STID
all subsequent packets for that transfer are sent between the client's CTID and the server's STID as needed.
Client:CTID <-----> Server:STID
I have noticed that the client is unable to receive the packet from server:STID when the windows defender firewall is enabled. When disabled the packet is received.
It is my understanding that when the client binds CTID it should receive all packets with that destination port. Why are the UDP packets from server:STID filtered out by the firewall?
Applications like tftp64 are able to function even with the firewall enabled. What does it do differently?
Here a minimal example in C that demonstrates the issue:
#include <stdint.h>
#include <stdio.h>
#include <winsock2.h>
#define DBG(fmt, ...) fprintf(stderr, "% 8d : " fmt "\n", __LINE__ __VA_OPT__(, ) __VA_ARGS__)
int main(void) {
uint32_t ip = 0xC0A8010A; // 192.168.1.10
uint16_t port = 69;
int err;
WSADATA WsaDat;
if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0) {
err = WSAGetLastError();
DBG("WSAStartup() failed (Err: %d)\n", err);
return -1;
}
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
DBG("sock: %d", sock);
if (sock < 0) {
return -1;
}
struct sockaddr_in destAddr;
memset(&destAddr, 0, sizeof(destAddr));
destAddr.sin_family = AF_INET;
destAddr.sin_addr.s_addr = htonl(ip);
destAddr.sin_port = htons(port);
char buffer[1024] = "\x00\x02\x2f\x62\x61\x63\x6b\x65\x6e\x64\x2e\x68\x00\x6f\x63\x74\x65\x74\x00\x74\x73\x69\x7a\x65\x00\x30\x00";
DBG("Send TO %u.%u.%u.%u:%u", (ip & 0xff000000) >> 24, (ip & 0xff0000) >> 16, (ip & 0xff00) >> 8, ip & 0xff, port);
err = sendto(sock, buffer, 27, 0, (struct sockaddr *) &destAddr, sizeof(destAddr));
DBG("sendto: %d", err);
if (err != 27) {
return -1;
}
// socket should now be implicitly bound to some random port and should be able to receive
struct sockaddr_in srcAddr;
memset(&srcAddr, 0, sizeof(srcAddr));
int32_t srcAddrLen = sizeof(srcAddr);
err = recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&srcAddr, &srcAddrLen);
DBG("recvfrom: %d", err);
if (err > 0) {
ip = ntohl(srcAddr.sin_addr.s_addr);
port = ntohs(srcAddr.sin_port);
DBG("Recv From %u.%u.%u.%u:%u", (ip & 0xff000000) >> 24, (ip & 0xff0000) >> 16, (ip & 0xff00) >> 8, ip & 0xff, port);
}
return 0;
}
FIREWALL ON
20 : sock: 264
33 : Send TO 192.168.1.10:69
35 : sendto: 27
^C
FIREWALL OFF
20 : sock: 244
33 : Send TO 192.168.1.10:69
35 : sendto: 27
46 : recvfrom: 4
50 : Recv From 192.168.1.10:50000