Tplink Archer c2 : tftp via python under linux

hello

Im trying with this one :slight_smile:

as the process descriibed here :

but...

when I try to patch the tftpd.py with the patch (1.patch in my case) :

patch tftpd.py 1.patch
patching file tftpd.py
Hunk #1 FAILED at 190.
Hunk #2 FAILED at 198.
2 out of 2 hunks FAILED -- saving rejects to file tftpd.py.rej

but :

cat 1.patch
--- a/tftp_common.py
+++ b/tftp_common.py
@@ -190,7 +190,7 @@ class RQPacket(TFTPPacket):
@staticmethod
def parse_rq(packet: bytes, constructor):
block_size = 512

  •    window_size = 1
    
  •    window_size = 2  # temporarily changed
      bad_opts = False
     packet = packet[2:].split(b'\0')
    for i in range(2, len(packet), 2):
    

@@ -198,6 +198,8 @@ class RQPacket(TFTPPacket):
block_size = int(packet[i + 1])
elif packet[i].lower() == b'windowsize':
window_size = int(packet[i + 1])

  •        elif packet[i].lower() == b'timeout':
    
  •            pass  # not implemented, temporarily ignoring
         elif packet[i] != b'':
            bad_opts = True
    
    return constructor(packet[0], TransferModes.get_mode(packet[1]), block_size, window_size, bad_opts)

cat tftpd.py

#!/usr/bin/env python3
import socket
import sys
import threading
from tftp_common import TFTPConnection, TransferModes, ErrorPacket, ErrorCodes, RRQPacket, DEBUG, TFTPPacket,
OACKPacket, ACKPacket
class TFTPServerConnection(TFTPConnection):
def init(self, client_address, base_path: bytes):
connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
connection.bind(('', 0))
super().init(connection, client_address)
self.base_path = base_path
def handle_file_request(self, packet: RRQPacket):
if packet.bad_opts:
if DEBUG:
print('Bad opts')
self.send_packet(ErrorPacket(ErrorCodes.UNSUPPORTED_OPTS, b'Only blksize and windowsize opts supported'))
return
if packet.mode != TransferModes.OCTET:
if DEBUG:
print('Bad mode: ', packet.mode)
self.send_packet(ErrorPacket(ErrorCodes.ILLEGAL_OPERATION, b'Only octet mode supported'))
return
if packet.block_size != 512 or packet.window_size != 1:
counter = 0
while counter < 20:
counter += 1
self.send_packet(OACKPacket(packet.block_size, packet.window_size))
try:
packed, _ = self.receive_packet()
except TimeoutError:
pass
if isinstance(packet, ACKPacket):
if packet.ack_id == 0:
break
try:
file = open(self.base_path + packet.filename, 'rb')
self.transmit_file(file, packet.block_size, packet.window_size)
file.close()
except IOError as er:
self.send_packet(ErrorPacket(ErrorCodes.FILE_NOT_FOUND, str(er).encode('utf8')))
class TFTPServer:
def init(self, bind_to: str = '', port: int = 6969, base_path: bytes = b''):
self.master_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.master_socket.bind((bind_to, port))
self.base_path = base_path
def file_request(self, packet: RRQPacket, client_address):
if DEBUG:
print('File requested ', packet.filename)
connection = TFTPServerConnection(client_address, base_path=self.base_path)
connection.handle_file_request(packet)
connection.close()
def run(self):
while True:
frame, client_address = self.master_socket.recvfrom(65535)
if DEBUG:
print('Connection form ', client_address)
packet = TFTPPacket.decode(frame)
if isinstance(packet, RRQPacket):
threading.Thread(target=self.file_request, args=(packet, client_address)).run()
path = sys.argv[2].encode('utf8')
if path[-1] != b'/':
path += b'/'
TFTPServer(port=int(sys.argv[1]), base_path=path).run()

what am I doing wrong ? looks like the wiki's page doesnt explain that clear :frowning:
(first time I use patch process/command..)

thank you

None of your links say anything about python scripts.
What are you trying to accomplish?

1 Like

TFTP server implementations on a PC OS are outside the scope of this forum. On the other hand, a second OpenWrt router can be readily used as a TFTP server.

  • Change the LAN IP to 192.168.1.66 or whatever the target router is expecting.
  • Add these two lines to the global settings in /etc/config/dhcp: option enable_tftp 1 and option tftp_root '/tmp/tftpboot'
  • Restart dnsmasq or reboot the router to start up the TFTP server. The directory /tmp/tftpboot should now exist.
  • scp or otherwise copy the firmware file to /tmp/tftpboot. Note this is a RAM disk and it will be erased on a reboot.
  • Connect the router to be installed / recovered to one of the LAN ports and power it up in TFTP mode.
2 Likes

Hi @prem2,

Flashing TP-Link Archer C2 AC750 over TFTP normally should not require making modifications to the TFTP server. The approach you are linking to is a work-around which may help with some partially defective devices that are for some reason unable to perform a TFTP download from a standards-compliant TFTP server.

If you indeed do have such a partially defective Archer C2 device, then patching a TFTP server is a way to allow the TFTP download to finish successfully.

The approach mentioned in the linked post patches the tftp_common.py file from the PyTFTPd TFTP server. Its code seems to have remained unchanged for 8 years now. So the originally provided patch should still apply cleanly.

It can be applied like this:

# enter the main directory of the PyTFTPd TFTP server
$ cd PyTFTPd
# apply the patch
$ patch -p1 < /path/to/provided.patch
patching file tftp_common.py

From your message it seems like you are trying to patch the tftpd.py file instead.

Also, any of the current online AI assistants in their freely accessible versions, such as Claude, ChatGPT, Google Gemini, etc. should be able to help you out with this kind of questions.

Futile efforts fly,
Whispering to silence's ear,
Dead horse won't rise again.

thank you, it worked ! :slight_smile:

1 Like