about summary refs log tree commit homepage
path: root/lib/PublicInbox/NetNNTPSocks.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/NetNNTPSocks.pm')
-rw-r--r--lib/PublicInbox/NetNNTPSocks.pm36
1 files changed, 36 insertions, 0 deletions
diff --git a/lib/PublicInbox/NetNNTPSocks.pm b/lib/PublicInbox/NetNNTPSocks.pm
new file mode 100644
index 00000000..d27efba1
--- /dev/null
+++ b/lib/PublicInbox/NetNNTPSocks.pm
@@ -0,0 +1,36 @@
+# Copyright (C) all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# wrap Net::NNTP client with SOCKS support.  Convoluted, but AFAIK this
+# is the only way to get SOCKS working with Net::NNTP w/o LD_PRELOAD.
+package PublicInbox::NetNNTPSocks;
+use v5.12;
+use Net::NNTP;
+our %OPT; # used to pass options between ->new_socks and our ->new
+our @ISA = qw(IO::Socket::Socks);
+
+# use this instead of Net::NNTP->new if using Proxy*
+sub new_socks {
+        my (undef, %opt) = @_;
+        require IO::Socket::Socks;
+        local @Net::NNTP::ISA = (qw(Net::Cmd), __PACKAGE__);
+        local %OPT = map {;
+                defined($opt{$_}) ? ($_ => $opt{$_}) : ()
+        } qw(ProxyAddr ProxyPort SocksVersion SocksDebug SocksResolve);
+        no warnings 'uninitialized'; # needed for $SOCKS_ERROR
+        my $ret = Net::NNTP->new(%opt); # calls PublicInbox::NetNNTPSocks::new
+        return $ret if $ret || $!{EINTR};
+        $ret // die "errors: \$!=$! SOCKS=",
+                                eval('$IO::Socket::Socks::SOCKS_ERROR // ""'),
+                                ', SSL=',
+                                (eval('IO::Socket::SSL->errstr')  // ''), "\n";
+}
+
+# called by Net::NNTP->new
+sub new {
+        my ($self, %opt) = @_;
+        @OPT{qw(ConnectAddr ConnectPort)} = @opt{qw(PeerAddr PeerPort)};
+        $self->SUPER::new(%OPT);
+}
+
+1;