line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
2
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
41
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package App::HTTP_Proxy_IMP::Relay; |
5
|
|
|
|
|
|
|
use fields ( |
6
|
1
|
|
|
|
|
5
|
'fds', # file descriptors |
7
|
|
|
|
|
|
|
'conn', # App::HTTP_Proxy_IMP::HTTPConn object |
8
|
|
|
|
|
|
|
'acct', # collect accounting |
9
|
1
|
|
|
1
|
|
5
|
); |
|
1
|
|
|
|
|
3
|
|
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
69
|
use App::HTTP_Proxy_IMP::Debug; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
83
|
|
12
|
1
|
|
|
1
|
|
6
|
use Scalar::Util 'weaken'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
40
|
|
13
|
1
|
|
|
1
|
|
844
|
use IO::Socket::SSL; |
|
1
|
|
|
|
|
78134
|
|
|
1
|
|
|
|
|
7
|
|
14
|
1
|
|
|
1
|
|
1234
|
use AnyEvent; |
|
1
|
|
|
|
|
5487
|
|
|
1
|
|
|
|
|
37
|
|
15
|
1
|
|
|
1
|
|
7
|
use POSIX '_exit'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# set if the child should destroy itself after last connection closed |
18
|
|
|
|
|
|
|
my $exit_if_no_relays; |
19
|
0
|
|
|
0
|
0
|
|
sub exit_if_no_relays { $exit_if_no_relays = pop; } |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# active relay, inserted in new, removed in $idlet timer |
22
|
|
|
|
|
|
|
my @relays; |
23
|
0
|
|
|
0
|
0
|
|
sub relays { return grep { $_ } @relays } |
|
0
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# creates new relay and puts it into @relays as weak reference |
26
|
|
|
|
|
|
|
sub new { |
27
|
0
|
|
|
0
|
0
|
|
my ($class,$cfd,$upstream,$conn) = @_; |
28
|
0
|
|
|
|
|
|
my $self = fields::new($class); |
29
|
0
|
|
|
|
|
|
debug("create relay $self"); |
30
|
|
|
|
|
|
|
|
31
|
0
|
0
|
0
|
|
|
|
if ( $upstream && ! ref($upstream)) { |
32
|
0
|
0
|
|
|
|
|
$upstream =~m{\A(?:\[([a-f\d:.]+)\]|([\da-z_\-.]+)):(\d+)\Z} or |
33
|
|
|
|
|
|
|
die "invalid upstream specification: $upstream"; |
34
|
0
|
|
0
|
|
|
|
$upstream = [ $1||$2, $3 ]; |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
my $cobj = $conn->new_connection({ |
38
|
|
|
|
|
|
|
daddr => $cfd->sockhost, |
39
|
|
|
|
|
|
|
dport => $cfd->sockport, |
40
|
|
|
|
|
|
|
saddr => $cfd->peerhost, |
41
|
|
|
|
|
|
|
sport => $cfd->peerport, |
42
|
|
|
|
|
|
|
upstream => $upstream, |
43
|
|
|
|
|
|
|
},$self); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
#debug("create connection $cobj"); |
46
|
0
|
|
|
|
|
|
$self->{conn} = $cobj; |
47
|
0
|
|
|
|
|
|
my $cfo = $self->{fds}[0] = App::HTTP_Proxy_IMP::Relay::FD->new(0,$cfd,$self,1); |
48
|
0
|
|
|
|
|
|
$cfo->mask( r => 1 ); # enable read |
49
|
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
push @relays, $self; |
51
|
0
|
|
|
|
|
|
weaken($relays[-1]); |
52
|
|
|
|
|
|
|
|
53
|
0
|
|
|
|
|
|
return $self; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub DESTROY { |
57
|
0
|
|
|
0
|
|
|
my $self = shift; |
58
|
0
|
|
|
|
|
|
$self->account('destroy'); |
59
|
0
|
|
|
|
|
|
$self->xdebug("destroy relay $self"); |
60
|
0
|
0
|
0
|
|
|
|
if ( $exit_if_no_relays && ! $self->relays ) { |
61
|
|
|
|
|
|
|
# der letzte macht das Licht aus |
62
|
0
|
|
|
|
|
|
debug("exit child $$ after last connection"); |
63
|
0
|
|
|
|
|
|
_exit(0) |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub acctinfo { |
68
|
0
|
|
|
0
|
0
|
|
my ($self,$acct) = @_; |
69
|
0
|
|
|
|
|
|
$self->{acct} = $acct; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
sub account { |
72
|
0
|
|
|
0
|
0
|
|
my ($self,$what,%args) = @_; |
73
|
0
|
|
|
|
|
|
my $acct = $self->{acct}; |
74
|
0
|
0
|
|
|
|
|
$acct = $acct ? { %$acct,%args } : \%args if %args; |
|
|
0
|
|
|
|
|
|
75
|
0
|
0
|
|
|
|
|
$acct or return; |
76
|
0
|
|
|
|
|
|
$self->{acct} = undef; |
77
|
0
|
0
|
|
|
|
|
if ( my $t = delete $acct->{start} ) { |
78
|
0
|
|
|
|
|
|
$acct->{duration} = AnyEvent->now - $t; |
79
|
|
|
|
|
|
|
} |
80
|
0
|
|
|
|
|
|
my @msg; |
81
|
0
|
|
|
|
|
|
for( sort keys %$acct ) { |
82
|
0
|
|
|
|
|
|
my $t; |
83
|
0
|
|
|
|
|
|
my $v = $acct->{$_}; |
84
|
0
|
0
|
|
|
|
|
if ( ! defined $v ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
next; |
86
|
|
|
|
|
|
|
} elsif ( ref($v) eq 'ARRAY') { |
87
|
0
|
|
|
|
|
|
$t = "$_=[".join(',',map { _quote($_) } @$v)."]"; |
|
0
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
} elsif ( defined $v ) { |
89
|
0
|
|
|
|
|
|
$t = "$_="._quote($v); |
90
|
|
|
|
|
|
|
} |
91
|
0
|
|
|
|
|
|
push @msg,$t; |
92
|
|
|
|
|
|
|
} |
93
|
0
|
|
|
|
|
|
print STDERR "ACCT @msg\n"; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub _quote { |
97
|
0
|
|
|
0
|
|
|
my $text = shift; |
98
|
0
|
|
|
|
|
|
$text =~s{([\000-\037\\"\377-\777])}{ sprintf("\\%03o",ord($1)) }eg; |
|
0
|
|
|
|
|
|
|
99
|
0
|
0
|
|
|
|
|
return $text =~m{ } ? qq["$text"]:$text; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub xdebug { |
103
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
104
|
0
|
|
|
|
|
|
my $conn = $self->{conn}; |
105
|
0
|
0
|
|
|
|
|
if ( my $xdebug = UNIVERSAL::can($conn,'xdebug') ) { |
106
|
0
|
|
|
|
|
|
unshift @_,$conn; |
107
|
0
|
|
|
|
|
|
goto &$xdebug; |
108
|
|
|
|
|
|
|
} else { |
109
|
0
|
|
|
|
|
|
goto &debug; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# non-fatal problem |
115
|
|
|
|
|
|
|
sub error { |
116
|
0
|
|
|
0
|
0
|
|
my ($self,$reason) = @_; |
117
|
0
|
|
0
|
|
|
|
warn "[error] ".( $self->{conn} && $self->{conn}->id || 'noid')." $reason\n"; |
118
|
0
|
|
|
|
|
|
return 0; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# fatal problem - close connection |
122
|
|
|
|
|
|
|
sub fatal { |
123
|
0
|
|
|
0
|
0
|
|
my ($self,$reason) = @_; |
124
|
0
|
|
0
|
|
|
|
warn "[fatal] ".( $self->{conn} && $self->{conn}->id || 'noid')." $reason\n"; |
125
|
0
|
|
|
|
|
|
$self->close; |
126
|
0
|
|
|
|
|
|
return 0; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub connect:method { |
130
|
0
|
|
|
0
|
0
|
|
my ($self,$to,$host,$port,$callback,$reconnect) = @_; |
131
|
0
|
|
0
|
|
|
|
my $fo = $self->{fds}[$to] ||= App::HTTP_Proxy_IMP::Relay::FD->new($to,undef,$self); |
132
|
0
|
|
|
|
|
|
$fo->connect($host,$port,$callback,$reconnect); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# masks/unmasks fd for dir, rw = r|w |
136
|
|
|
|
|
|
|
sub mask { |
137
|
0
|
|
|
0
|
0
|
|
my ($self,$dir,$rw,$v) = @_; |
138
|
0
|
0
|
|
|
|
|
my $fd = $self->{fds}[$dir] or do { |
139
|
0
|
|
|
|
|
|
warn "fd dir=$dir does not exists\n"; |
140
|
0
|
|
|
|
|
|
return; |
141
|
|
|
|
|
|
|
}; |
142
|
0
|
|
|
|
|
|
$fd->mask($rw,$v); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub fd { |
146
|
0
|
|
|
0
|
0
|
|
my ($self,$dir) = @_; |
147
|
0
|
|
|
|
|
|
return $self->{fds}[$dir]; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# send some data via fd dir |
151
|
|
|
|
|
|
|
sub forward { |
152
|
0
|
|
|
0
|
0
|
|
my ($self,$from,$to,$data) = @_; |
153
|
0
|
0
|
|
|
|
|
my $fo = $self->{fds}[$to] or return |
154
|
|
|
|
|
|
|
$self->fatal("cannot write to $to - no such fo"); |
155
|
0
|
|
|
|
|
|
$self->xdebug("$from>$to - forward %d bytes",length($data)); |
156
|
0
|
|
|
|
|
|
$fo->write($data,$from); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# ssl interception, e.g. upgrade both client and server to SSL sockets, |
160
|
|
|
|
|
|
|
# where I can read/write unencrypted data |
161
|
|
|
|
|
|
|
sub sslify { |
162
|
0
|
|
|
0
|
0
|
|
my ($self,$from,$to,$hostname,$callback) = @_; |
163
|
0
|
0
|
|
|
|
|
my $conn = $self->{conn} or return; |
164
|
0
|
0
|
|
|
|
|
my $mitm = $conn->{mitm} or return; # no MITM needed |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# destroy the current connection object and create a new obne |
167
|
0
|
|
|
|
|
|
$conn = $self->{conn} = $conn->clone; |
168
|
0
|
|
|
|
|
|
$conn->{intunnel} = 1; |
169
|
|
|
|
|
|
|
|
170
|
0
|
0
|
|
|
|
|
my $sfo = $self->{fds}[$from] or return |
171
|
|
|
|
|
|
|
$self->fatal("cannot startssl $from - no such fo"); |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# stop handling all data |
174
|
0
|
|
|
|
|
|
$self->mask($to,r=>0); |
175
|
0
|
|
|
|
|
|
$self->mask($from,r=>0); |
176
|
0
|
|
|
|
|
|
weaken( my $wself = $self ); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
my %sslargs = ( |
179
|
|
|
|
|
|
|
SSL_verifycn_name => $hostname, |
180
|
|
|
|
|
|
|
SSL_verifycn_schema => 'http', |
181
|
|
|
|
|
|
|
SSL_hostname => $hostname, # SNI |
182
|
|
|
|
|
|
|
$conn->{capath} ? ( |
183
|
|
|
|
|
|
|
SSL_verify_mode => SSL_VERIFY_PEER, |
184
|
|
|
|
|
|
|
( -d $conn->{capath} ? 'SSL_ca_path' : 'SSL_ca_file' ), |
185
|
|
|
|
|
|
|
$conn->{capath} |
186
|
0
|
0
|
|
|
|
|
):( |
|
|
0
|
|
|
|
|
|
187
|
|
|
|
|
|
|
SSL_verify_mode => SSL_VERIFY_NONE |
188
|
|
|
|
|
|
|
) |
189
|
|
|
|
|
|
|
); |
190
|
|
|
|
|
|
|
$sfo->startssl( %sslargs, sub { |
191
|
0
|
|
|
0
|
|
|
my $sfo = shift; |
192
|
0
|
|
|
|
|
|
my ($cert,$key) = $mitm->clone_cert($sfo->{fd}->peer_certificate); |
193
|
0
|
0
|
|
|
|
|
my $cfo = $wself->{fds}[$to] or return |
194
|
|
|
|
|
|
|
$wself->fatal("cannot startssl $to - no such fo"); |
195
|
|
|
|
|
|
|
$cfo->startssl( |
196
|
|
|
|
|
|
|
SSL_server => 1, |
197
|
|
|
|
|
|
|
SSL_cert => $cert, |
198
|
|
|
|
|
|
|
SSL_key => $key, |
199
|
|
|
|
|
|
|
sub { |
200
|
|
|
|
|
|
|
# allow data again |
201
|
0
|
|
|
|
|
|
$self->mask($to,r=>1); |
202
|
0
|
|
|
|
|
|
$self->mask($from,r=>1); |
203
|
0
|
0
|
|
|
|
|
$callback->() if $callback; |
204
|
|
|
|
|
|
|
} |
205
|
0
|
|
|
|
|
|
); |
206
|
0
|
|
|
|
|
|
}); |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# closes relay |
210
|
|
|
|
|
|
|
sub close:method { |
211
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
212
|
|
|
|
|
|
|
#debug("close $self"); |
213
|
0
|
|
|
|
|
|
undef $self->{conn}; |
214
|
0
|
0
|
|
|
|
|
@relays = grep { !$_ or $_ != $self } @relays; |
|
0
|
|
|
|
|
|
|
215
|
0
|
|
0
|
|
|
|
$_ && $_->close for @{$self->{fds}}; |
|
0
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
@{$self->{fds}} = (); |
|
0
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# shutdown part of relay |
220
|
|
|
|
|
|
|
sub shutdown:method { |
221
|
0
|
|
|
0
|
0
|
|
my ($self,$dir,$rw,$force) = @_; |
222
|
0
|
0
|
|
|
|
|
my $fo = $self->{fds}[$dir] or return; |
223
|
0
|
|
|
|
|
|
$fo->shutdown($rw,$force); |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# check for condition, where we cannot transfer anymore data: |
227
|
|
|
|
|
|
|
# - nowhere to read and no open requests |
228
|
|
|
|
|
|
|
# - nowhere to write too |
229
|
|
|
|
|
|
|
sub closeIfDone { |
230
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
231
|
0
|
|
|
|
|
|
my $sink = my $drain = ''; |
232
|
0
|
|
|
|
|
|
for my $fo (@{$self->{fds}}) { |
|
0
|
|
|
|
|
|
|
233
|
0
|
0
|
0
|
|
|
|
$fo && $fo->{fd} or next; |
234
|
0
|
0
|
|
|
|
|
return if $fo->{rbuf} ne ''; # has unprocessed data |
235
|
0
|
0
|
|
|
|
|
return if $fo->{wbuf} ne ''; # has unwritten data |
236
|
0
|
0
|
|
|
|
|
$drain .= $fo->{dir} if not $fo->{status} & 0b100; # not read-closed |
237
|
0
|
0
|
|
|
|
|
$sink .= $fo->{dir} if not $fo->{status} & 0b010; # not write-closed |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
0
|
0
|
|
|
|
|
if ( $sink eq '' ) { # nowhere to write |
241
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug( "close relay because all fd done sink='$sink' "); |
242
|
|
|
|
|
|
|
# close relay |
243
|
0
|
|
|
|
|
|
return $self->close; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
0
|
0
|
|
|
|
|
if ( $drain ne '01' ) { # no reading from both sides |
247
|
0
|
|
|
|
|
|
my $conn = $self->{conn}; |
248
|
0
|
0
|
0
|
|
|
|
if ( ! $conn or ! $conn->open_requests ) { |
249
|
|
|
|
|
|
|
# close relay |
250
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug( "close relay because nothing to read and all done"); |
251
|
0
|
|
|
|
|
|
return $self->close; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
0
|
0
|
|
|
|
|
$DEBUG && $self->xdebug("drain=$drain sink=$sink rq=".$self->{conn}->open_requests." - keeping open"); |
256
|
0
|
|
|
|
|
|
return; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# dump state to debug |
261
|
|
|
|
|
|
|
sub dump_state { |
262
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
263
|
0
|
|
|
|
|
|
my $conn = $self->{conn}; |
264
|
0
|
|
|
|
|
|
my $msg = ''; |
265
|
0
|
0
|
|
|
|
|
if ( my $fds = $self->{fds} ) { |
266
|
0
|
|
|
|
|
|
my @st; |
267
|
0
|
|
|
|
|
|
for( my $i=0;$i<@$fds;$i++) { |
268
|
0
|
|
0
|
|
|
|
push @st, sprintf("%d=%03b",$i,$fds->[$i]{status} || 0); |
269
|
|
|
|
|
|
|
} |
270
|
0
|
|
|
|
|
|
$msg .= " fd:".join(',',@st); |
271
|
|
|
|
|
|
|
} |
272
|
0
|
|
|
|
|
|
$msg = $conn->dump_state().$msg; |
273
|
0
|
0
|
|
|
|
|
return $msg if defined wantarray; |
274
|
0
|
|
|
|
|
|
debug($msg); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
my $idlet = AnyEvent->timer( |
279
|
|
|
|
|
|
|
after => 5, |
280
|
|
|
|
|
|
|
interval => 5, cb => sub { |
281
|
|
|
|
|
|
|
@relays = grep { $_ } @relays or return; |
282
|
|
|
|
|
|
|
#debug("check timeouts for %d conn",+@relays); |
283
|
|
|
|
|
|
|
my $now = AnyEvent->now; |
284
|
|
|
|
|
|
|
RELAY: for my $r (@relays) { |
285
|
|
|
|
|
|
|
# timeout depends on the state of the relay and child |
286
|
|
|
|
|
|
|
# if there are active requests set it to 60, if not (e.g. |
287
|
|
|
|
|
|
|
# idle keep-alive connections) to 30. If this is a forked |
288
|
|
|
|
|
|
|
# child with no listener which should close after all |
289
|
|
|
|
|
|
|
# requests are done close idle keep-alive connections faster, |
290
|
|
|
|
|
|
|
# e.g. set timeout to 1 |
291
|
|
|
|
|
|
|
my $idle = ! $r->{conn}->open_requests; |
292
|
|
|
|
|
|
|
my $timeout = |
293
|
|
|
|
|
|
|
! $idle ? 60 : |
294
|
|
|
|
|
|
|
$exit_if_no_relays ? 1 : |
295
|
|
|
|
|
|
|
30; |
296
|
|
|
|
|
|
|
for my $fo (@{$r->{fds}}) { |
297
|
|
|
|
|
|
|
next RELAY if $_->{didit} + $timeout > $now; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
$r->xdebug("close because of timeout"); |
300
|
|
|
|
|
|
|
$r->close |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
); |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
############################################################################ |
306
|
|
|
|
|
|
|
# Filehandle |
307
|
|
|
|
|
|
|
############################################################################ |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
package App::HTTP_Proxy_IMP::Relay::FD; |
310
|
1
|
|
|
1
|
|
2381
|
use Carp 'croak'; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
72
|
|
311
|
1
|
|
|
1
|
|
7
|
use Scalar::Util 'weaken'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
81
|
|
312
|
1
|
|
|
1
|
|
7
|
use App::HTTP_Proxy_IMP::Debug; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
93
|
|
313
|
1
|
|
|
1
|
|
613
|
use AnyEvent::Socket qw(tcp_connect format_address); |
|
1
|
|
|
|
|
21565
|
|
|
1
|
|
|
|
|
67
|
|
314
|
1
|
|
|
1
|
|
8
|
use IO::Socket::SSL; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
10
|
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
use fields ( |
317
|
1
|
|
|
|
|
7
|
'dir', # direction 0,1 |
318
|
|
|
|
|
|
|
'fd', # file descriptor |
319
|
|
|
|
|
|
|
'host', # destination hostname |
320
|
|
|
|
|
|
|
'status', # bitmap of read_shutdown|write_shutdown|connected |
321
|
|
|
|
|
|
|
'relay', # weak link to relay |
322
|
|
|
|
|
|
|
'didit', # time of last activity (read/write) |
323
|
|
|
|
|
|
|
'rbuf', # read buffer (read but not processed) |
324
|
|
|
|
|
|
|
'rsub', # read handler |
325
|
|
|
|
|
|
|
'rwatch', # AnyEvent watcher - undef if read is disabled |
326
|
|
|
|
|
|
|
'wbuf', # write buffer (not yet written to socket) |
327
|
|
|
|
|
|
|
'wsub', # write handler |
328
|
|
|
|
|
|
|
'wwatch', # AnyEvent watcher - undef if write is disabled |
329
|
|
|
|
|
|
|
'wsrc', # source of writes for stalled handling |
330
|
1
|
|
|
1
|
|
158
|
); |
|
1
|
|
|
|
|
2
|
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub new { |
333
|
0
|
|
|
0
|
|
|
my ($class,$dir,$fd,$relay,$connected) = @_; |
334
|
0
|
|
|
|
|
|
my $self = fields::new($class); |
335
|
0
|
|
|
|
|
|
$self->{dir} = $dir; |
336
|
0
|
|
|
|
|
|
$self->{fd} = $fd; |
337
|
0
|
0
|
|
|
|
|
$self->{status} = $connected ? 0b001 : 0; |
338
|
|
|
|
|
|
|
#weaken( $self->{relay} = $relay ); |
339
|
0
|
|
|
|
|
|
$self->{relay} = $relay; |
340
|
0
|
|
|
|
|
|
$self->{rbuf} = $self->{wbuf} = ''; |
341
|
0
|
|
|
|
|
|
return $self; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub xdebug { |
345
|
0
|
|
|
0
|
|
|
my $self = shift; |
346
|
0
|
|
|
|
|
|
my $conn = $self->{relay}{conn}; |
347
|
0
|
0
|
|
|
|
|
if ( my $xdebug = UNIVERSAL::can($conn,'xdebug') ) { |
348
|
0
|
|
|
|
|
|
my $msg = "[$self->{dir}] ".shift(@_); |
349
|
0
|
|
|
|
|
|
unshift @_,$conn,$msg; |
350
|
0
|
|
|
|
|
|
goto &$xdebug; |
351
|
|
|
|
|
|
|
} else { |
352
|
0
|
|
|
|
|
|
goto &debug; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub close:method { |
357
|
0
|
|
|
0
|
|
|
my $self = shift; |
358
|
0
|
|
|
|
|
|
$self->xdebug("close"); |
359
|
0
|
0
|
|
|
|
|
if ( $self->{fd} ) { |
360
|
0
|
|
|
|
|
|
$self->{fd} = undef; |
361
|
0
|
|
|
|
|
|
delete $self->{relay}{fds}[$self->{dir}]; |
362
|
0
|
|
|
|
|
|
$self->{relay}->closeIfDone; |
363
|
|
|
|
|
|
|
} |
364
|
0
|
|
|
|
|
|
%$self = (); |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub reset { |
368
|
0
|
|
|
0
|
|
|
my $self = shift; |
369
|
0
|
|
|
|
|
|
$self->xdebug("reset"); |
370
|
0
|
0
|
|
|
|
|
close($self->{fd}) if $self->{fd}; |
371
|
|
|
|
|
|
|
$self->{fd} = |
372
|
|
|
|
|
|
|
$self->{rwatch} = $self->{rsub} = |
373
|
|
|
|
|
|
|
$self->{wwatch} = $self->{wsub} = |
374
|
|
|
|
|
|
|
$self->{host} = |
375
|
|
|
|
|
|
|
$self->{wsrc} = |
376
|
0
|
|
|
|
|
|
undef; |
377
|
0
|
|
|
|
|
|
$self->{status} = $self->{didit} = 0; |
378
|
0
|
|
|
|
|
|
$self->{rbuf} = $self->{wbuf} = ''; |
379
|
0
|
|
|
|
|
|
return 1; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# attempt to shutdown fd. |
383
|
|
|
|
|
|
|
# don't shutdown(1) if wbuf ne '' && ! $force |
384
|
|
|
|
|
|
|
sub shutdown:method { |
385
|
0
|
|
|
0
|
|
|
my ($self,$rw,$force) = @_; |
386
|
0
|
0
|
|
|
|
|
my $write = $rw eq 'r' ? 0 : $rw eq 'w' ? 1 : $rw; |
|
|
0
|
|
|
|
|
|
387
|
0
|
0
|
|
|
|
|
my $stat = $write ? 0b010 : 0b100; |
388
|
0
|
0
|
0
|
|
|
|
return if $self->{status} & $stat && ! $force; # no change |
389
|
|
|
|
|
|
|
|
390
|
0
|
|
|
|
|
|
$self->{status} |= $stat; |
391
|
0
|
0
|
0
|
|
|
|
if ( $write && $self->{wbuf} ne '' ) { |
392
|
|
|
|
|
|
|
$self->xdebug("called shutdown $rw fn=".fileno($self->{fd}). |
393
|
0
|
|
|
|
|
|
" wbuf.len=".length($self->{wbuf})); |
394
|
0
|
0
|
|
|
|
|
return if ! $force; # will shutdown once all is written |
395
|
0
|
|
|
|
|
|
$self->{wbuf} = ''; # drop rest |
396
|
0
|
|
|
|
|
|
undef $self->{wsrc}; # don't re-enable, unclear state |
397
|
0
|
|
|
|
|
|
undef $self->{wwatch}; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
|
$self->xdebug("shutdown $rw fn=".fileno($self->{fd})); |
401
|
0
|
|
|
|
|
|
shutdown($self->{fd},$write); |
402
|
|
|
|
|
|
|
# shutdown on both sides -> close |
403
|
0
|
0
|
|
|
|
|
if (( $self->{status} & 0b110 ) == 0b110 ) { |
|
|
0
|
|
|
|
|
|
404
|
0
|
|
|
|
|
|
$self->xdebug( "close fn=".fileno($self->{fd})." because status $self->{status} done"); |
405
|
0
|
|
|
|
|
|
$self->close; |
406
|
|
|
|
|
|
|
} elsif ( $write ) { |
407
|
0
|
|
|
|
|
|
undef $self->{wwatch}; |
408
|
|
|
|
|
|
|
} else { |
409
|
0
|
|
|
|
|
|
undef $self->{rwatch}; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# if all fd are closed, close the relay too |
413
|
0
|
|
|
|
|
|
$self->{relay}->closeIfDone; |
414
|
|
|
|
|
|
|
|
415
|
0
|
|
|
|
|
|
return 1; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
sub mask { |
420
|
0
|
|
|
0
|
|
|
my ($self,$rw,$val) = @_; |
421
|
|
|
|
|
|
|
#debug("$self->{dir} $self->{fd} fn=".fileno($self->{fd})." $rw=>$val"); |
422
|
0
|
0
|
|
|
|
|
if ( $rw eq 'r' ) { |
|
|
0
|
|
|
|
|
|
423
|
0
|
0
|
|
|
|
|
if ( ! $val ) { |
424
|
|
|
|
|
|
|
# disable read |
425
|
0
|
|
|
|
|
|
undef $self->{rwatch}; |
426
|
|
|
|
|
|
|
} else { |
427
|
0
|
0
|
|
|
|
|
$self->{status} & 0b100 and return 0; # read shutdown already |
428
|
0
|
|
0
|
0
|
|
|
$self->{rsub} ||= sub { _read($self) }; |
|
0
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
$self->{rwatch} = AnyEvent->io( |
430
|
|
|
|
|
|
|
fh => $self->{fd}, |
431
|
|
|
|
|
|
|
poll => 'r', |
432
|
|
|
|
|
|
|
cb => ref($val) ? $val : $self->{rsub} |
433
|
0
|
0
|
|
|
|
|
); |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
} elsif ( $rw eq 'w' ) { |
436
|
0
|
0
|
|
|
|
|
if ( ! $val ) { |
437
|
|
|
|
|
|
|
# disable write |
438
|
0
|
|
|
|
|
|
undef $self->{wwatch}; |
439
|
|
|
|
|
|
|
} else { |
440
|
0
|
0
|
|
|
|
|
$self->{status} & 0b010 and return 0; # write shutdown already |
441
|
0
|
|
0
|
0
|
|
|
$self->{wsub} ||= sub { _writebuf($self) }; |
|
0
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
$self->{wwatch} = AnyEvent->io( |
443
|
|
|
|
|
|
|
fh => $self->{fd}, |
444
|
|
|
|
|
|
|
poll => 'w', |
445
|
|
|
|
|
|
|
cb => ref($val) ? $val : $self->{wsub} |
446
|
0
|
0
|
|
|
|
|
); |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
} else { |
449
|
0
|
|
|
|
|
|
croak("cannot set mask for $rw"); |
450
|
|
|
|
|
|
|
} |
451
|
0
|
|
|
|
|
|
return 1; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
# write data, gets written from relay->send |
455
|
|
|
|
|
|
|
sub write:method { |
456
|
0
|
|
|
0
|
|
|
my ($self,$data,$from) = @_; |
457
|
0
|
|
|
|
|
|
my $n = 0; |
458
|
0
|
0
|
|
|
|
|
if ( $self->{wbuf} eq '' ) { |
459
|
|
|
|
|
|
|
# no buffered data, set as buffer and try to write immediately |
460
|
0
|
|
|
|
|
|
$self->{wbuf} = $data; |
461
|
0
|
|
0
|
|
|
|
$n = _writebuf($self,$from) // return; # fatal? |
462
|
|
|
|
|
|
|
} else { |
463
|
|
|
|
|
|
|
# only append to buffer, will be written on write ready |
464
|
0
|
|
|
|
|
|
$self->{wbuf} .= $data; |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
0
|
0
|
0
|
|
|
|
if ( $self->{wbuf} ne '' |
468
|
|
|
|
|
|
|
&& ! $self->{wsrc}{$from}++ ) { |
469
|
|
|
|
|
|
|
# newly stalled, disable reads on $from for now |
470
|
0
|
|
|
|
|
|
$self->{relay}->mask($from, r=>0); |
471
|
|
|
|
|
|
|
} |
472
|
0
|
|
|
|
|
|
return $n; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
# gets called if wbuf is not empty, either from write or from callback |
476
|
|
|
|
|
|
|
# when fd is writable again |
477
|
|
|
|
|
|
|
sub _writebuf { |
478
|
0
|
|
|
0
|
|
|
my $self = shift; |
479
|
|
|
|
|
|
|
#debug("write $self fn=".fileno($self->{fd})); |
480
|
0
|
|
|
|
|
|
my $n = syswrite($self->{fd},$self->{wbuf}); |
481
|
|
|
|
|
|
|
#debug("write(%s,%d) -> %s", $self->{dir},length($self->{wbuf}), (defined $n ? $n : $!)); |
482
|
0
|
0
|
|
|
|
|
if ( ! defined $n ) { |
483
|
|
|
|
|
|
|
$self->{relay}->fatal("write($self->{dir}) failed: $!") |
484
|
0
|
0
|
0
|
|
|
|
unless $!{EINTR} or $!{EAGAIN}; |
485
|
0
|
|
|
|
|
|
return; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
0
|
|
|
|
|
|
substr($self->{wbuf},0,$n,''); |
489
|
0
|
|
|
|
|
|
$self->{didit} = AnyEvent->now; |
490
|
|
|
|
|
|
|
|
491
|
0
|
0
|
|
|
|
|
if ( $self->{wbuf} eq '' ) { |
492
|
|
|
|
|
|
|
# wrote everything |
493
|
|
|
|
|
|
|
#debug("all written to $self->{dir}"); |
494
|
0
|
|
|
|
|
|
undef $self->{wwatch}; |
495
|
|
|
|
|
|
|
|
496
|
0
|
0
|
|
|
|
|
if ( $self->{status} & 0b100 ) { |
497
|
|
|
|
|
|
|
# was marked for shutdown |
498
|
0
|
|
|
|
|
|
shutdown($self->{fd},1); |
499
|
|
|
|
|
|
|
# if all fd are closed, close the relay too |
500
|
0
|
|
|
|
|
|
$self->{relay}->closeIfDone; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
# enable read again on stalled fd |
503
|
0
|
0
|
|
|
|
|
if ( my $src = $self->{wsrc} ) { |
504
|
0
|
|
|
|
|
|
$self->{relay}->mask($_, r=>1) for (keys %$src); |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
} else { |
507
|
|
|
|
|
|
|
# need to write more later |
508
|
|
|
|
|
|
|
#debug("need to write more"); |
509
|
0
|
|
|
|
|
|
mask($self,w=>1); |
510
|
|
|
|
|
|
|
} |
511
|
0
|
|
|
|
|
|
return $n; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# gets called if data are available on the socket |
515
|
|
|
|
|
|
|
# but only, if we don't have unsent data in wbuf |
516
|
|
|
|
|
|
|
# reads data into rbuf and calls connection->in |
517
|
|
|
|
|
|
|
sub _read:method { |
518
|
0
|
|
|
0
|
|
|
my $self = shift; |
519
|
|
|
|
|
|
|
#debug("read $self fn=".fileno($self->{fd})); |
520
|
0
|
|
|
|
|
|
my $n = sysread($self->{fd},$self->{rbuf},2**15,length($self->{rbuf})); |
521
|
|
|
|
|
|
|
#debug("read done: ". (defined $n ? $n : $!)); |
522
|
0
|
0
|
|
|
|
|
if ( ! defined $n ) { |
523
|
0
|
0
|
0
|
|
|
|
if ( ! $!{EINTR} and ! $!{EAGAIN} ) { |
524
|
|
|
|
|
|
|
# complain only if we are inside a request |
525
|
|
|
|
|
|
|
# timeouts after inactivity are normal |
526
|
|
|
|
|
|
|
return $self->{relay}->fatal("read($self->{dir}) failed: $!") |
527
|
0
|
0
|
|
|
|
|
if $self->{relay}{conn}->open_requests; |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
# close connection |
530
|
0
|
|
|
|
|
|
$self->xdebug("closing relay because of read error on $self->{dir}"); |
531
|
0
|
|
|
|
|
|
return $self->{relay}->close; |
532
|
|
|
|
|
|
|
} |
533
|
0
|
|
|
|
|
|
return; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
0
|
|
|
|
|
|
$self->{didit} = AnyEvent->now; |
537
|
|
|
|
|
|
|
my $bytes = $self->{relay}{conn} |
538
|
0
|
|
|
|
|
|
->in($self->{dir},$self->{rbuf},!$n,$self->{didit}); |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# fd/relay closed from within in() ? |
541
|
0
|
0
|
|
|
|
|
defined $self->{fd} or return; |
542
|
|
|
|
|
|
|
|
543
|
0
|
0
|
|
|
|
|
if ( $bytes ) { |
544
|
|
|
|
|
|
|
# connection accepted $bytes |
545
|
0
|
|
|
|
|
|
substr($self->{rbuf},0,$bytes,''); |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
return $self->{relay}->fatal( |
549
|
|
|
|
|
|
|
"connection should have taken all remaining bytes on eof") |
550
|
0
|
0
|
0
|
|
|
|
if !$n && $self->{rbuf} ne ''; |
551
|
|
|
|
|
|
|
|
552
|
0
|
0
|
|
|
|
|
$self->shutdown('r') if ! $n; |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
sub connect:method { |
556
|
0
|
|
|
0
|
|
|
my ($self,$host,$port,$callback,$reconnect) = @_; |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
# down existing connection if we should connect to another host |
559
|
|
|
|
|
|
|
$self->reset if $self->{fd} and |
560
|
0
|
0
|
0
|
|
|
|
( $reconnect or $self->{host}||'' ne "$host.$port" ); |
|
|
|
0
|
|
|
|
|
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# if we have a connection already, keep it |
563
|
0
|
0
|
|
|
|
|
if ( $self->{status} & 0b001 ) { # already connected |
564
|
0
|
|
|
|
|
|
$callback->(); |
565
|
0
|
|
|
|
|
|
return 1; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
# (re)connect |
569
|
0
|
|
|
|
|
|
$self->xdebug("connecting to $host.$port"); |
570
|
|
|
|
|
|
|
# async dns lookup + connect |
571
|
|
|
|
|
|
|
App::HTTP_Proxy_IMP::Relay::DNS::lookup($host, sub { |
572
|
0
|
0
|
|
0
|
|
|
$self->{relay} or return; # relay already closed |
573
|
0
|
0
|
|
|
|
|
if ( my $addr = shift ) { |
574
|
|
|
|
|
|
|
tcp_connect($addr,$port, sub { |
575
|
0
|
0
|
|
|
|
|
if ( my $fd = shift ) { |
576
|
0
|
0
|
|
|
|
|
$self->{relay} or return; # relay already closed |
577
|
0
|
|
|
|
|
|
$self->{fd} = $fd; |
578
|
0
|
|
|
|
|
|
$self->{status} = 0b001; |
579
|
0
|
|
|
|
|
|
$self->{host} = "$host.$port"; |
580
|
0
|
|
|
|
|
|
$self->xdebug("connect done"); |
581
|
0
|
|
|
|
|
|
$self->mask( r => 1 ); |
582
|
0
|
|
|
|
|
|
$callback->(); |
583
|
|
|
|
|
|
|
} else { |
584
|
0
|
|
|
|
|
|
App::HTTP_Proxy_IMP::Relay::DNS::uncache($host,$addr); |
585
|
0
|
0
|
|
|
|
|
$self->{relay} or return; # relay already closed |
586
|
0
|
|
|
|
|
|
$self->{relay}->fatal("connect to $host.$port failed: $!"); |
587
|
|
|
|
|
|
|
} |
588
|
0
|
|
|
|
|
|
}); |
589
|
|
|
|
|
|
|
} else { |
590
|
|
|
|
|
|
|
$self->{relay}->fatal( |
591
|
0
|
|
|
|
|
|
"connect to $host.$port failed: no such host (DNS)"); |
592
|
|
|
|
|
|
|
} |
593
|
0
|
|
|
|
|
|
}); |
594
|
0
|
|
|
|
|
|
return -1; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub startssl { |
598
|
0
|
|
|
0
|
|
|
my $self = shift; |
599
|
|
|
|
|
|
|
$self->{rbuf} eq '' or return |
600
|
0
|
0
|
|
|
|
|
$self->{relay}->fatal("read buf $self->{dir} not empty before starting SSL: '$self->{rbuf}'"); |
601
|
|
|
|
|
|
|
$self->{wbuf} eq '' or return |
602
|
0
|
0
|
|
|
|
|
$self->{relay}->fatal("write buf $self->{dir} not empty before starting SSL: '$self->{wbuf}'"); |
603
|
|
|
|
|
|
|
|
604
|
0
|
0
|
|
|
|
|
my $callback = @_%2 ? pop(@_):undef; |
605
|
0
|
|
|
|
|
|
my %sslargs = @_; |
606
|
|
|
|
|
|
|
IO::Socket::SSL->start_SSL( $self->{fd}, |
607
|
0
|
0
|
|
|
|
|
%sslargs, |
608
|
|
|
|
|
|
|
SSL_startHandshake => 0, |
609
|
|
|
|
|
|
|
) or die "failed to upgrade socket to SSL"; |
610
|
|
|
|
|
|
|
my $sub = $sslargs{SSL_server} |
611
|
0
|
0
|
|
|
|
|
? \&IO::Socket::SSL::accept_SSL |
612
|
|
|
|
|
|
|
: \&IO::Socket::SSL::connect_SSL; |
613
|
0
|
|
|
|
|
|
_ssl($self,$sub,$callback,\%sslargs); |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
sub _ssl { |
617
|
0
|
|
|
0
|
|
|
my ($self,$sub,$cb,$sslargs) = @_; |
618
|
0
|
0
|
|
|
|
|
if ( $sub->($self->{fd}) ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
619
|
0
|
|
|
|
|
|
$self->xdebug("ssl handshake success"); |
620
|
0
|
0
|
|
|
|
|
$cb->($self) if $cb; |
621
|
|
|
|
|
|
|
} elsif ( $!{EAGAIN} ) { |
622
|
|
|
|
|
|
|
# retry |
623
|
|
|
|
|
|
|
my $dir = |
624
|
|
|
|
|
|
|
$SSL_ERROR == SSL_WANT_READ ? 'r' : |
625
|
|
|
|
|
|
|
$SSL_ERROR == SSL_WANT_WRITE ? 'w' : |
626
|
0
|
0
|
|
|
|
|
return $self->{relay}->fatal( "unhandled $SSL_ERROR on EAGAIN" ); |
|
|
0
|
|
|
|
|
|
627
|
0
|
|
|
0
|
|
|
$self->mask( $dir => sub { _ssl($self,$sub,$cb,$sslargs) }); |
|
0
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
} elsif ( $sslargs->{SSL_server} ) { |
629
|
0
|
|
|
|
|
|
return $self->{relay}->fatal( "error on accept_SSL: $SSL_ERROR|$!" ); |
630
|
|
|
|
|
|
|
} else { |
631
|
|
|
|
|
|
|
return $self->{relay}->fatal( |
632
|
0
|
|
|
|
|
|
"error on connect_SSL to $sslargs->{SSL_verifycn_name}: $SSL_ERROR|$!" ); |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
############################################################################ |
638
|
|
|
|
|
|
|
# DNS cache |
639
|
|
|
|
|
|
|
############################################################################ |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
package App::HTTP_Proxy_IMP::Relay::DNS; |
642
|
1
|
|
|
1
|
|
2285
|
use AnyEvent::DNS; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
643
|
1
|
|
|
1
|
|
5
|
use Socket qw(AF_INET AF_INET6 inet_pton); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
327
|
|
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
my %cache; |
646
|
|
|
|
|
|
|
sub uncache { |
647
|
0
|
|
|
0
|
|
|
my ($host,$addr) = @_; |
648
|
0
|
0
|
|
|
|
|
my $e = $cache{lc($host)} or return; |
649
|
0
|
|
|
|
|
|
@$e = grep { $_ ne $addr } @$e; |
|
0
|
|
|
|
|
|
|
650
|
0
|
0
|
|
|
|
|
delete $cache{lc($host)} if !@$e; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
sub lookup { |
654
|
0
|
|
|
0
|
|
|
my ($host,$cb) = @_; |
655
|
0
|
|
|
|
|
|
$host = lc($host); |
656
|
|
|
|
|
|
|
|
657
|
0
|
0
|
0
|
|
|
|
if ( my $e = $cache{$host} ) { |
|
|
0
|
|
|
|
|
|
658
|
0
|
|
|
|
|
|
return $cb->(@$e); |
659
|
|
|
|
|
|
|
} elsif ( inet_pton(AF_INET,$host) || inet_pton(AF_INET6,$host) ) { |
660
|
0
|
|
|
|
|
|
return $cb->($host); |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
AnyEvent::DNS::a($host,sub { |
664
|
0
|
0
|
|
0
|
|
|
if ( @_ ) { |
665
|
0
|
|
|
|
|
|
$cache{$host} = [ @_ ]; |
666
|
0
|
|
|
|
|
|
return $cb->(@_); |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# try AAAA |
670
|
|
|
|
|
|
|
AnyEvent::DNS::aaaa($host,sub { |
671
|
0
|
0
|
|
|
|
|
$cache{$host} = [ @_ ] if @_; |
672
|
0
|
|
|
|
|
|
return $cb->(@_); |
673
|
0
|
|
|
|
|
|
}); |
674
|
0
|
|
|
|
|
|
}); |
675
|
|
|
|
|
|
|
} |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
1; |