forked from mirrors/tftp-hpa-google
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)
This commit is contained in:
parent
5f64014add
commit
ec5973ac5f
4 changed files with 56 additions and 34 deletions
|
@ -272,3 +272,41 @@ synchnet(int f) /* socket to flush */
|
||||||
|
|
||||||
return pktcount; /* Return packets drained */
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -74,3 +74,6 @@ extern char *xstrdup(const char *);
|
||||||
void (*bsd_signal(int, void (*)(int)))(int);
|
void (*bsd_signal(int, void (*)(int)))(int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int from, unsigned int to);
|
||||||
|
|
15
tftp/main.c
15
tftp/main.c
|
@ -102,6 +102,9 @@ const char *prompt = "tftp> ";
|
||||||
sigjmp_buf toplevel;
|
sigjmp_buf toplevel;
|
||||||
void intr(int);
|
void intr(int);
|
||||||
struct servent *sp;
|
struct servent *sp;
|
||||||
|
int portrange = 0;
|
||||||
|
unsigned int portrange_from = 0;
|
||||||
|
unsigned int portrange_to = 0;
|
||||||
|
|
||||||
void get (int, char **);
|
void get (int, char **);
|
||||||
void help (int, char **);
|
void help (int, char **);
|
||||||
|
@ -241,6 +244,16 @@ main(int argc, char *argv[])
|
||||||
case 'c':
|
case 'c':
|
||||||
iscmd = 1;
|
iscmd = 1;
|
||||||
break;
|
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':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
usage(*optx == 'h' ? 0 : EX_USAGE);
|
usage(*optx == 'h' ? 0 : EX_USAGE);
|
||||||
|
@ -276,7 +289,7 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
bzero((char *)&s_in, sizeof (s_in));
|
bzero((char *)&s_in, sizeof (s_in));
|
||||||
s_in.sin_family = AF_INET;
|
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");
|
perror("tftp: bind");
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
|
@ -750,7 +718,7 @@ main(int argc, char **argv)
|
||||||
from.sin_family = AF_INET;
|
from.sin_family = AF_INET;
|
||||||
|
|
||||||
/* Process the request... */
|
/* 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");
|
syslog(LOG_ERR, "bind: %m");
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue