diff --git a/appl/ftp/ftpd/ftpd.8 b/appl/ftp/ftpd/ftpd.8 index bc927058c..22152be6c 100644 --- a/appl/ftp/ftpd/ftpd.8 +++ b/appl/ftp/ftpd/ftpd.8 @@ -42,7 +42,7 @@ .Sh SYNOPSIS .Nm .Op Fl a Ar authmode -.Op Fl dilv +.Op Fl dilvU .Op Fl g Ar umask .Op Fl p Ar port .Op Fl T Ar maxtimeout @@ -128,6 +128,14 @@ The inactivity timeout period is set to seconds (the default is 15 minutes). .It Fl u Set the initial umask to something else than the default 027. +.It Fl U +In previous versions of +.Nm ftpd , +when a passive mode client requested a data connection to the server, the +server would use data ports in the range 1024..4999. Now, by default, +if the system supports the IP_PORTRANGE socket option, the server will +use data ports in the range 49152..65535. Specifying this option will +revert to the old behavior. .It Fl v Verbose mode. .It Xo diff --git a/appl/ftp/ftpd/ftpd.c b/appl/ftp/ftpd/ftpd.c index c38eaffd8..295c2d753 100644 --- a/appl/ftp/ftpd/ftpd.c +++ b/appl/ftp/ftpd/ftpd.c @@ -68,6 +68,7 @@ struct passwd *pw; int debug = 0; int ftpd_timeout = 900; /* timeout after 15 minutes of inactivity */ int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ +int restricted_data_ports = 1; int logging; int guest; int dochroot; @@ -217,6 +218,7 @@ struct getargs args[] = { { NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" }, { NULL, 'T', arg_integer, &maxtimeout, "max timeout" }, { NULL, 'u', arg_string, &umask_string, "umask for user logins" }, + { NULL, 'U', arg_negative_flag, &restricted_data_ports, "don't use high data ports" }, { NULL, 'd', arg_flag, &debug, "enable debugging" }, { NULL, 'v', arg_flag, &debug, "enable debugging" }, { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" }, @@ -1951,6 +1953,8 @@ pasv(void) socket_set_address_and_port (pasv_addr, socket_get_address (ctrl_addr), 0); + socket_set_portrange(pdata, restricted_data_ports, + pasv_addr->sa_family); seteuid(0); if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { seteuid(pw->pw_uid); @@ -1993,6 +1997,8 @@ epsv(char *proto) socket_set_address_and_port (pasv_addr, socket_get_address (ctrl_addr), 0); + socket_set_portrange(pdata, restricted_data_ports, + pasv_addr->sa_family); seteuid(0); if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { seteuid(pw->pw_uid); diff --git a/lib/roken/roken-common.h b/lib/roken/roken-common.h index 8cffed37d..4958b0873 100644 --- a/lib/roken/roken-common.h +++ b/lib/roken/roken-common.h @@ -301,6 +301,9 @@ socket_get_port (const struct sockaddr *sa); void socket_set_port (struct sockaddr *sa, int port); +void +socket_set_portrange (int sock, int restrict, int af); + void socket_set_debug (int sock); diff --git a/lib/roken/socket.c b/lib/roken/socket.c index 3181bc7cd..be2513961 100644 --- a/lib/roken/socket.c +++ b/lib/roken/socket.c @@ -221,6 +221,31 @@ socket_set_port (struct sockaddr *sa, int port) } } +/* + * Set the range of ports to use when binding with port = 0. + */ +void +socket_set_portrange (int sock, int restrict, int af) +{ +#if defined(IP_PORTRANGE) + if (af == AF_INET) { + int on = restrict ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; + if (setsockopt (sock, IPPROTO_IP, IP_PORTRANGE, &on, + sizeof(on)) < 0) + warn ("setsockopt IP_PORTRANGE (ignored)"); + } +#endif +#if defined(IPV6_PORTRANGE) + if (af == AF_INET6) { + int on = restrict ? IPV6_PORTRANGE_HIGH : + IPV6_PORTRANGE_DEFAULT; + if (setsockopt (sock, IPPROTO_IPV6, IPV6_PORTRANGE, &on, + sizeof(on)) < 0) + warn ("setsockopt IPV6_PORTRANGE (ignored)"); + } +#endif +} + /* * Enable debug on `sock'. */