All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit e6a0977e authored by David Johnson's avatar David Johnson

Allow tiptunnel to set serial device options via capture.

For now, I made it possible to set speed of the capture with
tiptunnel.  Later we could expose more options... but the right
thing to do is build a ConsoleAgent that is much more flexible.
I think we now know what we need as far as a good feature set
for that program.
parent 997dc57a
...@@ -108,7 +108,7 @@ int handleupload(void); ...@@ -108,7 +108,7 @@ int handleupload(void);
#define DEVNAME "%s/%s" #define DEVNAME "%s/%s"
#define BUFSIZE 4096 #define BUFSIZE 4096
#define DROP_THRESH (32*1024) #define DROP_THRESH (32*1024)
#define MAX_UPLOAD_SIZE (1 * 1024 * 1024) #define MAX_UPLOAD_SIZE (32 * 1024 * 1024)
#define DEFAULT_CERTFILE PREFIX"/etc/capture.pem" #define DEFAULT_CERTFILE PREFIX"/etc/capture.pem"
#define DEFAULT_CLIENT_CERTFILE PREFIX"/etc/client.pem" #define DEFAULT_CLIENT_CERTFILE PREFIX"/etc/client.pem"
#define DEFAULT_CAFILE PREFIX"/etc/emulab.pem" #define DEFAULT_CAFILE PREFIX"/etc/emulab.pem"
...@@ -1562,9 +1562,14 @@ clientconnect(void) ...@@ -1562,9 +1562,14 @@ clientconnect(void)
secretkey_t key; secretkey_t key;
capret_t capret; capret_t capret;
#ifdef WITHSSL #ifdef WITHSSL
int dorelay = 0, doupload = 0; int dorelay = 0, doupload = 0, dooptions = 0;
int newspeed = 0;
speed_t newsymspeed;
int opterr = 0;
int ret; int ret;
SSL *newssl; SSL *newssl;
struct termios serial_opts;
char *caddr;
#endif #endif
newfd = accept(sockfd, (struct sockaddr *)&sin, &length); newfd = accept(sockfd, (struct sockaddr *)&sin, &length);
...@@ -1588,6 +1593,7 @@ clientconnect(void) ...@@ -1588,6 +1593,7 @@ clientconnect(void)
if (cc == sizeof(key) && if (cc == sizeof(key) &&
(0 == strncmp( key.key, "USESSL", 6 ) || (0 == strncmp( key.key, "USESSL", 6 ) ||
(dorelay = (0 == strncmp( key.key, "RELAY", 5 ))) || (dorelay = (0 == strncmp( key.key, "RELAY", 5 ))) ||
(dooptions = (0 == strncmp( key.key, "OPTIONS", 7 ))) ||
(doupload = (0 == strncmp( key.key, "UPLOAD", 6 ))))) { (doupload = (0 == strncmp( key.key, "UPLOAD", 6 ))))) {
/* /*
dolog(LOG_NOTICE, "Client %s wants to use SSL", dolog(LOG_NOTICE, "Client %s wants to use SSL",
...@@ -1663,6 +1669,56 @@ clientconnect(void) ...@@ -1663,6 +1669,56 @@ clientconnect(void)
return 0; return 0;
} }
} }
else if (dooptions) {
/*
* Just handle these quick inline -- then don't have to
* worry about multiple option changes cause they all
* happen "atomically" from the client point of view.
*/
caddr = inet_ntoa(sin.sin_addr);
sscanf(key.key,"OPTIONS SPEED=%d",&newspeed);
newsymspeed = val2speed(newspeed);
dolog(LOG_NOTICE,"%s changing speed to %d.",
caddr,newspeed);
if (newspeed == 0) {
dolog(LOG_ERR,"%s invalid speed option %d.",
caddr,newspeed);
opterr = 1;
}
if (opterr == 0 && tcgetattr(devfd,&serial_opts) == -1) {
dolog(LOG_ERR,"%s failed to get attrs before speed change: %s.",
caddr,strerror(errno));
opterr = 1;
}
// XXX testing
//serial_opts.c_lflag |= ECHO | ECHONL;
if (opterr) {
}
else if (cfsetispeed(&serial_opts,newsymspeed) == -1) {
dolog(LOG_ERR,"%s cfsetispeed(%d) failed: %s.",
caddr,newspeed,strerror(errno));
opterr = 1;
}
else if (cfsetospeed(&serial_opts,newsymspeed) == -1) {
dolog(LOG_ERR,"%s cfsetospeed(%d) failed: %s.",
caddr,newspeed,strerror(errno));
opterr = 1;
}
else if (tcsetattr(devfd,TCSANOW,&serial_opts) == -1) {
dolog(LOG_ERR,"%s tcsetattr(%d) failed: %s.",
caddr,newspeed,strerror(errno));
opterr = 1;
}
SSL_free(newssl);
shutdown(newfd, SHUT_RDWR);
close(newfd);
return opterr;
}
else if (dorelay) { else if (dorelay) {
if (devfd >= 0) { if (devfd >= 0) {
dolog(LOG_NOTICE, "%s relay already connected.", dolog(LOG_NOTICE, "%s relay already connected.",
...@@ -1837,7 +1893,7 @@ handleupload(void) ...@@ -1837,7 +1893,7 @@ handleupload(void)
} }
} }
else if ((upfilesize + rc) > MAX_UPLOAD_SIZE) { else if ((upfilesize + rc) > MAX_UPLOAD_SIZE) {
dolog(LOG_NOTICE, "upload to large"); dolog(LOG_NOTICE, "upload too large");
drop = 1; drop = 1;
} }
else if (rc == 0) { else if (rc == 0) {
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <termios.h>
#include <fcntl.h> #include <fcntl.h>
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
...@@ -35,6 +36,8 @@ ...@@ -35,6 +36,8 @@
int localmode = 0; int localmode = 0;
int uploadmode = 0; int uploadmode = 0;
int optionsmode = 0;
int speed = -1;
#define ACLDIR "/var/log/tiplogs" #define ACLDIR "/var/log/tiplogs"
#define DEFAULT_PROGRAM "xterm -T TIP -e telnet localhost @s" #define DEFAULT_PROGRAM "xterm -T TIP -e telnet localhost @s"
...@@ -88,6 +91,8 @@ char * certString = NULL; ...@@ -88,6 +91,8 @@ char * certString = NULL;
#endif /* WITHSSL */ #endif /* WITHSSL */
static void dotippipe(int capsock,int localin,int localout);
#if defined(TIPPTY) #if defined(TIPPTY)
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
...@@ -138,6 +143,8 @@ int main( int argc, char ** argv ) ...@@ -138,6 +143,8 @@ int main( int argc, char ** argv )
const char * name = argv[0]; const char * name = argv[0];
char * aclfile = (char *) NULL; char * aclfile = (char *) NULL;
int op; int op;
int oldflags;
struct termios tios;
#if defined(LOCALBYDEFAULT) || defined(TIPPTY) #if defined(LOCALBYDEFAULT) || defined(TIPPTY)
localmode++; localmode++;
...@@ -146,7 +153,7 @@ int main( int argc, char ** argv ) ...@@ -146,7 +153,7 @@ int main( int argc, char ** argv )
#endif #endif
#endif #endif
while ((op = getopt( argc, argv, "hlp:rdu:c:a:" )) != -1) { while ((op = getopt( argc, argv, "hlp:rdu:c:a:os:" )) != -1) {
switch (op) { switch (op) {
case 'h': case 'h':
usage(name); usage(name);
...@@ -172,6 +179,15 @@ int main( int argc, char ** argv ) ...@@ -172,6 +179,15 @@ int main( int argc, char ** argv )
uploadmode++; uploadmode++;
usingSSL++; usingSSL++;
break; break;
case 's':
speed = atoi(optarg);
if (speed <= 0) {
fprintf(stderr,"Speed option must be greater than 0\n");
usage(name);
}
optionsmode++;
usingSSL++;
break;
case 'c': case 'c':
certfile = optarg; certfile = optarg;
break; break;
...@@ -191,6 +207,14 @@ int main( int argc, char ** argv ) ...@@ -191,6 +207,14 @@ int main( int argc, char ** argv )
} else { } else {
programToLaunch = strdup( DEFAULT_PROGRAM ); programToLaunch = strdup( DEFAULT_PROGRAM );
} }
if (debug) printf("Will launch program '%s'\n",programToLaunch);
if (uploadmode && optionsmode) {
fprintf(stderr,
"You cannot specify both an upload and options; "
" they must be done with multiple invocations of %s",name);
usage(name);
}
if (localmode) { if (localmode) {
if (aclfile) if (aclfile)
...@@ -252,6 +276,9 @@ int main( int argc, char ** argv ) ...@@ -252,6 +276,9 @@ int main( int argc, char ** argv )
} }
} }
if (optionsmode)
exit(0);
if (uploadmode) { if (uploadmode) {
int fd = STDIN_FILENO; int fd = STDIN_FILENO;
...@@ -293,6 +320,36 @@ int main( int argc, char ** argv ) ...@@ -293,6 +320,36 @@ int main( int argc, char ** argv )
dotippty(argv[0]); dotippty(argv[0]);
#else #else
if (localmode && strcmp(programToLaunch,"-") == 0) {
// just hook stdin/out to connection ;)
oldflags = fcntl(STDIN_FILENO,F_GETFL);
oldflags |= O_NONBLOCK;
fcntl(STDIN_FILENO,F_SETFL,oldflags);
// also get rid of line buffering -- we do enough buffering
// internally!
setvbuf(stdin,NULL,_IONBF,0);
setvbuf(stdout,NULL,_IONBF,0);
if (isatty(STDOUT_FILENO)) {
tcgetattr(STDOUT_FILENO,&tios);
tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
tios.c_oflag &= ~OPOST;
tcsetattr(STDOUT_FILENO,TCSANOW,&tios);
}
oldflags = fcntl(STDOUT_FILENO,F_GETFL);
oldflags |= O_NONBLOCK;
fcntl(STDOUT_FILENO,F_SETFL,oldflags);
oldflags = fcntl(sock,F_GETFL);
oldflags |= O_NONBLOCK;
fcntl(sock,F_SETFL,oldflags);
dotippipe(sock,STDIN_FILENO,STDOUT_FILENO);
exit(0);
}
doCreateTunnel(); doCreateTunnel();
if (programToLaunch) { if (programToLaunch) {
...@@ -739,6 +796,15 @@ void sslConnect() ...@@ -739,6 +796,15 @@ void sslConnect()
sslHintKey.keylen = 7; sslHintKey.keylen = 7;
if (uploadmode) if (uploadmode)
strcpy( sslHintKey.key, "UPLOAD" ); strcpy( sslHintKey.key, "UPLOAD" );
else if (optionsmode) {
strcpy(sslHintKey.key,"OPTIONS ");
if (speed > 0) {
// copy in the speed option safely
snprintf((char *)(sslHintKey.key+strlen(sslHintKey.key)),
sizeof(sslHintKey.key)-strlen(sslHintKey.key)-1,
"SPEED=%d ",speed);
}
}
else else
strncpy( sslHintKey.key, "USESSL", 7 ); strncpy( sslHintKey.key, "USESSL", 7 );
write( sock, &sslHintKey, sizeof( sslHintKey ) ); write( sock, &sslHintKey, sizeof( sslHintKey ) );
...@@ -774,7 +840,7 @@ void sslConnect() ...@@ -774,7 +840,7 @@ void sslConnect()
exit(-1); exit(-1);
} }
if (uploadmode) if (uploadmode || optionsmode)
return; return;
peer = SSL_get_peer_certificate( ssl ); peer = SSL_get_peer_certificate( ssl );
...@@ -825,6 +891,205 @@ int readSSL( void * data, int size ) ...@@ -825,6 +891,205 @@ int readSSL( void * data, int size )
#endif /* WITHSSL */ #endif /* WITHSSL */
// Just do a very simple select loop that ties the remote capture
// to a pair of fds -- probably stdin/out.
static void dotippipe(int capsock,int localin,int localout) {
fd_set rfds,rfds_master,wfds,wfds_master;
int nfds = 0;
struct timeval tv = { 1,0 };
int retval, rc;
char fromsock[1024];
char fromlocal[1024];
int sockrc = 0,localrc = 0,len = 0;
char *sockhptr,*socktptr,*localhptr,*localtptr;
sockhptr = socktptr = fromsock;
localhptr = localtptr = fromlocal;
nfds = (capsock > localin) ? capsock + 1 : localin + 1;
nfds = (nfds > localout) ? nfds : localout + 1;
FD_ZERO(&rfds_master);
FD_ZERO(&wfds_master);
FD_SET(capsock,&rfds_master);
FD_SET(localin,&rfds_master);
FD_SET(capsock,&wfds_master);
FD_SET(localout,&wfds_master);
while (1) {
memcpy(&rfds,&rfds_master,sizeof(rfds));
memcpy(&wfds,&wfds_master,sizeof(wfds));
retval = select(nfds,&rfds,NULL,NULL,NULL);
if (retval < 0) {
printf("dotippipe select: %s\n",strerror(retval));
exit(retval);
}
if (FD_ISSET(capsock,&rfds)) {
if (sockrc == sizeof(fromsock)) {
// we're full... let it buffer elsewhere
if (debug) fprintf(stderr,"sock read buf full\n");
}
else {
// simple, non-optimal ring buffering
if (socktptr > sockhptr || sockrc == 0)
len = (fromsock + sizeof(fromsock)) - socktptr;
else
len = sockhptr - socktptr;
if (len > 0) {
retval = readFunc(socktptr,len);
if (retval < 0) {
if (retval == ECONNRESET) {
if (debug) fprintf(stderr,"remote hung up\n");
FD_CLR(capsock,&rfds_master);
FD_CLR(capsock,&wfds_master);
}
else {
fprintf(stderr,"dotippipe sock read: %s\n",
strerror(retval));
exit(retval);
}
}
else if (retval > 0) {
if (debug) fprintf(stderr,"read %d sock\n",retval);
sockrc += retval;
socktptr += retval;
if (socktptr == fromsock + sizeof(fromsock)) {
// move from end to head of buffer
socktptr = fromsock;
}
}
else {
if (debug) fprintf(stderr,"sock EOF\n");
FD_CLR(capsock,&rfds_master);
}
}
}
}
if (FD_ISSET(localin,&rfds)) {
if (localrc == sizeof(fromlocal)) {
// we're full... let it buffer elsewhere
}
else {
// simple, non-optimal ring buffering
if (localtptr > localhptr || localrc == 0)
len = (fromlocal + sizeof(fromlocal)) - localtptr;
else
len = localhptr - localtptr;
if (len > 0) {
retval = read(localin,localtptr,len);
if (retval < 0) {
if (retval == ECONNRESET) {
FD_CLR(localin,&rfds_master);
FD_CLR(localin,&wfds_master);
}
else {
printf("dotippipe localin read: %s\n",
strerror(retval));
exit(retval);
}
}
else if (retval > 0) {
if (debug) fprintf(stderr,"read %d local\n",retval);
localrc += retval;
localtptr += retval;
if (localtptr == fromlocal + sizeof(fromlocal)) {
// move from end to head of buffer
localtptr = fromlocal;
}
}
else {
FD_CLR(localin,&rfds_master);
}
}
}
}
if (sockrc && FD_ISSET(localout,&wfds)) {
// write what we can
if (sockhptr > socktptr || sockrc == sizeof(fromsock))
len = (fromsock + sizeof(fromsock)) - sockhptr;
else
len = socktptr - sockhptr;
if (debug) fprintf(stderr,"trying write %d local\n",len);
retval = write(localout,sockhptr,len);
if (retval < 0) {
if (retval == EPIPE) {
FD_CLR(localout,&wfds_master);
FD_CLR(capsock,&rfds_master);
sockrc = 0;
}
else if (retval == EAGAIN) {
;
}
else {
printf("dotippipe local write: %s\n",
strerror(retval));
exit(retval);
}
}
else {
if (debug) fprintf(stderr,"wrote %d local\n",retval);
sockrc -= retval;
sockhptr += retval;
if (sockhptr == fromsock + sizeof(fromsock)) {
// move from end to head of buffer
sockhptr = fromsock;
}
}
}
if (localrc && FD_ISSET(capsock,&wfds)) {
// write what we can
if (localhptr > localtptr || localrc == sizeof(fromlocal))
len = (fromlocal + sizeof(fromlocal)) - localhptr;
else
len = localtptr - localhptr;
retval = writeFunc(localhptr,len);
if (retval < 0) {
if (retval == EPIPE) {
FD_CLR(capsock,&wfds_master);
FD_CLR(localin,&rfds_master);
localrc = 0;
}
else if (retval == EAGAIN) {
;
}
else {
printf("dotippipe sock write: %s\n",
strerror(retval));
exit(retval);
}
}
else {
if (debug) fprintf(stderr,"wrote %d sock\n",retval);
localrc -= retval;
localhptr += retval;
if (localhptr == fromlocal + sizeof(fromlocal)) {
// move from end to head of buffer
localhptr = fromlocal;
}
}
}
if ((!FD_ISSET(capsock,&rfds_master)
|| !FD_ISSET(localin,&rfds_master))
&& sockrc == 0 && localrc == 0) {
// if one of the src ends has closed, and we have nothing
// queued, we're done
if (debug) fprintf(stderr,"Exiting sanely.\n");
exit(0);
}
}
}
#ifdef TIPPTY #ifdef TIPPTY
static void pack_buffer(buffer_t *buffer, int amount) static void pack_buffer(buffer_t *buffer, int amount)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment