On Thu, Sep 27, 2018 at 11:59 AM sven falempin <sven.falem...@gmail.com> wrote:
> > > On Thu, Sep 27, 2018 at 10:47 AM sven falempin <sven.falem...@gmail.com> > wrote: > >> I m not sure how this is possible but here s the data : >> >> i used the ENV to push -w 5 in my pkg_add process : >> # date >> Thu Sep 27 10:40:28 EDT 2018 >> # ps auxww | grep pkgfet >> _pkgfetc 60348 0.0 0.1 1728 5456 ?? INp Wed05PM 0:00.09 /usr/bin/ftp -w 5 >> -S session -o - https:// >> myportal.com/tar/6.3/packages/amd64/p5-LWP-MediaTypes-6.02.tgz >> # fstat -p 60348 >> _pkgfetc ftp 60348 5* internet stream tcp 0xffff8000006e8548 >> 172.16.1.35:5512 --> 92.222.70.241:443 >> >> I can see the PF state on the natting device: >> >> tcp 206.180.254.190:52251 (172.16.1.35:5512) -> 92.222.70.241:443 >> ESTABLISHED:ESTABLISHED >> age: 16:55:28 expires: 07:07:25 id: 5b7ce30b0094854a >> rule: pass out quick on em5 all flags S/SA label "READY_TO_NAT" tagged >> READY_TO_NAT >> >> this is stock 6.3 ftp which is still the same now ( >> https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ftp/ ) >> >> # ktrace -p 60348 >> generate an empty 64 bit file. >> >> Any other test i could do to understand ? >> >> > Reading NC it seems that the 'poll' syscall is indeed required to timeout correctly. I m trying to find a way to recreate the problem and i am running a modified version in a loop My understanding of the tls_read(SSL_read then ssl_read) .. is that the retry is for SSL protocol error and retry which would only occur on non TCP layer. That's irrelevant in fetch.c I m just guessing the <handshake> ( at the top of ssl_read ) call will write and fix an POLLIN when write is done. This explaining trying to read again when a write is requested >.< Nevertheless each read/write code ( and even close ) shall be precede by a poll call. Bellow is the patch i m testing at the moment , i do not quite like it, it s not solving the problem, and show how the factorization of read is making the code hard to read/modify IMHO url_get should be just calling url_get_https url_get_http url_get_ftp and each of this function do only that. The _fin_ FILE* may be NULL fd may be -1 randomly in the function, it s kinda messy. And this make it difficult to nicely call poll before reading to avoid being blocked in a read indefinitely RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.167 diff -u -p -r1.167 fetch.c --- fetch.c 10 Feb 2018 06:25:16 -0000 1.167 +++ fetch.c 27 Sep 2018 20:10:52 -0000 @@ -59,6 +59,7 @@ #include <resolv.h> #ifndef NOSSL +#include <poll.h> #include <tls.h> #else /* !NOSSL */ struct tls; @@ -73,12 +74,12 @@ void abortfile(int); char hextochar(const char *); char *urldecode(const char *); char *recode_credentials(const char *_userinfo); -int ftp_printf(FILE *, struct tls *, const char *, ...) __attribute__((format(printf, 3, 4))); +int ftp_printf(FILE *, int fd, struct tls *, const char *, ...) __attribute__((format(printf, 4, 5))); char *ftp_readline(FILE *, struct tls *, size_t *); size_t ftp_read(FILE *, struct tls *, char *, size_t); #ifndef NOSSL int proxy_connect(int, char *, char *); -int SSL_vprintf(struct tls *, const char *, va_list); +int SSL_vprintf(int fd, struct tls *, const char *, va_list); char *SSL_readline(struct tls *, size_t *); #endif /* !NOSSL */ @@ -98,6 +99,90 @@ jmp_buf httpabort; static int redirect_loop; +#ifndef NOSSL +/*from netcat.c correct way to timeout a tls_call*/ +int +timeout_tls(int s, struct tls *tls_ctx, int (*func)(struct tls *)) +{ + int timeout = connect_timeout; // glu + struct pollfd pfd; + int ret; + + while ((ret = (*func)(tls_ctx)) != 0) { + if (ret == TLS_WANT_POLLIN) + pfd.events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd.events = POLLOUT; + else + break; + pfd.fd = s; + if ((ret = poll(&pfd, 1, timeout)) == 1) + continue; + else if (ret == 0) { + errno = ETIMEDOUT; + ret = -1; + break; + } else + err(1, "poll failed"); + } + + return ret; +} + +/*must realloc / offset*/ +int +timeout_tls_write(int s, struct tls *tls_ctx, + const void *buf, size_t buflen) +{ + int timeout = connect_timeout; // glu + struct pollfd pfd; + int ret; + + // should check ready first => do poll write then write + while ((ret = tls_write(tls_ctx,buf,buflen)) != 0) { + if (ret == TLS_WANT_POLLIN) + pfd.events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd.events = POLLOUT; + else + break; + pfd.fd = s; + if ((ret = poll(&pfd, 1, timeout)) == 1) + continue; + else if (ret == 0) { + errno = ETIMEDOUT; + ret = -1; + break; + } else + err(1, "poll failed"); + } + + return ret; +} + +// this may never timeout ! +int +timeout_tls_read(struct tls *tls_ctx, + void *buf, size_t len) { + int tret; + for (;;) { + tret = tls_read(tls_ctx, buf, len); + if (tret == TLS_WANT_POLLIN) { + if (debug) + fprintf(ttyout, "POLLIN REQUEST !\n"); + continue; + } + if (tret == TLS_WANT_POLLOUT) { + if (debug) + fprintf(ttyout, "POLLOUT REQUEST !\n"); + continue; + } + break; + } + return tret; +} +#endif + /* * Determine whether the character needs encoding, per RFC1738: * - No corresponding graphic US-ASCII. @@ -678,13 +763,13 @@ noslash: * the original URI (path). */ if (credentials) - ftp_printf(fin, tls, "GET %s HTTP/1.0\r\n" + ftp_printf(fin,fd, tls, "GET %s HTTP/1.0\r\n" "Proxy-Authorization: Basic %s\r\n" "Host: %s\r\n%s%s\r\n\r\n", epath, credentials, proxyhost, buf ? buf : "", httpuseragent); else - ftp_printf(fin, tls, "GET %s HTTP/1.0\r\n" + ftp_printf(fin, fd, tls, "GET %s HTTP/1.0\r\n" "Host: %s\r\n%s%s\r\n\r\n", epath, proxyhost, buf ? buf : "", httpuseragent); } else { @@ -702,7 +787,7 @@ noslash: #endif /* SMALL */ #ifndef NOSSL if (credentials) { - ftp_printf(fin, tls, + ftp_printf(fin, fd, tls, "GET /%s %s\r\nAuthorization: Basic %s\r\nHost: ", epath, restart_point ? "HTTP/1.1\r\nConnection: close" : "HTTP/1.0", @@ -711,13 +796,13 @@ noslash: credentials = NULL; } else #endif /* NOSSL */ - ftp_printf(fin, tls, "GET /%s %s\r\nHost: ", epath, + ftp_printf(fin, fd, tls, "GET /%s %s\r\nHost: ", epath, #ifndef SMALL restart_point ? "HTTP/1.1\r\nConnection: close" : #endif /* !SMALL */ "HTTP/1.0"); if (proxyhost) { - ftp_printf(fin, tls, "%s", proxyhost); + ftp_printf(fin, fd, tls, "%s", proxyhost); port = NULL; } else if (strchr(host, ':')) { /* @@ -729,10 +814,10 @@ noslash: errx(1, "Can't allocate memory."); if ((p = strchr(h, '%')) != NULL) *p = '\0'; - ftp_printf(fin, tls, "[%s]", h); + ftp_printf(fin, fd, tls, "[%s]", h); free(h); } else - ftp_printf(fin, tls, "%s", host); + ftp_printf(fin, fd, tls, "%s", host); /* * Send port number only if it's specified and does not equal @@ -741,15 +826,15 @@ noslash: */ #ifndef NOSSL if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) - ftp_printf(fin, tls, ":%s", port); + ftp_printf(fin, fd, tls, ":%s", port); if (restart_point) - ftp_printf(fin, tls, "\r\nRange: bytes=%lld-", + ftp_printf(fin, fd, tls, "\r\nRange: bytes=%lld-", (long long)restart_point); #else /* !NOSSL */ if (port && strcmp(port, "80") != 0) - ftp_printf(fin, tls, ":%s", port); + ftp_printf(fin, fd, tls, ":%s", port); #endif /* !NOSSL */ - ftp_printf(fin, tls, "\r\n%s%s\r\n\r\n", + ftp_printf(fin, fd, tls, "\r\n%s%s\r\n\r\n", buf ? buf : "", httpuseragent); } free(epath); @@ -1040,9 +1125,8 @@ cleanup_url_get: if (tls_session_fd != -1) dprintf(STDERR_FILENO, "tls session resumed: %s\n", tls_conn_session_resumed(tls) ? "yes" : "no"); - do { - i = tls_close(tls); - } while (i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); + + i = timeout_tls(fd,tls,tls_close); tls_free(tls); } free(full_host); @@ -1527,9 +1611,8 @@ ftp_read(FILE *fp, struct tls *tls, char ret = fread(buf, sizeof(char), len, fp); #ifndef NOSSL else if (tls != NULL) { - do { - tret = tls_read(tls, buf, len); - } while (tret == TLS_WANT_POLLIN || tret == TLS_WANT_POLLOUT); + tret = timeout_tls_read(tls, buf, len); + if (tret < 0) errx(1, "SSL read error: %s", tls_error(tls)); ret = (size_t)tret; @@ -1539,7 +1622,7 @@ ftp_read(FILE *fp, struct tls *tls, char } int -ftp_printf(FILE *fp, struct tls *tls, const char *fmt, ...) +ftp_printf(FILE *fp, int fd, struct tls *tls, const char *fmt, ...) { int ret; va_list ap; @@ -1549,8 +1632,9 @@ ftp_printf(FILE *fp, struct tls *tls, co if (fp != NULL) ret = vfprintf(fp, fmt, ap); #ifndef NOSSL - else if (tls != NULL) - ret = SSL_vprintf(tls, fmt, ap); + else if (tls != NULL) { + ret = SSL_vprintf(fd, tls, fmt, ap); + } #endif /* !NOSSL */ else ret = 0; @@ -1568,7 +1652,7 @@ ftp_printf(FILE *fp, struct tls *tls, co #ifndef NOSSL int -SSL_vprintf(struct tls *tls, const char *fmt, va_list ap) +SSL_vprintf(int fd, struct tls *tls, const char *fmt, va_list ap) { char *string, *buf; size_t len; @@ -1579,9 +1663,7 @@ SSL_vprintf(struct tls *tls, const char buf = string; len = ret; while (len > 0) { - ret = tls_write(tls, buf, len); - if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) - continue; + ret = timeout_tls_write(fd, tls, buf, len); if (ret < 0) errx(1, "SSL write error: %s", tls_error(tls)); buf += ret; @@ -1608,9 +1690,7 @@ SSL_readline(struct tls *tls, size_t *le buf = q; len *= 2; } - do { - ret = tls_read(tls, &c, 1); - } while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); + ret = timeout_tls_read(tls, &c, 1); if (ret < 0) errx(1, "SSL read error: %s", tls_error(tls)); -- -- --------------------------------------------------------------------------------------------------------------------- Knowing is not enough; we must apply. Willing is not enough; we must do