summaryrefslogtreecommitdiffstats
path: root/x11vnc/misc/inet6to4
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/misc/inet6to4')
-rwxr-xr-xx11vnc/misc/inet6to4400
1 files changed, 400 insertions, 0 deletions
diff --git a/x11vnc/misc/inet6to4 b/x11vnc/misc/inet6to4
new file mode 100755
index 0000000..b5c2fd1
--- /dev/null
+++ b/x11vnc/misc/inet6to4
@@ -0,0 +1,400 @@
+#!/usr/bin/perl
+#
+# inet6to4: Act as an ipv6-to-ipv4 relay for tcp applications that
+# do not support ipv6.
+#
+# Usage: inet6to4 <ipv6-listen-port> <ipv4-host:port>
+# inet6to4 -r <ipv4-listen-port> <ipv6-host:port>
+#
+# Examples: inet6to4 5900 localhost:5900
+# inet6to4 8080 web1:80
+# inet6to4 -r 5900 fe80::217:f2ff:fee6:6f5a%eth0:5900
+#
+# The -r option reverses the direction of translation (e.g. for ipv4
+# clients that need to connect to ipv6 servers.) Reversing is the default
+# if this script is named 'inet4to6' (e.g. by a symlink.)
+#
+# Use Ctrl-C to stop this program.
+#
+# You can also set env. vars INET6TO4_LOOP=1 or INET6TO4_LOOP=BG
+# to have an outer loop restarting this program (BG means do that
+# in the background), and INET6TO4_LOGFILE for a log file.
+# Also set INET6TO4_VERBOSE to verbosity level and INET6TO4_WAITTIME
+# and INET6TO4_PIDFILE (see below.)
+#
+
+#-------------------------------------------------------------------------
+# Copyright (c) 2010 by Karl J. Runge <runge@karlrunge.com>
+#
+# inet6to4 is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or (at
+# your option) any later version.
+#
+# inet6to4 is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with inet6to4; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+# or see <http://www.gnu.org/licenses/>.
+#-------------------------------------------------------------------------
+
+# Set up logging:
+#
+if (exists $ENV{INET6TO4_LOGFILE}) {
+ close STDOUT;
+ if (!open(STDOUT, ">>$ENV{INET6TO4_LOGFILE}")) {
+ die "inet6to4: $ENV{INET6TO4_LOGFILE} $!\n";
+ }
+ close STDERR;
+ open(STDERR, ">&STDOUT");
+}
+select(STDERR); $| = 1;
+select(STDOUT); $| = 1;
+
+# interrupt handler:
+#
+my $looppid = '';
+my $pidfile = '';
+my $listen_sock = ''; # declared here for get_out()
+#
+sub get_out {
+ print STDERR "$_[0]:\t$$ looppid=$looppid\n";
+ close $listen_sock if $listen_sock;
+ if ($looppid) {
+ kill 'TERM', $looppid;
+ fsleep(0.2);
+ }
+ unlink $pidfile if $pidfile;
+ exit 0;
+}
+$SIG{INT} = \&get_out;
+$SIG{TERM} = \&get_out;
+
+# pidfile:
+#
+sub open_pidfile {
+ if (exists $ENV{INET6TO4_PIDFILE}) {
+ my $pf = $ENV{INET6TO4_PIDFILE};
+ if (open(PID, ">$pf")) {
+ print PID "$$\n";
+ close PID;
+ $pidfile = $pf;
+ } else {
+ print STDERR "could not open pidfile: $pf - $! - continuing...\n";
+ }
+ delete $ENV{INET6TO4_PIDFILE};
+ }
+}
+
+####################################################################
+# Set INET6TO4_LOOP=1 to have this script create an outer loop
+# restarting itself if it ever exits. Set INET6TO4_LOOP=BG to
+# do this in the background as a daemon.
+
+if (exists $ENV{INET6TO4_LOOP}) {
+ my $csl = $ENV{INET6TO4_LOOP};
+ if ($csl ne 'BG' && $csl ne '1') {
+ die "inet6to4: invalid INET6TO4_LOOP.\n";
+ }
+ if ($csl eq 'BG') {
+ # go into bg as "daemon":
+ setpgrp(0, 0);
+ my $pid = fork();
+ if (! defined $pid) {
+ die "inet6to4: $!\n";
+ } elsif ($pid) {
+ wait;
+ exit 0;
+ }
+ if (fork) {
+ exit 0;
+ }
+ setpgrp(0, 0);
+ close STDIN;
+ if (! $ENV{INET6TO4_LOGFILE}) {
+ close STDOUT;
+ close STDERR;
+ }
+ }
+ delete $ENV{INET6TO4_LOOP};
+
+ if (exists $ENV{INET6TO4_PIDFILE}) {
+ open_pidfile();
+ }
+
+ print STDERR "inet6to4: starting service at ", scalar(localtime), " master-pid=$$\n";
+ while (1) {
+ $looppid = fork;
+ if (! defined $looppid) {
+ sleep 10;
+ } elsif ($looppid) {
+ wait;
+ } else {
+ exec $0, @ARGV;
+ exit 1;
+ }
+ print STDERR "inet6to4: re-starting service at ", scalar(localtime), " master-pid=$$\n";
+ sleep 1;
+ }
+ exit 0;
+}
+if (exists $ENV{INET6TO4_PIDFILE}) {
+ open_pidfile();
+}
+
+use IO::Socket::INET6;
+use strict;
+use warnings;
+
+# some settings:
+#
+my $verbose = 1; # set to 0 for no messages, 2 for more.
+my $killpid = 1; # does kill(2) at end of connection.
+my $waittime = 0.25; # time to wait between connections.
+my $reverse = 0; # -r switch (or file named inet4to6)
+
+if (exists $ENV{INET6TO4_VERBOSE}) {
+ $verbose = $ENV{INET6TO4_VERBOSE};
+}
+if (exists $ENV{INET6TO4_WAITTIME}) {
+ $waittime = $ENV{INET6TO4_WAITTIME};
+}
+
+# process command line args:
+
+if (! @ARGV || $ARGV[0] =~ '^-+h') { # -help
+ open(ME, "<$0");
+ while (<ME>) {
+ last unless /^#/;
+ next if /usr.bin.perl/;
+ $_ =~ s/# ?//;
+ print;
+ }
+ exit;
+}
+
+if ($ARGV[0] eq '-r') { # -r
+ shift;
+ $reverse = 1;
+} elsif ($0 =~ /inet4to6$/) {
+ $reverse = 1;
+}
+
+my $listen_port = shift; # ipv6-listen-port
+my $connect_to = shift; # ipv4-host:port
+
+die "no listen port or connect-to-host:port\n" if ! $listen_port || ! $connect_to;
+
+# connect to host:
+#
+my $host = '';
+my $port = '';
+if ($connect_to =~ /^(.*):(\d+)$/) {
+ $host = $1;
+ $port = $2;
+}
+die "invalid connect-to-host:port\n" if ! $host || ! $port;
+
+setpgrp(0, 0);
+
+# create listening socket:
+#
+if (!$reverse) {
+ $listen_sock = IO::Socket::INET6->new(
+ Listen => 10,
+ LocalPort => $listen_port,
+ Domain => AF_INET6,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+} else {
+ $listen_sock = IO::Socket::INET->new(
+ Listen => 10,
+ LocalPort => $listen_port,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+}
+if (! $listen_sock) {
+ die "inet6to4: $!\n";
+}
+
+# for use by the xfer helper processes' interrupt handlers:
+#
+my $current_fh1 = '';
+my $current_fh2 = '';
+
+# connection counter:
+#
+my $conn = 0;
+
+# loop forever waiting for connections:
+#
+while (1) {
+ $conn++;
+ print STDERR "listening for connection: $conn\n" if $verbose;
+ my ($client, $ip) = $listen_sock->accept();
+
+ if ($client && !$reverse && $port == $listen_port) {
+ # This happens on Darwin 'tcp46'
+ if ($client->peerhost() =~ /^::ffff:/) {
+ print STDERR "closing client we think is actually us: ",
+ $client->peerhost(), "\n";
+ close $client;
+ $client = undef;
+ }
+ }
+ if (! $client) {
+ # to throttle runaways
+ fsleep(2 * $waittime);
+ next;
+ }
+ print STDERR "conn: $conn -- ", $client->peerhost(), " at ", scalar(localtime), "\n" if $verbose;
+
+ # spawn helper:
+ #
+ my $pid = fork();
+ if (! defined $pid) {
+ die "inet6to4: $!\n";
+ } elsif ($pid) {
+ wait;
+ # to throttle runaways
+ fsleep($waittime);
+ next;
+ } else {
+ # this is to avoid zombies:
+ close $listen_sock;
+ if (fork) {
+ exit 0;
+ }
+ setpgrp(0, 0);
+ handle_conn($client);
+ }
+}
+
+exit 0;
+
+sub handle_conn {
+ my $client = shift;
+
+ my $start = time();
+
+ print STDERR "connecting to: $host:$port\n" if $verbose;
+
+ my $sock = '';
+ if (!$reverse) {
+ $sock = IO::Socket::INET->new(
+ PeerAddr => $host,
+ PeerPort => $port,
+ Proto => "tcp"
+ );
+ } else {
+ $sock = IO::Socket::INET6->new(
+ PeerAddr => $host,
+ PeerPort => $port,
+ Domain => AF_INET6,
+ Proto => "tcp"
+ );
+ }
+
+ if (! $sock) {
+ close $client;
+ die "inet6to4: $!\n";
+ }
+
+ $current_fh1 = $client;
+ $current_fh2 = $sock;
+
+ # interrupt handler:
+ #
+ $SIG{TERM} = sub {print STDERR "got sigterm\[$$]\n" if $verbose; close $current_fh1; close $current_fh2; exit 0};
+
+ # spawn another helper and transfer the data:
+ #
+ my $parent = $$;
+ if (my $child = fork()) {
+ xfer($sock, $client, 'S->C');
+ if ($killpid) {
+ fsleep(0.5);
+ kill 'TERM', $child;
+ }
+ } else {
+ xfer($client, $sock, 'C->S');
+ if ($killpid) {
+ fsleep(0.75);
+ kill 'TERM', $parent;
+ }
+ }
+
+ # done.
+ #
+ if ($verbose > 1) {
+ my $dt = time() - $start;
+ print STDERR "dt\[$$]: $dt\n";
+ }
+ exit 0;
+}
+
+# transfers data in one direction:
+#
+sub xfer {
+ my($in, $out, $lab) = @_;
+ my ($RIN, $WIN, $EIN, $ROUT);
+ $RIN = $WIN = $EIN = "";
+ $ROUT = "";
+ vec($RIN, fileno($in), 1) = 1;
+ vec($WIN, fileno($in), 1) = 1;
+ $EIN = $RIN | $WIN;
+ my $buf;
+
+ while (1) {
+ my $nf = 0;
+ while (! $nf) {
+ $nf = select($ROUT=$RIN, undef, undef, undef);
+ }
+ my $len = sysread($in, $buf, 8192);
+ if (! defined($len)) {
+ next if $! =~ /^Interrupted/;
+ print STDERR "inet6to4\[$lab/$conn/$$]: $!\n";
+ last;
+ } elsif ($len == 0) {
+ print STDERR "inet6to4\[$lab/$conn/$$]: "
+ . "Input is EOF.\n";
+ last;
+ }
+
+ if ($verbose > 4) {
+ # verbose debugging of data:
+ syswrite(STDERR , "\n$lab: ", 6);
+ syswrite(STDERR , $buf, $len);
+ }
+
+ my $offset = 0;
+ my $quit = 0;
+ while ($len) {
+ my $written = syswrite($out, $buf, $len, $offset);
+ if (! defined $written) {
+ print STDERR "inet6to4\[$lab/$conn/$$]: "
+ . "Output is EOF. $!\n";
+ $quit = 1;
+ last;
+ }
+ $len -= $written;
+ $offset += $written;
+ }
+ last if $quit;
+ }
+ close($in);
+ close($out);
+}
+
+# sleep a fraction of a second:
+#
+sub fsleep {
+ my ($time) = @_;
+ select(undef, undef, undef, $time) if $time;
+}