File: dual.pm

package info (click to toggle)
libnet-proxy-perl 0.12-5
  • links: PTS
  • area: main
  • in suites: squeeze, wheezy
  • size: 304 kB
  • ctags: 66
  • sloc: perl: 777; sh: 84; makefile: 44
file content (153 lines) | stat: -rw-r--r-- 4,047 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package Net::Proxy::Connector::dual;
use strict;
use warnings;
use Carp;
use Scalar::Util qw( reftype );

use Net::Proxy::Connector;
our @ISA = qw( Net::Proxy::Connector );

sub init {
    my ($self) = @_;

    # check connectors
    for my $conn (qw( client_first server_first )) {
        croak "'$conn' connector required" if !exists $self->{$conn};

        croak "'$conn' connector must be a HASHREF"
            if ref $self->{$conn} ne 'HASH';

        croak "'type' key required for '$conn' connector"
            if !exists $self->{$conn}{type};

        croak "'hook' key is not a CODE reference for '$conn' connector"
            if $self->{$conn}{hook}
            && reftype( $self->{$conn}{hook} ) ne 'CODE';

        # load the class
        my $class = 'Net::Proxy::Connector::' . $self->{$conn}{type};
        eval "require $class";
        croak "Couldn't load $class for '$conn' connector: $@" if $@;

        # create and store the Connector object
        $self->{$conn} = $class->new( $self->{$conn} );
        $self->{$conn}->set_proxy($self->{_proxy_});
    }

    # other parameters
    croak q{Parameter 'port' is required} if !exists $self->{port};
    $self->{timeout} ||= 1;              # by default wait for one second
    $self->{host}    ||= 'localhost';    # by default listen on localhost

    return;
}

# IN
*listen = \&Net::Proxy::Connector::raw_listen;

sub accept_from {
    my ( $self, $listen ) = @_;
    my $sock = $self->raw_accept_from($listen);

    # find out who speaks first
    # if the client talks first, it's a client_first connection
    my $waiter = IO::Select->new($sock);
    my @waited = $waiter->can_read( $self->{timeout} );
    my $type   = @waited ? 'client_first' : 'server_first';

    # do the outgoing connection
    $self->{$type}->_out_connect_from($sock);

    return $sock;
}

# OUT

# READ
*read_from = \&Net::Proxy::Connector::raw_read_from;

# WRITE
*write_to = \&Net::Proxy::Connector::raw_write_to;

1;

__END__

=head1 NAME

Net::Proxy::Connector::dual - Y-shaped Net::Proxy connector

=head1 DESCRIPTION

C<Net::Proxy::Connecter::dual> is a C<Net::Proxy::Connector>
that can forward the connection to two distinct services,
based on the client connection, before any data is exchanged.

=head1 CONNECTOR OPTIONS

This connector can only work as an C<in> connector.

The C<server_first> and C<client_first> options are required: they
are hashrefs containing the options necessary to create two C<out>
C<Net::Proxy::Connector> objects that will be used to connect to
the requested service.

The C<Net::Proxy::Connector::dual> object decides between the two
services by waiting during a short timeout. If the client sends
some data directly, then it is connected via the C<client_first>
connector. Otherwise, at the end of the timeout, it is connected
via the C<server_first> connector.

=over 4

=item * host

The hostname on which the connector will listen for client connections.
Default is C<localhost>.

=item * port

The port on which the connector will listen for client connections.

=item * server_first

Typically an C<out> connector to a SSH server or any service that sends
a banner line.

=item * client_first

Typically an C<out> connectrot to a web server or SSL server.

=item * timeout

The timeout in seconds (can be decimal) to make a decision.
Default is 1 second.

=back

=head1 AUTHOR

Philippe 'BooK' Bruhat, C<< <book@cpan.org> >>.

=head1 ACKNOWLEDGMENTS

This module is based on a script named B<sslh>, which I wrote with
Frdric Pl C<< <sslh@wattoo.org> >> (who had the original insight
about the fact that not all servers speak first on the wire).

Frdric wrote a C program, while I wrote a Perl script (based on my
experience with B<connect-tunnel>).

Now that C<Net::Proxy> is available, I've ported the Perl script to use it.

=head1 COPYRIGHT

Copyright 2006 Philippe 'BooK' Bruhat, All Rights Reserved.

=head1 LICENSE

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut