summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZack Bartel <zack@jack.localdomain>2006-11-13 17:33:29 -0800
committerZack Bartel <zack@jack.localdomain>2006-11-13 17:33:29 -0800
commitec5973ac5fa6beb57629ef38f3f602d5f8880edd (patch)
tree9d14e142fcce4737ab9e1eb7cb96f4d119b9fa07
parent5f64014add3ac0030945f52755b37ba6ccb65ecc (diff)
downloadtftp-hpa-ec5973ac5fa6beb57629ef38f3f602d5f8880edd.tar.gz
Moved pick_port_bind() to the libcommon common code so both client and server can use it. Client can now specify a range of ephemeral ports (transaction id)
-rw-r--r--common/tftpsubs.c38
-rw-r--r--common/tftpsubs.h3
-rw-r--r--tftp/main.c15
-rw-r--r--tftpd/tftpd.c34
4 files changed, 56 insertions, 34 deletions
diff --git a/common/tftpsubs.c b/common/tftpsubs.c
index 9103106..b2eae71 100644
--- a/common/tftpsubs.c
+++ b/common/tftpsubs.c
@@ -272,3 +272,41 @@ synchnet(int f) /* socket to flush */
return pktcount; /* Return packets drained */
}
+
+
+int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int port_range_from, unsigned int port_range_to)
+{
+ unsigned int port, firstport;
+ int port_range = 0;
+
+ if (port_range_from != 0 && port_range_to != 0) {
+ port_range = 1;
+ }
+
+ firstport = port_range
+ ? port_range_from + rand() % (port_range_to-port_range_from+1)
+ : 0;
+
+ port = firstport;
+
+ do {
+ myaddr->sin_port = htons(port);
+
+ if (bind(sockfd, (struct sockaddr *)myaddr, sizeof *myaddr) < 0) {
+ /* Some versions of Linux return EINVAL instead of EADDRINUSE */
+ if ( !(port_range && (errno == EINVAL || errno == EADDRINUSE)) )
+ return -1;
+
+ /* Normally, we shouldn't have to loop, but some situations involving
+ aborted transfers make it possible. */
+ } else {
+ return 0;
+ }
+
+ port++;
+ if ( port > port_range_to )
+ port = port_range_from;
+ } while ( port != firstport );
+
+ return -1;
+}
diff --git a/common/tftpsubs.h b/common/tftpsubs.h
index 645c6b9..359ba1a 100644
--- a/common/tftpsubs.h
+++ b/common/tftpsubs.h
@@ -74,3 +74,6 @@ extern char *xstrdup(const char *);
void (*bsd_signal(int, void (*)(int)))(int);
#endif
+
+
+int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int from, unsigned int to);
diff --git a/tftp/main.c b/tftp/main.c
index 3a8315f..c3ec3a0 100644
--- a/tftp/main.c
+++ b/tftp/main.c
@@ -102,6 +102,9 @@ const char *prompt = "tftp> ";
sigjmp_buf toplevel;
void intr(int);
struct servent *sp;
+int portrange = 0;
+unsigned int portrange_from = 0;
+unsigned int portrange_to = 0;
void get (int, char **);
void help (int, char **);
@@ -241,6 +244,16 @@ main(int argc, char *argv[])
case 'c':
iscmd = 1;
break;
+ case 'R':
+ if ( ++arg >= argc )
+ usage(EX_USAGE);
+ if ( sscanf(argv[arg], "%u:%u", &portrange_from, &portrange_to) != 2 ||
+ portrange_from > portrange_to || portrange_to > 65535 ) {
+ fprintf(stderr, "Bad port range: %s\n", argv[arg]);
+ exit(EX_USAGE);
+ }
+ portrange = 1;
+ break;
case 'h':
default:
usage(*optx == 'h' ? 0 : EX_USAGE);
@@ -276,7 +289,7 @@ main(int argc, char *argv[])
}
bzero((char *)&s_in, sizeof (s_in));
s_in.sin_family = AF_INET;
- if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
+ if (pick_port_bind(f, &s_in, portrange_from, portrange_to)) {
perror("tftp: bind");
exit(EX_OSERR);
}
diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c
index 6018850..09d8733 100644
--- a/tftpd/tftpd.c
+++ b/tftpd/tftpd.c
@@ -273,38 +273,6 @@ static int recv_time(int s, void *rbuf, int len, unsigned int flags,
}
}
-static int
-pick_port_bind(int sockfd, struct sockaddr_in *myaddr)
-{
- unsigned int port, firstport;
-
- firstport = portrange
- ? portrange_from + rand() % (portrange_to-portrange_from+1)
- : 0;
-
- port = firstport;
-
- do {
- myaddr->sin_port = htons(port);
-
- if (bind(sockfd, (struct sockaddr *)myaddr, sizeof *myaddr) < 0) {
- /* Some versions of Linux return EINVAL instead of EADDRINUSE */
- if ( !(portrange && (errno == EINVAL || errno == EADDRINUSE)) )
- return -1;
-
- /* Normally, we shouldn't have to loop, but some situations involving
- aborted transfers make it possible. */
- } else {
- return 0;
- }
-
- port++;
- if ( port > portrange_to )
- port = portrange_from;
- } while ( port != firstport );
-
- return -1;
-}
int
main(int argc, char **argv)
@@ -750,7 +718,7 @@ main(int argc, char **argv)
from.sin_family = AF_INET;
/* Process the request... */
- if (pick_port_bind(peer, &myaddr) < 0) {
+ if (pick_port_bind(peer, &myaddr, portrange_from, portrange_to) < 0) {
syslog(LOG_ERR, "bind: %m");
exit(EX_IOERR);
}