ftpd: bound the PASV port search instead of looping forever
On a failed bind cmdPASV jumped straight back to .next_port, and nextpasvport wraps within [start, end], so a range with no usable port spun forever without reading the control connection again: the client hangs. The source itself said "TODO: break the endless loop". Count the ports in the range (end - start + 1), decrement after a failed bind and give up at zero, then close the listener, reset the state and answer 425 Can't open data connection. The counter lives in a new thread_data field rather than a register, because mcall bind clobbers eax/ebx/ecx/edx/esi/edi and esi already carries the sockaddr length for bind. Decrementing after the failed bind and not before the next attempt is what keeps a single-port range (start = end) working: it still gets its one attempt. Also validate the pair read from the ini. With start > end the range degenerates and no port is bindable, so fall back to 2000/5000. Assisted-by: ZCode:deepseek-flash
This commit is contained in:
1 parent
1e05d19c4c
commit
2091d65381
2 files changed
+28
-2
No files matched your search
@@ -14,6 +14,7 @@ struct thread_data
|
||||
socketnum dd ? ; Commands socket
|
||||
state dd ? ; disconnected/logging in/logged in/..
|
||||
passivesocknum dd ? ; when in passive mode, this is the listening socket
|
||||
pasv_tries dd ? ; ports tried for the current PASV
|
||||
datasocketnum dd ? ; socket used for data transfers
|
||||
permissions dd ? ; read/write/execute/....
|
||||
buffer_ptr dd ?
|
||||
@@ -847,7 +848,13 @@ cmdPASV:
|
||||
lea edx, [ebp + thread_data.datasock]
|
||||
mov esi, sizeof.thread_data.datasock
|
||||
|
||||
.next_port: ; TODO: break the endless loop
|
||||
movzx eax, word [pasv_end]
|
||||
movzx ebx, word [pasv_start]
|
||||
sub eax, ebx
|
||||
inc eax
|
||||
mov [ebp + thread_data.pasv_tries], eax ; number of ports in the range
|
||||
|
||||
.next_port:
|
||||
call nextpasvport
|
||||
mov ax, [pasv_port]
|
||||
xchg al, ah
|
||||
@@ -855,7 +862,18 @@ cmdPASV:
|
||||
|
||||
mcall bind
|
||||
cmp eax, -1
|
||||
je .next_port
|
||||
jne .bound
|
||||
dec dword [ebp + thread_data.pasv_tries] ; only count a port once bind failed
|
||||
jnz .next_port
|
||||
|
||||
; The range is exhausted, do not spin here forever
|
||||
mcall close, [ebp + thread_data.passivesocknum]
|
||||
mov [ebp + thread_data.passivesocknum], -1
|
||||
call close_data_sock
|
||||
mov [ebp + thread_data.mode], MODE_NOTREADY
|
||||
jmp socketerror
|
||||
|
||||
.bound:
|
||||
|
||||
; And set it to listen!
|
||||
mcall listen, , 1
|
||||
|
||||
@@ -172,6 +172,14 @@ start:
|
||||
invoke ini.get_int, path, str_pasv, str_end, 5000
|
||||
mov [pasv_end], ax
|
||||
|
||||
; an inverted range would leave no port to bind, fall back to the defaults
|
||||
mov ax, [pasv_start]
|
||||
cmp ax, [pasv_end]
|
||||
jbe @f
|
||||
mov word [pasv_start], 2000
|
||||
mov word [pasv_end], 5000
|
||||
@@:
|
||||
|
||||
mov [alive], 1
|
||||
|
||||
mainloop:
|
||||
|
||||
Reference in new issue
Block a user