File Coverage

blib/lib/Protocol/SOCKS/Server.pm
Criterion Covered Total %
statement 39 56 69.6
branch 8 18 44.4
condition 4 14 28.5
subroutine 9 13 69.2
pod 7 7 100.0
total 67 108 62.0


line stmt bran cond sub pod time code
1             package Protocol::SOCKS::Server;
2             $Protocol::SOCKS::Server::VERSION = '0.003';
3 1     1   30735 use strict;
  1         2  
  1         35  
4 1     1   6 use warnings;
  1         1  
  1         30  
5              
6 1     1   1495 use parent qw(Protocol::SOCKS);
  1         328  
  1         5  
7              
8             =head1 NAME
9              
10             Protocol::SOCKS::Server - server support for SOCKS protocol
11              
12             =head1 VERSION
13              
14             Version 0.003
15              
16             =head1 DESCRIPTION
17              
18             This provides an abstraction for dealing with the server side of the SOCKS protocol.
19              
20             =cut
21              
22 1     1   50 use Future;
  1         2  
  1         26  
23 1     1   7 use Socket qw(inet_pton inet_ntop inet_ntoa AF_INET AF_INET6);
  1         1  
  1         64  
24              
25 1     1   6 use Protocol::SOCKS::Constants qw(:all);
  1         1  
  1         771  
26              
27             =head1 METHODS
28              
29             =cut
30              
31             =head2 completion
32              
33             Returns the completion future.
34              
35             =cut
36              
37 0   0 0 1 0 sub completion { $_[0]->{completion} ||= $_[0]->new_future }
38              
39             =head2 auth
40              
41             Returns the auth Future.
42              
43             =cut
44              
45 0   0 0 1 0 sub auth { $_[0]->{auth} ||= $_[0]->new_future }
46              
47             =head2 auth_methods
48              
49             Returns the list of auth methods we can handle.
50              
51             =cut
52              
53             sub auth_methods {
54 3     3 1 4 my $self = shift;
55 3   100     4 @{ $self->{auth_methods} ||= [ AUTH_NONE ] }
  3         29  
56             }
57              
58             =head2 init_packet
59              
60             Initial client packet.
61              
62             =cut
63              
64             sub init_packet {
65 0     0 1 0 my $self = shift;
66 0         0 my @methods = (0);
67 0         0 pack 'C1C/C*', $self->version, $self->auth_methods;
68             }
69              
70             =head2 on_read
71              
72             Handler for reading data from the client.
73              
74             =cut
75              
76             sub on_read {
77 2     2 1 1782 my ($self, $buf) = @_;
78 2 50       7 if(!$self->init->is_ready) {
79 2 50       26 return if length($$buf) < 3;
80 2         12 my (undef, $method_count) = unpack 'C1C', substr $$buf, 0, 2;
81 2 50       8 return unless length($$buf) >= 2 + $method_count;
82              
83 2         8 my ($version, $methods) = unpack 'C1C/C*', substr $$buf, 0, 2 + $method_count, '';
84 2 50       9 die "Invalid version" unless $version == $self->version;
85 2         3 my $auth_method;
86             METHOD:
87 2         11 for my $method (split //, $methods) {
88 3 100       9 next METHOD unless grep $method == $_, $self->auth_methods;
89 1         3 $auth_method = $method;
90 1         3 last METHOD;
91             }
92 2 100       6 unless(defined $auth_method) {
93 1         5 $self->write(
94             pack 'C1C1',
95             $self->version,
96             AUTH_FAIL,
97             );
98 1         375 return $self->init->fail(auth => 'no suitable methods');
99             }
100 1         10 $self->init->done($version => $auth_method);
101 1         53 return $self->write(
102             pack 'C1C1',
103             $self->version,
104             $auth_method
105             )
106             }
107              
108 0 0       0 return unless my $details = $self->parse_request($buf);
109              
110 0         0 my $f = shift @{$self->{awaiting_reply}};
  0         0  
111 0         0 $f->done($details);
112             }
113              
114             =head2 init
115              
116             Resolves with version and auth method when connection
117             has been established
118              
119             =cut
120              
121 6   66 6 1 1321 sub init { $_[0]->{init} ||= $_[0]->new_future }
122              
123             =head2 parse_request
124              
125             Parse a client request.
126              
127             =cut
128              
129             sub parse_request {
130 0     0 1   my ($self, $buffref) = @_;
131 0 0         return unless length $$buffref >= 6;
132 0           my ($version, $cmd, $reserved, $atype) = unpack 'C1C1C1C1', substr $$buffref, 0, 4;
133 0 0 0       die "unknown command $cmd" unless $cmd > 0 && $cmd < 4;
134              
135 0           substr $$buffref, 0, 3, '';
136 0           my $addr = $self->extract_address($buffref);
137 0           my $port = unpack 'n1', substr $$buffref, 0, 2, '';
138 0           warn "Addr $addr, port $port\n";
139             }
140              
141             1;
142              
143             __END__