summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Anvin <hpa@tazenda.sc.orionmulti.com>2005-10-13 11:30:45 -0700
committerPeter Anvin <hpa@tazenda.sc.orionmulti.com>2005-10-13 11:30:45 -0700
commitae1305e2d56d0a90d6e25f04006412f73cea8ba2 (patch)
tree1803f879a42af2fcfb364b8a006302f6621599dd
parent25d63c415a548ac400acc63f687b25f35262e948 (diff)
downloadtftp-hpa-ae1305e2d56d0a90d6e25f04006412f73cea8ba2.tar.gz
Local port range functionality hack
-rw-r--r--tftpd/tftpd.c53
1 files changed, 43 insertions, 10 deletions
diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c
index 8c3033e..f859afd 100644
--- a/tftpd/tftpd.c
+++ b/tftpd/tftpd.c
@@ -104,11 +104,12 @@ int tsize_ok;
int ndirs;
const char **dirs;
-int secure = 0;
-int cancreate = 0;
-int unixperms = 0;
-
-int verbosity = 0;
+int secure = 0;
+int cancreate = 0;
+int unixperms = 0;
+int portrange = 0;
+unsigned int portrange_from, portrange_to;
+int verbosity = 0;
struct formats;
#ifdef WITH_REGEX
@@ -303,8 +304,10 @@ main(int argc, char **argv)
__progname = (p && p[1]) ? p+1 : argv[0];
openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
+
+ srand(time(NULL) ^ getpid());
- while ((c = getopt(argc, argv, "cspvVla:B:u:U:r:t:T:m:")) != -1)
+ while ((c = getopt(argc, argv, "cspvVla:B:u:U:r:t:T:R:m:")) != -1)
switch (c) {
case 'c':
cancreate = 1;
@@ -347,6 +350,16 @@ main(int argc, char **argv)
maxtimeout = rexmtval*TIMEOUT_LIMIT;
}
break;
+ case 'R':
+ {
+ if ( sscanf(optarg, "%u:%u", &portrange_from, &portrange_to) != 2 ||
+ portrange_from > portrange_to || portrange_to >= 65535 ) {
+ syslog(LOG_ERR, "Bad port range: %s", optarg);
+ exit(EX_USAGE);
+ }
+ portrange = 1;
+ }
+ break;
case 'u':
user = optarg;
break;
@@ -705,11 +718,31 @@ main(int argc, char **argv)
/* Process the request... */
- myaddr.sin_port = htons(0); /* We want a new local port */
- if (bind(peer, (struct sockaddr *)&myaddr, sizeof myaddr) < 0) {
- syslog(LOG_ERR, "bind: %m");
- exit(EX_IOERR);
+ while(1) {
+ unsigned int port;
+
+ if ( portrange ) {
+ /* Pick a (pseudo)random port in the relevant range */
+ port = portrange_from + rand() % (portrange_to-portrange_from+1);
+ } else {
+ port = 0; /* Let the kernel pick a port */
+ }
+
+
+ myaddr.sin_port = htons(port);
+
+ if (bind(peer, (struct sockaddr *)&myaddr, sizeof myaddr) < 0) {
+ if ( (errno == EINVAL || errno == EADDRINUSE) && portrange )
+ continue; /* Should not happen in normal operation, but try again */
+
+ syslog(LOG_ERR, "bind: %m");
+ exit(EX_IOERR);
+ } else {
+ break;
+ }
}
+
+
if (connect(peer, (struct sockaddr *)&from, sizeof from) < 0) {
syslog(LOG_ERR, "connect: %m");
exit(EX_IOERR);