How to detect or log interrupted uploads with OpenSSH SFTP server?
I have this problem where a customer of ours has been SFTP-ing truncated data. I'm not sure if the problem is on our end or his. I've enabled SFTP logging but it does not allow me to detect if an upload has been interrupted.
For example, if I fire up the sftp client, and hit ^C
in the middle of the upload, the server just says something like close "/data/README.md" bytes read 0 written 5366
, which is indistinguishable from an uninterrupted upload.
I guess something like a .part
prefix would work but by looking at other posts on server fault, I don't think it's possible with OpenSSH's sftp server.
So, is there a way for me to detect if a file upload has been interrupted?
I assume that by "sftp client" you refer to an OpenSSH SFTP client. The "problem" is that when you press Ctrl+C, it stops the upload and cleanly closes the remote file, just as if the upload completely finished (note that it is a correct behavior and many other SFTP clients behave the same). So the server has absolutely no way to tell that the upload was interrupted.
Well strictly speaking it has, as the OpenSSH client sends a size hint to the server when creating the file. But OpenSSH server does not use nor even log that information. Though it would be pretty simple to modify its code to log the size, if that's an option for you.
See process_open
in sftp-server.c
:
a = get_attrib();
flags = flags_from_portable(pflags);
mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
logit("open \"%s\" flags %s mode 0%o",
name, string_from_portable(pflags), mode);
Change the logit
statement to:
logit("open \"%s\" flags %s mode 0%o size %llu",
name, string_from_portable(pflags), mode, (unsigned long long)a->size);
Note that sending the size hint is optional. While some SFTP clients will send it (e.g. OpenSSH or WinSCP), some won't (e.g. PSFTP, FileZilla, or LFTP). In such a case, you will get 0 in a->size
.
Had the client really aborted the upload (without closing the remote file cleanly, e.g. when sftp
is killed), you would be able to tell it from "forced" prefix to "close" record:
forced close "/data/README.md" bytes read 0 written 5366