Commit fa15bb7b authored by Kirk Webb's avatar Kirk Webb

tbadb_proxy: Add code to remove forwarded ADB port, and some fixes.

parent e3a3a0c5
......@@ -43,7 +43,7 @@ sub cmd_loadimage($@);
sub cmd_forward($@);
sub cmd_reboot($;@);
sub GetSSHPipe();
sub chldhandler($);
sub chldhandler(;$);
sub genhandler($);
sub cleanexit($);
......@@ -186,6 +186,9 @@ sub cmd_loadimage($@) {
my $imageid = $image->imageid();
my $imagepath = $image->path();
$imagename = $image->imagename(); # strip any version
my $size = $image->size();
my $mtime;
$image->GetUpdate(\$mtime);
# Check user's access to the image.
die "tbadb::cmd_loadimage: You do not have permission to use imageid $imageid!\n"
......@@ -205,11 +208,6 @@ sub cmd_loadimage($@) {
my ($rpcin, $rpcout) = GetRPCPipeHandles($node);
die "tbadb::cmd_reboot: Failed to get valid SSH pipe filehandles!\n"
if (!$rpcin || !$rpcout);
# Get stats from the image file.
my @fstats = stat($imagepath);
my $mtime = $fstats[9];
my $size = $fstats[7];
# Have remote side check for this image in its cache.
die "tbadb::cmd_loadimage: Failed to send 'checkimage' RPC!\n"
......@@ -246,7 +244,8 @@ sub cmd_loadimage($@) {
my $SAVEUID = $UID;
$EUID = $UID = 0; # Flip to root to run!
die "tbadb::cmd_loadimage: Failed to transfer image to $rhost: $imagepath\n"
if (system("$SCP -q -B -p $imagepath $rhost:$rpath") != 0);
if (mysystem($SCP, '-q', '-B', '-p',
"$imagepath", "$rhost:$rpath/$imagename") != 0);
$EUID = $UID = $SAVEUID; # Flip back.
}
......@@ -281,13 +280,13 @@ sub cmd_loadimage($@) {
# node_id, target host, and target port.
#
sub cmd_forward($@) {
my ($node_id, $thost, $tport);
my ($node_id, $thost, $tport) = @_;
# Check and untaint arguments
die "tbadb::cmd_forward: missing arguments! (need: <node_id> <target_host> <target_port>\n"
die "tbadb::cmd_forward: missing arguments! (need: <target_host> <target_port>\n"
if (!$node_id || !$thost || !$tport);
die "tbadb::cmd_forward: malformed target host!"
if ($thost !~ /^([-\w]{$MINHLEN,$MAXHLEN})$/);
if ($thost !~ /^([-\.\w]{$MINHLEN,$MAXHLEN})$/);
$thost = $1;
die "tbadb::cmd_forward: malformed target port!"
if ($tport !~ /^(\d+)$/ || $1 < 1 || $1 > 65535);
......@@ -297,7 +296,7 @@ sub cmd_forward($@) {
my $node = Node->Lookup($node_id);
die "tbadb::cmd_forward: Invalid node name $node_id!\n"
if (!defined($node));
die("tbadb::cmd_forward: You do not have permission to reboot $node\n")
die("tbadb::cmd_forward: You do not have permission to access $node\n")
if (!$node->AccessCheck($this_user, TB_NODEACCESS_REBOOT));
# Grab the RPC pipe.
......@@ -447,8 +446,10 @@ sub cleanexit($) {
my $stime = time();
while (keys %SSHPIPES) {
chldhandler();
if (time() - $stime > $CHILD_WAIT_TMO) {
warn "tbadb: Timed out waiting for SSH pipe children to exit!\n";
warn "tbadb: Timed out waiting for SSH RPC pipes to exit!\n".
"Remaining: ". join(", ", keys %SSHPIPES) ."\n";
last;
}
sleep 1;
......@@ -458,17 +459,21 @@ sub cleanexit($) {
exit $exval;
}
sub chldhandler($) {
sub chldhandler(;$) {
local ($!, $?); # Don't let issues in the handler affect these globals.
my $pid = waitpid(-1, WNOHANG);
return if ($pid < 1);
while (my ($cs_node_id, $sshpipe) = each %SSHPIPES) {
if ($sshpipe->child() == $pid) {
print "tbadb: SSH Pipe exited for $cs_node_id\n"
if $debug;
delete $SSHPIPES{$cs_node_id};
last;
while ((my $pid = waitpid(-1, WNOHANG)) > 0) {
my $found = 0;
while (my ($cs_node_id, $sshpipe) = each %SSHPIPES) {
if ($sshpipe->child() == $pid) {
print "tbadb: SSH Pipe exited for $cs_node_id\n"
if $debug;
delete $SSHPIPES{$cs_node_id};
$found = 1;
last;
}
}
warn "tbadb: Non-pipe child process exited: $pid\n"
if (!$found && $debug);
}
}
......@@ -476,7 +481,15 @@ sub genhandler($) {
cleanexit(1);
}
sub mysystem(@) {
local $SIG{CHLD} = 'DEFAULT';
my $retcode = system(@_);
chldhandler();
return $retcode;
}
END {
warn "This is the end...\n" if $debug;
cleanexit($?) if (keys %SSHPIPES);
}
......
......@@ -43,12 +43,13 @@ sub rpc_ping($);
sub rpc_exit($);
sub send_error($$$);
sub do_lru_cleanup();
sub unpack_image($$);
sub unpack_bundle($$);
sub enter_fastboot($);
sub load_android_image($$$);
sub reboot_android($);
sub wait_for_android($);
sub setup_adb_forward($$$);
sub setup_android_forward($$$);
sub remove_android_forward($);
# Dispatch table
my %DISPATCH = (
......@@ -99,9 +100,11 @@ open(MFILE, "<$MAPFILE")
or die "tbadb_proxy: Can't open map file: $MAPFILE: $!\n";
while (my $ln = <MFILE>) {
chomp $ln;
next if (!$ln || $ln =~ /^#$/);
warn "tbadb_proxy: malformed node mapping line: $ln\n"
if ($ln !~ /^\s*([-\w]+)\s+([a-zA-Z0-9]+)\s*$/);
next if (!$ln || $ln =~ /^#.*$/);
if ($ln !~ /^\s*([-\w]+)\s+([a-zA-Z0-9]+)\s*$/) {
warn "tbadb_proxy: malformed node mapping line: $ln\n";
next;
}
$NMAP{$1} = $2;
$NMAP{$2} = $1;
}
......@@ -168,10 +171,10 @@ sub rpc_checkimage($) {
warn "tbadb_proxy::rpc_checkimage: Image check requested for $proj/$srcname\n";
# Grab the lock for this image.
my $lres = TBScriptLock("${proj}_${srcname}", $IMGLOCK_TMO,
TBSCRIPTLOCK_GLOBALWAIT, \$g_imglock);
my $lres = TBScriptLock("${proj}_${srcname}", TBSCRIPTLOCK_GLOBALWAIT,
$IMGLOCK_TMO, \$g_imglock);
LOCKSW: for ($lres) {
TBSCRIPTLOCK_IGNORE && do {
$_ == TBSCRIPTLOCK_IGNORE && do {
# Another process just did the check/transfer, so we're done.
if (!SendRPCData(*STDOUT, EncodeResult($data->{FID}, { NEED_IMG => 0 }))) {
warn "tbadb_proxy::rpc_checkimage: Error sending RPC result. Exiting!\n";
......@@ -179,7 +182,7 @@ sub rpc_checkimage($) {
}
return;
};
TBSCRIPTLOCK_OKAY && do {
$_ == TBSCRIPTLOCK_OKAY && do {
# Got the lock, just bail out of here and proceed.
last LOCKSW;
};
......@@ -192,7 +195,7 @@ sub rpc_checkimage($) {
my $projdir = "$TBADB_IMAGE_CACHE_DIR/$proj";
if (!-d $projdir) {
if (!mkdir($projdir, 0750)) {
warn "tbadb_proxy::rpc_checkimage: Failed to create project image directory: $projdir: $1\n";
warn "tbadb_proxy::rpc_checkimage: Failed to create project image directory: $projdir: $!\n";
send_error($data->{FID}, RPCERR_INTERNAL, "Internal file handling error.");
exit 1;
}
......@@ -237,7 +240,7 @@ sub rpc_checkimage($) {
# Check to see if we are over quota, and LRU prune if so.
if (!do_lru_cleanup()) {
warn "tbadb_proxy::rpc_loadimage: Error cleaning up cache. Exiting!\n";
warn "tbadb_proxy::rpc_checkimage: Error cleaning up cache. Exiting!\n";
send_error($data->{FID}, RPCERR_INTERNAL,
"Failed while cleaning up image cache.");
exit 1;
......@@ -305,26 +308,26 @@ sub rpc_loadimage($) {
: "$sysdir/pnet-cache.img";
my $boot_image = "$image_staging_dir/boot.img";
# This may block.
if (!unpack_image($fname, $image_staging_dir)) {
if (!unpack_bundle($fname, $image_staging_dir)) {
warn "tbadb_proxy::rpc_loadimage: Could not unpack image bundle!\n";
send_args($data->{FID}, RPCERR_INTERNAL, "Image unpack failed.");
send_error($data->{FID}, RPCERR_INTERNAL, "Image unpack failed.");
exit 1;
}
if (!-r $boot_image) {
warn "tbadb_proxy::rpc_loadimage: boot.img missing from bundle!\n";
send_args($data->{FID}, RPCERR_BADARGS, "boot.img missing from bundle.");
send_error($data->{FID}, RPCERR_BADARGS, "boot.img missing from bundle.");
exit 1;
}
my $system_image = "$image_staging_dir/system.img";
if (!-r $system_image) {
warn "tbadb_proxy::rpc_loadimage: system.img missing from bundle!\n";
send_args($data->{FID}, RPCERR_BADARGS, "system.img missing from bundle.");
send_error($data->{FID}, RPCERR_BADARGS, "system.img missing from bundle.");
exit 1;
}
# Step 2: Reload the partitions based on the images we setup above.
if (!-r $recovery_image || !-r $boot_image ||
!-r $userdata_image || !-r $cache_image || !-r $system_image ) {
if (!-r $recovery_image || !-r $boot_image || #!-r $userdata_image ||
!-r $cache_image || !-r $system_image ) {
warn "tbadb_proxy::rpc_loadimage: one or more images missing!\n";
send_error($data->{FID}, RPCERR_INTERNAL, "Missing images.");
exit 1;
......@@ -334,9 +337,9 @@ sub rpc_loadimage($) {
send_error($data->{FID}, RPCERR_NODE_ERR, "Node failed to load into fastboot.");
exit 1;
}
if (!(load_android_image($node_id, IMG_RECOVERY, $recovery_image) &&
if (!(#load_android_image($node_id, IMG_RECOVERY, $recovery_image) &&
load_android_image($node_id, IMG_BOOT, $boot_image) &&
load_android_image($node_id, IMG_USERDATA, $userdata_image) &&
#load_android_image($node_id, IMG_USERDATA, $userdata_image) &&
load_android_image($node_id, IMG_CACHE, $cache_image) &&
load_android_image($node_id, IMG_SYSTEM, $system_image)
)) {
......@@ -495,14 +498,14 @@ sub do_lru_cleanup() {
# Grab the global LRU lock.
# XXX: We should also skip this process if we did it recently.
my $lock_res = TBScriptLock("lrulock", $LRULOCK_TMO,
TBSCRIPTLOCK_GLOBALWAIT, \$lru_lock);
my $lock_res = TBScriptLock("lrulock", TBSCRIPTLOCK_GLOBALWAIT,
$LRULOCK_TMO, \$lru_lock);
LOCKSW: for ($lock_res) {
TBSCRIPTLOCK_IGNORE && do {
$_ == TBSCRIPTLOCK_IGNORE && do {
# Another process just did the LRU, so let's not do it again.
return 1;
};
TBSCRIPTLOCK_OKAY && do {
$_ == TBSCRIPTLOCK_OKAY && do {
# Got the lock, just bail out of here and proceed.
last LOCKSW;
};
......@@ -599,8 +602,8 @@ sub unpack_bundle($$) {
my $unpack_lock;
# Grab the unpack lock.
if (TBScriptLock("unpacklock", $UNPACKLOCK_TMO,
undef, \$unpack_lock) != TBSCRIPTLOCK_OKAY) {
if (TBScriptLock("unpacklock", undef,
$UNPACKLOCK_TMO, \$unpack_lock) != TBSCRIPTLOCK_OKAY) {
warn "tbadb_proxy::unpack_bundle: Failed to get the unpack lock!\n";
return 0;
}
......@@ -684,7 +687,7 @@ sub load_android_image($$$) {
my $serial = $NMAP{$node_id};
if (!$serial) {
warn "tbadb_proxy::reboot_android: No serial number for $node_id!\n";
warn "tbadb_proxy::load_android_image: No serial number for $node_id!\n";
return 0;
}
......@@ -745,7 +748,7 @@ sub wait_for_android($) {
my $serial = $NMAP{$node_id};
if (!$serial) {
warn "tbadb_proxy::reboot_android: No serial number for $node_id!\n";
warn "tbadb_proxy::wait_for_android: No serial number for $node_id!\n";
return 0;
}
......@@ -766,12 +769,12 @@ sub wait_for_android($) {
}
# Helper that sets up listener port for a device
sub setup_adb_forward($$$) {
sub setup_android_forward($$$) {
my ($node_id, $thost, $tport) = @_;
my $serial = $NMAP{$node_id};
if (!$serial) {
warn "tbadb_proxy::reboot_android: No serial number for $node_id!\n";
warn "tbadb_proxy::setup_android_forward: No serial number for $node_id!\n";
return 0;
}
......@@ -781,22 +784,76 @@ sub setup_adb_forward($$$) {
if ($tres =~ /has address ([\.\d]+)/) {
$thost = $1;
} else {
warn "tbadb_proxy::setup_adb_forward: could not lookup ip for host $thost\n";
warn "tbadb_proxy::setup_android_forward: could not lookup ip for host $thost\n";
return 0;
}
}
# Scour any existing forwarding setup for the device
if (remove_android_forward($node_id)) {
warn "tbadb_proxy::setup_android_forward: could not remove old forwarding setup for $node_id!\n";
return 0;
}
# Setup iptables rule to only allow connections from target
if (system("$IPTABLES -A INPUT ! -s $thost -p tcp --dport $tport -j DROP >/dev/null 2>&1") != 0) {
warn "tbadb_proxy::setup_adb_forward: could not setup iptables rule to limit connections for $node_id via port $tport to target host IP $thost\n";
if (system("$IPTABLES -A INPUT ! -s $thost -p tcp --dport $tport -m comment --comment '$serial' -j DROP >/dev/null 2>&1") != 0) {
warn "tbadb_proxy::setup_android_forward: could not setup iptables rule to limit connections for $node_id via port $tport to target host IP $thost\n";
return 0;
}
# Forward!
if (system("ADB -s $serial forward tcp:$tport tcp:5555") != 0) {
warn "tbadb_proxy::setup_adb_forward: could not forward adbd port on node_id to local port $tport!\n";
if (system("$ADB -s $serial forward tcp:$tport tcp:5555 >/dev/null 2>&1") != 0) {
warn "tbadb_proxy::setup_android_forward: could not forward adbd port on node_id to local port $tport!\n";
return 0;
}
return 1;
}
sub remove_android_forward($) {
my ($node_id) = @_;
my $serial = $NMAP{$node_id};
if (!$serial) {
warn "tbadb_proxy::remove_android_forward: No serial number for $node_id!\n";
return 0;
}
# Clear the adb forwarding.
my $adb_fwd_list = `$ADB forward --list 2>&1`;
if ($? != 0) {
warn "tbadb_proxy::remove_android_forward: unable to list adb forwarded ports!\n";
return 0;
}
my $portnum = 0;
foreach my $fwd (split(/\n/, $adb_fwd_list)) {
if ($fwd =~ /^$serial\s+tcp:(\d+)\s+/i) {
$portnum = $1;
last;
}
}
if ($portnum && system("$ADB -s $serial forward --remove tcp:$portnum >/dev/null 2>&1") != 0) {
warn "tbadb_proxy::remove_android_forward: unable to remove adb forward for $node_id!\n";
return 0;
}
return 1
# Clear the iptables rule.
my $ipt_rules = `$IPTABLES -L INPUT --line-numbers 2>&1`;
if ($? != 0) {
warn "tbadb_proxy::remove_android_forward: unable to list iptables rules!\n";
return 0;
}
my $rulenum = 0;
foreach my $rule (split(/\n/, $ipt_rules)) {
if ($rule =~ /^(\d+)\s+.+\/\* $serial \*\//i) {
$rulenum = $1;
last;
}
}
if ($rulenum && system("$IPTABLES -D INPUT $rulenum >/dev/null 2>&1") != 0) {
warn "tbadb_proxy::remove_android_forward: unable to clear iptables rule for $node_id!\n";
return 0;
}
}
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