line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::MitM; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Net::MitM - Man in the Middle - connects a client and a server, giving visibility of and control over messages passed. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 VERSION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
Version 0.03_02 |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=cut |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '0.03_02'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Net::MitM is designed to be inserted between a client and a server. It proxies all traffic through verbatum, and also copies that same data to a log file and/or a callback function, allowing a data session to be monitored, recorded, even altered on the fly. |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
MitM acts as a 'man in the middle', sitting between the client and server. To the client, MitM looks like the server. To the server, MitM looks like the client. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
MitM cannot be used to covertly operate on unsuspecting client/server sessions - it requires that you control either the client or the server. If you control the client, you can tell it to connect via your MitM. If you control the server, you can move it to a different port, and put a MitM in its place. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
When started, MitM opens a socket and listens for connections. When that socket is connected to, MitM opens another connection to the server. Messages from either client or server are passed to the other, and a copy of each message is, potentially, logged. Alternately, callback methods may be used to add business logic, including potentially altering the messages being passed. |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
MitM can also be used as a proxy, allowing two processes on machines that cannot 'see' each other to communicate via an intermediary machine that is visible to both. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
There is an (as yet unreleased) sister module L that allows a MitM session to be replayed. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head3 Usage |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Assume the following script is running on the local machine: |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
use Net::MitM; |
34
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("cpan.org", 80, 10080); |
35
|
|
|
|
|
|
|
$MitM->log_file("MitM.log"); |
36
|
|
|
|
|
|
|
$MitM->go(); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
A browser connecting to L will now cause MitM to open a connection to cpan.org, and messages sent by either end will be passed to the other end, and logged to MitM.log. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
For another example, see samples/mitm.pl in the MitM distribution. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head3 Modifying messages on the fly - a worked example. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
However you deploy MitM, it will be virtually identical to having the client and server talk directly. The difference will be that either the client and/or server will be at an address other than the one its counterpart believes it to be at. Most programs ignore this, but sometimes it matters. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
For example, HTTP browsers pass a number of parameters, one of which is "Host", the host to which the browser believes it is connecting. Often, this parameter is unused. But sometimes, a single HTTP server will be serving content for more than one website. Such a server generally relies on the Host parameter to know what it is to return. If the MitM is not on the same host as the HTTP server, the host parameter that the browser passes will cause the HTTP server to fail to serve the desired pages. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Further, HTTP servers typically return URLs containing the host address. If the browser navigates to a returned URL, it will from that point onwards connect directly to the server in the URL instead of communicating via MitM. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
Both of these problems can be worked around by modifying the messages being passed. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
For example, assume the following script is running on the local machine: |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
use Net::MitM; |
55
|
|
|
|
|
|
|
sub send_($) {$_[0] =~ s/Host: .*:\d+/Host: cpan.org/;} |
56
|
|
|
|
|
|
|
sub receive($) {$_[0] =~ s/cpan.org:\d+/localhost:10080/g;} |
57
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("cpan.org", 80, 10080); |
58
|
|
|
|
|
|
|
$MitM->client_to_server_callback(\&send,callback_behaviour=>"modify"); |
59
|
|
|
|
|
|
|
$MitM->server_to_client_callback(\&receive,callback_behaviour=>"modify"); |
60
|
|
|
|
|
|
|
$MitM->log_file("http_MitM.log"); |
61
|
|
|
|
|
|
|
$MitM->go(); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
The send callback tells the server that it is to serve cpan.org pages, instead of some other set of pages, while the receive callback tells the browser to access cpan.org URLs via the MitM process, not directly. The HTTP server will now respond properly, even though the browser sent the wrong hostname, and the browser will now behave as desired and direct future requests via the MitM. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
For another example, see samples/http_mitm.pl in the MitM distribution. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
A more difficult problem is security aware processes, such as those that use HTTPS based protocols. They are actively hostname aware. Precisely to defend against a man-in-the-middle attack, they check their counterpart's reported hostname (but not normally the port) against the actual hostname. Unless client, server and MitM are all on the same host, either the client or the server will notice that the remote hostname is not what it should be, and will abort the connection. |
68
|
|
|
|
|
|
|
There is no good workaround for this, unless you can run an instance of MitM on the server, and another on the client - but even if you do, you still have to deal with the communication being encrypted. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# ####### |
75
|
|
|
|
|
|
|
# Globals |
76
|
|
|
|
|
|
|
# ####### |
77
|
|
|
|
|
|
|
|
78
|
19
|
|
|
19
|
|
460244
|
use 5.002; # has been tested with 5.8.9. an earlier version failed with 5.6.2, but that has probably been fixed. |
|
19
|
|
|
|
|
104
|
|
|
19
|
|
|
|
|
753
|
|
79
|
|
|
|
|
|
|
|
80
|
19
|
|
|
19
|
|
77
|
use warnings FATAL => 'all'; |
|
19
|
|
|
|
|
20
|
|
|
19
|
|
|
|
|
860
|
|
81
|
19
|
|
|
19
|
|
18483
|
use Socket; |
|
19
|
|
|
|
|
124451
|
|
|
19
|
|
|
|
|
13927
|
|
82
|
19
|
|
|
19
|
|
19891
|
use FileHandle; |
|
19
|
|
|
|
|
779860
|
|
|
19
|
|
|
|
|
133
|
|
83
|
19
|
|
|
19
|
|
84312
|
use IO::Handle; |
|
19
|
|
|
|
|
74
|
|
|
19
|
|
|
|
|
987
|
|
84
|
19
|
|
|
19
|
|
115
|
use Carp; |
|
19
|
|
|
|
|
56
|
|
|
19
|
|
|
|
|
2778
|
|
85
|
19
|
|
|
19
|
|
151
|
use strict; |
|
19
|
|
|
|
|
236
|
|
|
19
|
|
|
|
|
970
|
|
86
|
|
|
|
|
|
|
#BEGIN{eval{require Time::HiRes; import Time::HiRes qw(time)}}; # only needed for high precision time_interval - will still work fine even if missing |
87
|
19
|
|
|
19
|
|
33042
|
eval {use Time::HiRes qw(time)}; # only needed for high precision time_interval - will still work fine even if missing |
|
19
|
|
|
|
|
61785
|
|
|
19
|
|
|
|
|
114
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head2 new( remote_ip_address, remote_port_num, local_port_num ) |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
Creates a new MitM |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head4 Parameters |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=over |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=item * remote_ip_address - the remote hostname/IP address of the server |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item * remote_port_num - the remote port number of the server |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=item * local_port_num - the port number to listen on |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=item * Returns - a new MitM object |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=back |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head4 Usage |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
To keep a record of all messages sent: |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
use Net::MitM; |
112
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("www.cpan.org", 80, 10080); |
113
|
|
|
|
|
|
|
$MitM->log_file("MitM.log"); |
114
|
|
|
|
|
|
|
$MitM->go(); |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=cut |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub hhmmss(); |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
my $mitm_count=0; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub _new(){ |
123
|
571
|
|
|
571
|
|
1440
|
my %this; |
124
|
571
|
|
|
|
|
7840
|
$this{verbose} = 1; |
125
|
571
|
|
|
|
|
4003
|
$this{parallel} = 0; |
126
|
571
|
|
|
|
|
2941
|
$this{mydate} = \&hhmmss; |
127
|
571
|
|
|
|
|
5935
|
$this{name} = "MitM".++$mitm_count; |
128
|
571
|
|
|
|
|
2776
|
return \%this; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub new($$$;$) { |
132
|
167
|
|
|
167
|
1
|
178473
|
my $class=shift; |
133
|
167
|
|
|
|
|
655
|
my $this=_new(); |
134
|
167
|
50
|
|
|
|
328986
|
$this->{remote_ip_address} = shift or croak "remote hostname/ip address missing"; |
135
|
167
|
50
|
|
|
|
848
|
$this->{remote_port_num} = shift or croak "remote port number missing"; |
136
|
167
|
|
33
|
|
|
667
|
$this->{local_port_num} = shift || $this->{remote_port_num}; |
137
|
167
|
|
|
|
|
772
|
return bless($this, $class); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=head2 go( ) |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
Listen on local_port, accept incoming connections, and forwards messages back and forth. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=head4 Parameters |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=over |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item * --none-- |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=item * Returns --none-- |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=back |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=head4 Usage |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
When a connection on local_port is received a connect to remote_ip_address:remote_port_num is created and messages from the client are passed to the server and vice-versa. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
If parallel() was set, which is not the default, there will be a new process created for each such session. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
If any callback functions have been set, they will be called before each message is passed. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
If logging is on, messages will be logged. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
By default, go() does not return. The function L can be called to force go() to return. You may want to L before calling it. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
If new_server() was used instead of new(), messages from client are instead passed to the server callback function. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=cut |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# Convenience function - intentionally not exposed. If you really want to call it, you can of course. But if you are going to violate encapsulation, why not go directly to the variables? |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub _set($;$) { |
173
|
1701
|
|
|
1701
|
|
48455
|
my $this=shift; |
174
|
1701
|
50
|
|
|
|
7399
|
my $key=shift or confess "missing mandatory parameter"; |
175
|
1701
|
|
|
|
|
2101
|
my $value=shift; |
176
|
1701
|
100
|
|
|
|
17344
|
if(defined $value){ |
177
|
1658
|
|
|
|
|
4123
|
$this->{$key} = $value; |
178
|
|
|
|
|
|
|
} |
179
|
1701
|
|
|
|
|
5404
|
return $this->{$key}; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head2 name( [name] ) |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Names the object - will be reported back in logging/debug |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head4 Parameters |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=over |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item * name - the new name (default is MitM1, MitM2, ...) |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=item * Returns - the current or new setting |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=back |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head4 Usage |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
For a minimal MitM: |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
use Net::MitM; |
201
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("www.cpan.org", 80, 10080); |
202
|
|
|
|
|
|
|
$MitM->go(); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=cut |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub name(;$) { |
207
|
545
|
|
|
545
|
1
|
179926
|
my $this=shift; |
208
|
545
|
|
|
|
|
2091
|
my $value=shift; |
209
|
545
|
|
|
|
|
1718
|
return $this->_set("name", $value); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=head2 verbose( [level] ) |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
Turns on/off reporting to stdout. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head4 Parameters |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=over |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=item * level - how verbose to be. 0=nothing, 1=normal, 2=debug. The default is 1. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=item * Returns - the current or new setting |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=back |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head4 Usage |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Setting verbose changes the amount of information printed to stdout. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=cut |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub verbose(;$) { |
233
|
133
|
|
|
133
|
1
|
1493
|
my $this=shift; |
234
|
133
|
|
|
|
|
321
|
my $verbose=shift; |
235
|
|
|
|
|
|
|
#warn "verbose->(",$verbose||"--undef--",")\n"; |
236
|
133
|
|
|
|
|
544
|
return $this->_set("verbose", $verbose); |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head2 client_to_server_callback( callback [callback_behaviour => behaviour] ) |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Set a callback function to monitor/modify each message sent to server |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=head4 Parameters |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=over |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=item * callback - a reference to a function to be called for each message sent to server |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=item * callback_behaviour - explicitly sets the callback as readonly, modifying or conditional. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=item * Returns - the current or new setting |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=back |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head4 Usage |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
If a client_to_server_callback callback is set, it will be called with a copy of each message received from the client before it is sent to the server. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
What the callback returns determines what will be sent, depending on the value of callback_behaviour: |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=over |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=item * If callback_behaviour = "readonly", the return value from the callback is ignored, and the original message is sent. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=item * If callback_behaviour = "modify", the return value from the callback is sent instead of the original message, unless the return value is undef, in which case nothing is sent |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item * If callback_behaviour = "conditional", which is the default, that the return value from the callback is sent instead of the original message, or if the return value is undef, then the original message is sent. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=back |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
For example, to modify messages: |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
use Net::MitM; |
274
|
|
|
|
|
|
|
sub send_($) {$_[0] =~ s/Host: .*:\d+/Host: cpan.org/;} |
275
|
|
|
|
|
|
|
sub receive($) {$_[0] =~ s/www.cpan.org(:\d+)?/localhost:10080/g;} |
276
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("www.cpan.org", 80, 10080); |
277
|
|
|
|
|
|
|
$MitM->client_to_server_callback(\&send, callback_behaviour=>"modify"); |
278
|
|
|
|
|
|
|
$MitM->server_to_client_callback(\&receive, callback_behaviour=>"modify"); |
279
|
|
|
|
|
|
|
$MitM->go(); |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
If the callback is readonly, it should either return a copy of the original message, or undef. Be careful not to accidentally return something else - remember that perl methods implicitly returns the value of the last command executed. |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
For example, to write messages to a log: |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub peek($) {my $msg = shift; print LOG; return $msg;} |
286
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("www.cpan.org", 80, 10080); |
287
|
|
|
|
|
|
|
$MitM->client_to_server_callback(\&peek, callback_behaviour=>"readonly"); |
288
|
|
|
|
|
|
|
$MitM->server_to_client_callback(\&peek, callback_behaviour=>"readonly"); |
289
|
|
|
|
|
|
|
$MitM->go(); |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
For historical reasons, "conditional" is the default. It is not recommended, and may be deprecated in a future release. |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
"conditional" may be used for readonly or modify type behaviour. For readonly behaviour, either return the original message, or return null. For example: |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub peek($) {my $msg = shift; print LOG; return $msg;} |
296
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("www.cpan.org", 80, 10080); |
297
|
|
|
|
|
|
|
$MitM->client_to_server_callback(\&peek,callback_behaviour=>"readonly"); |
298
|
|
|
|
|
|
|
... |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
sub peek($) {my $msg = shift; print LOG; return undef;} |
301
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("www.cpan.org", 80, 10080); |
302
|
|
|
|
|
|
|
$MitM->client_to_server_callback(\&peek,callback_behaviour=>"readonly"); |
303
|
|
|
|
|
|
|
... |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
But be careful. This is unlikely to do what you would want: |
306
|
|
|
|
|
|
|
sub peek($) {my $msg = shift; print LOG} |
307
|
|
|
|
|
|
|
my $MitM = Net::MitM->new("www.cpan.org", 80, 10080); |
308
|
|
|
|
|
|
|
$MitM->client_to_server_callback(\&peek,callback_behaviour=>"readonly"); |
309
|
|
|
|
|
|
|
... |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Assuming print LOG succeeds, print will return a true value (probably 1), and MitM will send that value, not $msg. |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=cut |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub _sanity_check_options($$) |
316
|
|
|
|
|
|
|
{ |
317
|
177
|
|
|
177
|
|
1633
|
my $self=shift; |
318
|
177
|
|
|
|
|
297
|
my $options=shift; |
319
|
177
|
|
|
|
|
285
|
my $allowed=shift; |
320
|
177
|
|
|
|
|
898
|
foreach my $key (keys %$options){ |
321
|
193
|
100
|
|
|
|
665
|
if(!$allowed->{$key}){ |
322
|
16
|
50
|
33
|
|
|
272
|
carp "Warning: $key not a supported option. Expected: ",join(" ",map {"'$_'"} keys %$options) unless defined $self->{verbose} && $self->{verbose}<=0; |
|
0
|
|
|
|
|
0
|
|
323
|
16
|
|
|
|
|
96
|
return undef; |
324
|
|
|
|
|
|
|
} |
325
|
177
|
100
|
|
|
|
3498
|
if( $options->{$key} !~ $allowed->{$key}){ |
326
|
16
|
50
|
|
|
|
64
|
carp "Warning: $key=$options->{$key} not a supported option.\n" unless $self->{verbose}<=0; |
327
|
16
|
|
|
|
|
64
|
return undef; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
} |
330
|
145
|
|
|
|
|
421
|
return 1; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub client_to_server_callback(;$%) { |
334
|
129
|
|
|
129
|
1
|
1349
|
my $this=shift; |
335
|
129
|
|
|
|
|
216
|
my $callback=shift; |
336
|
129
|
|
|
|
|
1256
|
my %options=@_; |
337
|
129
|
|
|
|
|
2256
|
$this->_sanity_check_options(\%options,{callback_behaviour=>qr{^(readonly|modify|conditional)$}}); |
338
|
129
|
50
|
|
|
|
838
|
$this->_set("client_to_server_callback_behaviour", $options{callback_behaviour}) if $options{callback_behaviour}; |
339
|
129
|
|
|
|
|
340
|
return $this->_set("client_to_server_callback", $callback); |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=head2 server_to_client_callback( [callback] [,callback_behaviour=>behaviour] ) |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
Set a callback function to monitor/modify each message received from server. |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=head4 Parameters |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=over |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=item * callback - a reference to a function to be called for each inward message |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=item * callback_behaviour - explicitly sets the callback to readonly, modify or conditional. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=item * Returns - the current or new setting of callback |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=back |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head4 Usage |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
If a server_to_client_callback callback is set, it will be called with a copy of each message received from the server before it is sent to the client. |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
What the callback returns determines what will be sent, depending on the value of callback_behaviour: |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=over |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=item * If callback_behaviour = "readonly", the return value from the callback is ignored, and the original message is sent. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=item * If callback_behaviour = "modify", the return value from the callback is sent instead of the original message, unless the return value is undef, in which case nothing is sent |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=item * If callback_behaviour = "conditional", which is the default, that the return value from the callback is sent instead of the original message, or if the return value is undef, then the original message is sent. |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=back |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=cut |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub server_to_client_callback(;$%) { |
377
|
128
|
|
|
128
|
1
|
681
|
my $this=shift; |
378
|
128
|
|
|
|
|
235
|
my $callback=shift; |
379
|
128
|
|
|
|
|
417
|
my %options=@_; |
380
|
128
|
100
|
|
|
|
915
|
$this->_set("server_to_client_callback_behaviour", $options{callback_behaviour}) if $options{callback_behaviour}; |
381
|
128
|
|
|
|
|
309
|
return $this->_set("server_to_client_callback", $callback); |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head2 timer_callback( [interval, callback] ) |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
Set a callback function to be called at regular intervals |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=head4 Parameters |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=over |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=item * interval - how often the callback function is to be called - must be > 0 seconds, may be fractional |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=item * callback - a reference to a function to be called every interval seconds |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=item * Returns - the current or new setting, as an array |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=back |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=head4 Usage |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
If the callback is set, it will be called every interval seconds. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
Interval must be > 0 seconds. It may be fractional. If interval is passed as 0 it will be reset to 1 second. This is to prevent accidental spin-wait. If you really want to spin-wait, pass an extremely small but non-zero interval. |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
The time spent in callbacks is not additional to the specified interval - the timer callback will be called every interval seconds, or as close as possible to every interval seconds. |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
Please remember that if you have called fork before calling go() that the timer_callback method will be executed in a different process to the parent - the two processes will need to use some form of IPC if they are to communicate. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Historical note: Prior to version 0.03_01, if the callback returned false, mainloop would exit and return control to the caller. (FIXME It still does.) stop_when_idle() can be used to persuade go() to exit. (FIXME check what happens if go() is called after stopping. TODO Add an unconditional stop() method) |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=cut |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
#FIXME ignore return code from timer_callback. (Or deprecate this function and create a new one?) |
415
|
|
|
|
|
|
|
#FIXME check what happens if go() is called after stopping. |
416
|
|
|
|
|
|
|
#TODO Add an unconditional stop() method |
417
|
|
|
|
|
|
|
#TODO - make callback optional - if the interval is set and the callback is not set, mainloop to return interval seconds after being called. |
418
|
|
|
|
|
|
|
#TODO - Add an idle_timer callback |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub timer_callback(;$) { |
421
|
178
|
|
|
178
|
1
|
57462
|
my $this=shift; |
422
|
178
|
|
|
|
|
374
|
my $interval=shift; |
423
|
178
|
|
|
|
|
289
|
my $callback=shift; |
424
|
178
|
100
|
100
|
|
|
1236
|
if(defined $interval && $interval==0){ |
425
|
2
|
|
|
|
|
14
|
$interval=1; |
426
|
|
|
|
|
|
|
} |
427
|
178
|
|
|
|
|
502
|
$interval=$this->_set("timer_interval", $interval); |
428
|
178
|
|
|
|
|
843
|
$callback=$this->_set("timer_callback", $callback); |
429
|
178
|
|
|
|
|
492
|
return ($interval, $callback); |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head2 parallel( [level] ) |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
Turns on/off running in parallel. |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=head4 Parameters |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=over |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=item * level - 0=serial, 1=parallel. Default is 0 (run in serial). |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=item * Returns - the current or new setting |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=back |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=head4 Usage |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
If running in parallel, MitM starts a new process for each new connection using L. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
Running in serial still allows multiple clients to run concurrently, as so long as none of them have long-running callbacks. If they do, they will block other clients from sending/recieving. |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=cut |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
sub parallel(;$) { |
455
|
5
|
|
|
5
|
1
|
60
|
my $this=shift; |
456
|
5
|
|
|
|
|
25
|
my $parallel=shift; |
457
|
5
|
50
|
|
|
|
40
|
if($parallel){ |
458
|
5
|
|
|
|
|
115
|
$SIG{CLD} = "IGNORE"; |
459
|
|
|
|
|
|
|
} |
460
|
5
|
|
|
|
|
35
|
return $this->_set("parallel", $parallel); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head2 serial( [level] ) |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
Turns on/off running in serial |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=head4 Parameters |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=over |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=item * level - 0=parallel, 1=serial. Default is 1, i.e. run in serial. |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=item * Returns - the current or new setting |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=back |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head4 Usage |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
Calling this function with level=$l is exactly equivalent to calling parallel with level=!$l. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
If running in parallel, MitM starts a new process for each new connection using L. |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
Running in serial, which is the default, still allows multiple clients to run concurrently, as so long as none of them have long-running callbacks. If they do, they will block other clients from sending/recieving. |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=cut |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
sub serial(;$) { |
488
|
0
|
|
|
0
|
1
|
0
|
my $this=shift; |
489
|
0
|
|
|
|
|
0
|
my $level=shift; |
490
|
0
|
0
|
|
|
|
0
|
my $parallel = $this->parallel(defined $level ? ! $level : undef); |
491
|
0
|
0
|
|
|
|
0
|
return $parallel ? 0 : 1; |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=head2 log_file( [log_file_name] ] ) |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
log_file() sets, or clears, a log file. |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
=head4 Parameters |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
=over |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
=item * log_file_name - the name of the log file to be appended to. Passing "" disables logging. Passing nothing, or undef, returns the current log filename without change. |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=item * Returns - log file name |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=back |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head4 Usage |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
The log file contains a record of connects and disconnects and messages as sent back and forwards. Log entries are timestamped. If the log file already exists, it is appended to. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
The default timestamp is "hh:mm:ss", eg 19:49:43 - see mydate() and hhmmss(). |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=cut |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
sub log_file(;$) { |
517
|
18
|
|
|
18
|
1
|
108
|
my $this=shift; |
518
|
18
|
|
|
|
|
36
|
my $new_log_file=shift; |
519
|
18
|
50
|
|
|
|
486
|
if(defined $new_log_file){ |
520
|
18
|
50
|
|
|
|
90
|
if(!$new_log_file){ |
521
|
0
|
0
|
|
|
|
0
|
if($this->{LOGFILE}){ |
522
|
0
|
|
|
|
|
0
|
close($this->{LOGFILE}); |
523
|
0
|
|
|
|
|
0
|
$this->{log_file}=$this->{LOGFILE}=undef; |
524
|
0
|
0
|
|
|
|
0
|
print "Logging turned off\n" if $this->{verbose}; |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
}else{ |
527
|
18
|
|
|
|
|
36
|
my $LOGFILE; |
528
|
18
|
50
|
|
|
|
918
|
if( open($LOGFILE, ">>$new_log_file") ) { |
529
|
18
|
|
|
|
|
72
|
binmode($LOGFILE); |
530
|
18
|
|
|
|
|
270
|
$LOGFILE->autoflush(1); # TODO make this configurable? |
531
|
18
|
|
|
|
|
1044
|
$this->{log_file}=$new_log_file; |
532
|
18
|
|
|
|
|
54
|
$this->{LOGFILE}=$LOGFILE; |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
else { |
535
|
0
|
0
|
|
|
|
0
|
print "Failed to open $new_log_file for logging: $!" if $this->{verbose}; |
536
|
|
|
|
|
|
|
} |
537
|
18
|
50
|
33
|
|
|
342
|
print "Logging to $this->{log_file}\n" if $this->{verbose} && $this->{log_file}; |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
} |
540
|
18
|
|
|
|
|
54
|
return $this->{log_file}; |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=head2 stop_when_idle( boolean ) |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
Wait for remaining children to exit, then exit |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=head4 Parameters |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=over |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=item * flag - whether to exit when idle, or not. The default is true (exit when idle). |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=item * Returns the current status (true=exit when idle, false=keep running) |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=back |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=head4 Usage |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
Causes MitM or Server to return from go() once its last child exits. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
If L is called after stop_when_idle() then L only takes effect after at least one child has been created. |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
MitM or Server will exit immediately if there are currently no children or if MitM or Server is running in parrallel. |
564
|
|
|
|
|
|
|
Otherwise it will stop accepting new children and exit when the last child exits. |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=cut |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
sub stop_when_idle |
569
|
|
|
|
|
|
|
{ |
570
|
163
|
|
|
163
|
1
|
2613
|
my $this=shift; |
571
|
163
|
100
|
|
|
|
718
|
if($this->{parent}){ |
572
|
13
|
|
|
|
|
472
|
return $this->{parent}->stop_when_idle(@_); |
573
|
|
|
|
|
|
|
}else{ |
574
|
150
|
|
100
|
|
|
1525
|
my $stop_when_idle=shift||1; |
575
|
150
|
|
|
|
|
641
|
my $retval= $this->_set("stop_when_idle", $stop_when_idle); |
576
|
150
|
|
50
|
|
|
1006
|
$this->log("stop_when_idle set to: ",$this->{stop_when_idle}||'--undefined--'); |
577
|
150
|
|
|
|
|
472
|
return $retval; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=head2 defrag_delay( [delay] ) |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
Use a small delay to defragment messages |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=head4 Parameters |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=over |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=item * Delay - seconds to wait - fractions of a second are OK |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=item * Returns - the current setting. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=back |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=head4 Usage |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
Under TCPIP, there is always a risk that large messages will be fragmented in transit, and that messages sent close together may be concatenated. |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
Client/Server programs have to know how to turn a stream of bytes into the messages they care about, either by repeatedly reading until they see an end-of-message (defragmenting), or by splitting the bytes read into multiple messages (deconcatenating). |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
For our purposes, fragmentation and concatenation can make our logs harder to read. |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
Without knowning the protocol, it's not possible to tell for sure if a message has been fragmented or concatenated. |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
A small delay can be used as a way of defragmenting messages, although it increases the risk that separate messages may be concatenated. |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
Eg: |
608
|
|
|
|
|
|
|
$MitM->defrag_delay( 0.1 ); |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
=cut |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
sub defrag_delay(;$) { |
613
|
0
|
|
|
0
|
1
|
0
|
my $this=shift; |
614
|
0
|
|
|
|
|
0
|
my $defrag_delay=shift; |
615
|
0
|
|
|
|
|
0
|
return $this->_set("defrag_delay",$defrag_delay); |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
=head2 protocol( [protocol] ) |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
Set protocol to tcp (default) or udp |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
=head4 Parameters |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=over |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=item * protocol - either 'tcp' or 'udp' |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=item * Returns - the current setting. |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=back |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head4 Usage |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
Eg: |
635
|
|
|
|
|
|
|
$MitM->protocol( 'udp' ); |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
=cut |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
sub protocol(;$) { |
640
|
0
|
|
|
0
|
1
|
0
|
my $this=shift; |
641
|
0
|
|
|
|
|
0
|
my $protocol=shift; |
642
|
0
|
|
|
|
|
0
|
return $this->_set("protocol",$protocol); |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=head1 SUPPORTING SUBROUTINES/METHODS |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
The remaining functions are supplimentary. new_server() and new_client() provide a simple client and a simple server that may be useful in some circumstances. The other methods are only likely to be useful if you choose to bypass go() in order to, for example, have more control over messages being received and sent. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head2 new_server( local_port_num, callback_function ) |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
Returns a very simple server, adequate for simple tasks. |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=head4 Parameters |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
=over |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=item * local_port_num - the Port number to listen on |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
=item * callback_function - a reference to a function to be called when a message arrives - must return a response which will be returned to the client |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=item * Returns - a new server |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
=back |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
=head4 Usage |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
sub do_something($){ |
668
|
|
|
|
|
|
|
my $in = shift; |
669
|
|
|
|
|
|
|
my $out = ... |
670
|
|
|
|
|
|
|
return $out; |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
my $server = Net::MitM->new_server(8080,\&do_something) || die; |
674
|
|
|
|
|
|
|
$server->go(); |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
The server returned by new_server has a method, go(), which tells it to start receiving messages (arbitrary strings). Each string is passed to the callback_function, which is expected to return a single string, being the response to be returned to caller. If the callback returns undef, the original message will be echoed back to the client. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
go() does not return. You may want to L before calling it. |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
See, for another example, samples/echo_server.pl in the MitM distribution. |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=cut |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
sub new_server($%) { |
685
|
35
|
|
|
35
|
1
|
133283
|
my $class=shift; |
686
|
35
|
|
|
|
|
533
|
my $this=_new(); |
687
|
35
|
50
|
|
|
|
331
|
$this->{local_port_num} = shift or croak "no port number passed"; |
688
|
35
|
50
|
|
|
|
397
|
$this->{server_callback} = shift or croak "no callback passed"; |
689
|
35
|
|
|
|
|
208
|
return bless $this, $class; |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=head2 new_client( remote_host, remote_port_num ) |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
new_client() returns a very simple client, adequate for simple tasks |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
The client returned has a method, send_and_receive(), which sends a message and receives a response. |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
Alternately, send_to_server() may be used to send a message, and receive_from_server() may be used to receive a message. |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
Explicitly calling connect_to_server() is optional, but may be useful if you want to be sure the server is reachable. If you don't call it explicitly, it will be called the first time a message is sent. |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=head4 Parameters |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=over |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=item * remote_ip_address - the hostname/IP address of the server |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=item * remote_port_num - the Port number of the server |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=item * Returns - a new client object |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=back |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=head4 Usage |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
my $client = Net::MitM->new_client("localhost", 8080) || die("failed to start test client: $!"); |
717
|
|
|
|
|
|
|
$client->connect_to_server(); |
718
|
|
|
|
|
|
|
my $resp = $client->send_and_receive("hello"); |
719
|
|
|
|
|
|
|
... |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
See, for example, samples/client.pl or samples/clients.pl in the MitM distribution. |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
=cut |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
sub new_client($%) { |
726
|
306
|
|
|
306
|
1
|
423654
|
my $class=shift; |
727
|
306
|
|
|
|
|
4317
|
my $this=_new(); |
728
|
306
|
50
|
|
|
|
2503
|
$this->{remote_ip_address} = shift or croak "remote hostname/ip address missing"; |
729
|
306
|
50
|
|
|
|
1647
|
$this->{remote_port_num} = shift or croak "remote port number missing"; |
730
|
306
|
|
|
|
|
35932
|
return bless $this, $class; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
#FIXME repetition in doco - clean it up |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
=head2 log( string ) |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
log is a convenience function that prefixes output with a timestamp and PID information then writes to log_file. |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=head4 Parameters |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=over |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
=item * string(s) - one or more strings to be logged |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
=item * Returns --none-- |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
=back |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
=head4 Usage |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
log is a convenience function that prefixes output with a timestamp and PID information then writes to log_file. |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
log() does nothing unless log_file is set, which by default, it is not. |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
=cut |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub log($@) |
758
|
|
|
|
|
|
|
{ |
759
|
2631
|
|
|
2631
|
1
|
9688
|
my $this=shift; |
760
|
2631
|
100
|
|
|
|
10175
|
printf {$this->{LOGFILE}} "%u/%s %s\n", $$, $this->{mydate}(), "@_" if $this->{LOGFILE}; |
|
368
|
|
|
|
|
1269
|
|
761
|
2631
|
|
|
|
|
10287
|
return undef; |
762
|
|
|
|
|
|
|
} |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
=head2 echo( string(s) ) |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
Prints to stdout and/or the logfile |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=head4 Parameters |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=over |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
=item * string(s) - one or more strings to be echoed (printed) |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
=item * Returns --none-- |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=back |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
=head4 Usage |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
echo() is a convenience function that prefixes output with a timestamp and PID information and prints it to standard out if verbose is set and, if log_file() has been set, logs it to the log file. |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=cut |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
sub echo($@) |
785
|
|
|
|
|
|
|
{ |
786
|
1294
|
|
|
1294
|
1
|
2951
|
my $this=shift; |
787
|
1294
|
|
|
|
|
24132
|
$this->log("@_"); |
788
|
1294
|
50
|
|
|
|
3968
|
return if !$this->{verbose}; |
789
|
1294
|
50
|
|
|
|
3572
|
confess "Did not expect not to have a name" if !$this->{name}; |
790
|
1294
|
100
|
|
|
|
9757
|
if($_[0] =~ m/^[<>]{3}$/){ |
791
|
543
|
|
|
|
|
918
|
my $prefix=shift; |
792
|
543
|
|
|
|
|
1239
|
my $msg=join "", @_; |
793
|
543
|
|
|
|
|
1563
|
chomp $msg; |
794
|
543
|
|
|
|
|
8892
|
printf("%s: %u/%s %s %s\n", $this->{name}, $$, $this->{mydate}(), $prefix, $msg); |
795
|
|
|
|
|
|
|
}else{ |
796
|
751
|
|
|
|
|
4202
|
printf("%s: %u/%s\n", $this->{name}, $$, join(" ", $this->{mydate}(), @_)); |
797
|
|
|
|
|
|
|
} |
798
|
1294
|
|
|
|
|
3609
|
return undef; |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
=head2 send_to_server( string(s) ) |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
send_to_server() sends a message to the server |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=head4 Parameters |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
=over |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
=item * string(s) - one or more strings to be sent |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
=item * Return: true if successful |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
=back |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
=head4 Usage |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
If a callback is set, it will be called before the message is sent. |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
send_to_server() may 'die' if it detects a failure to send. |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=cut |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
sub _do_callback($$) |
824
|
|
|
|
|
|
|
{ |
825
|
784
|
|
|
784
|
|
5971
|
my $this=shift; |
826
|
784
|
|
|
|
|
69373
|
my $direction = shift; |
827
|
784
|
|
|
|
|
1298
|
my $msg = shift; |
828
|
784
|
|
|
|
|
109317
|
my $callback = $this->{$direction."_callback"}; |
829
|
784
|
100
|
|
|
|
2483
|
if($callback){ |
830
|
295
|
50
|
|
|
|
952
|
$this->echo("calling $direction callback ($msg)\n") if $this->{verbose}>1; |
831
|
295
|
|
|
|
|
1947
|
my $new_msg = $callback->($msg,$this); |
832
|
|
|
|
|
|
|
#warn "~~~ ",$new_msg||"--undef--","\n"; |
833
|
295
|
|
100
|
|
|
4876
|
my $callback_behaviour = $this->{$direction."_callback_behaviour"} || 'conditional'; |
834
|
|
|
|
|
|
|
#warn ("callback behaviour is ($callback_behaviour)\n") if $this->{verbose}>1; |
835
|
295
|
100
|
66
|
|
|
2187
|
if($callback_behaviour eq 'modify' || ($callback_behaviour ne 'readonly' && defined $new_msg)){ |
|
|
|
66
|
|
|
|
|
836
|
25
|
|
|
|
|
82
|
$msg = $new_msg; |
837
|
|
|
|
|
|
|
} |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
#warn "+++ ",$msg||"--undef--","\n"; |
840
|
784
|
|
|
|
|
3023
|
return $msg; |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
sub _logmsg |
844
|
|
|
|
|
|
|
{ |
845
|
543
|
|
|
543
|
|
1058
|
my $this = shift; |
846
|
543
|
|
|
|
|
1084
|
my $direction = shift; |
847
|
543
|
|
|
|
|
861
|
my $msg = shift; |
848
|
543
|
50
|
|
|
|
2071
|
if($this->{verbose}>1){ |
849
|
0
|
|
|
|
|
0
|
$this->echo($direction,"(".length($msg)." bytes) {$msg}\n"); |
850
|
|
|
|
|
|
|
}else{ |
851
|
|
|
|
|
|
|
# don't print the whole message by default, in case it is either binary &/or long |
852
|
543
|
|
|
|
|
2979
|
$this->echo($direction,"(".length($msg)." bytes)\n"); |
853
|
543
|
|
|
|
|
3399
|
$this->log($direction," {{{$msg}}}\n"); |
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
} |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
sub send_to_server($@) |
858
|
|
|
|
|
|
|
{ |
859
|
469
|
|
|
469
|
1
|
611180
|
my $this = shift; |
860
|
469
|
|
|
|
|
1835
|
my $msg = shift; |
861
|
469
|
|
|
|
|
1799
|
$this->connect_to_server(); |
862
|
469
|
|
|
|
|
2990
|
$msg = $this->_do_callback( 'client_to_server', $msg ); |
863
|
469
|
100
|
|
|
|
3529
|
if(!defined $msg){ |
864
|
2
|
50
|
|
|
|
11
|
warn "client to server callback says no\n" if $this->{verbose}>1; |
865
|
2
|
|
|
|
|
5
|
return undef; |
866
|
|
|
|
|
|
|
} |
867
|
467
|
|
|
|
|
1946
|
$this->_logmsg(">>>",$msg); |
868
|
467
|
50
|
|
|
|
1558
|
confess "SERVER being null was unexpected" if !$this->{SERVER}; |
869
|
467
|
50
|
|
|
|
849
|
print({$this->{SERVER}} $msg) || die "Can't send to server: $?"; |
|
467
|
|
|
|
|
132744
|
|
870
|
467
|
|
|
|
|
1314
|
return undef; |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
=head2 send_to_client( string(s) ) |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
Sends a message to the client |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
=head4 Parameters |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
=over |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
=item * string(s) - one or more strings to be sent |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
=item * Return: true if successful |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
=back |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
=head4 Usage |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
If a callback is set, it will be called before the message is sent. |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
=cut |
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
sub _send_to_client($@) |
894
|
|
|
|
|
|
|
{ |
895
|
76
|
|
|
76
|
|
130
|
my $this = shift; |
896
|
76
|
|
|
|
|
153
|
my $msg = shift; |
897
|
76
|
|
|
|
|
340
|
$this->_logmsg("<<<",$msg); |
898
|
76
|
|
|
|
|
138
|
return print({$this->{CLIENT}} $msg); |
|
76
|
|
|
|
|
39117
|
|
899
|
|
|
|
|
|
|
} |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
sub send_to_client($@) |
902
|
|
|
|
|
|
|
{ |
903
|
76
|
|
|
76
|
1
|
628
|
my $this = shift; |
904
|
76
|
|
|
|
|
160
|
my $msg = shift; |
905
|
76
|
|
|
|
|
552
|
$msg = $this->_do_callback( 'server_to_client', $msg ); |
906
|
76
|
50
|
|
|
|
335
|
if(!defined $msg){ |
907
|
0
|
0
|
|
|
|
0
|
warn "server to client callback says no\n" if $this->{verbose}>1; |
908
|
|
|
|
|
|
|
return undef |
909
|
0
|
|
|
|
|
0
|
} |
910
|
76
|
|
|
|
|
304
|
return $this->_send_to_client($msg); |
911
|
|
|
|
|
|
|
} |
912
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
=head2 receive_from_server( ) |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
Receives a message from the server |
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
=head4 Parameters |
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
=over |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
=item * --none-- |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
=item * Returns - the message read, or undef if the server disconnected. |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
=back |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
=head4 Usage |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
Blocks until a message is received. |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
This method used to be called read_from_server(), and may still be called via that name. |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
=cut |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
sub receive_from_server() |
936
|
|
|
|
|
|
|
{ |
937
|
461
|
|
|
461
|
1
|
220016
|
my $this=shift; |
938
|
461
|
|
|
|
|
821
|
my $msg; |
939
|
461
|
50
|
|
|
|
4315493
|
sysread($this->{SERVER},$msg,100000) or confess "Fatal: sysread failed: $!"; |
940
|
461
|
50
|
|
|
|
1974
|
if(length($msg) == 0) |
941
|
|
|
|
|
|
|
{ |
942
|
0
|
|
|
|
|
0
|
$this->echo("Server disconnected\n"); |
943
|
0
|
|
|
|
|
0
|
return undef; |
944
|
|
|
|
|
|
|
} |
945
|
461
|
|
|
|
|
3303
|
return $msg; |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
=head2 read_from_server( ) [Deprecated] |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
use instead: receive_from_server( ) |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
=cut |
953
|
|
|
|
|
|
|
|
954
|
2
|
|
|
2
|
1
|
2292
|
sub read_from_server() { my $this=shift;return $this->receive_from_server(); } |
|
2
|
|
|
|
|
8
|
|
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
=head2 send_and_receive( ) |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
Sends a message to the server and receives a response |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
=head4 Parameters |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
=over |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
=item * the message(s) to be sent |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=item * Returns - message read, or undef if the server disconnected. |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
=back |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
=head4 Usage |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
Blocks until a message is received. If the server does not always return exactly one message for each message it receives, send_and_receive() will either concatenate messages or block forever. |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
=cut |
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
sub send_and_receive($) |
977
|
|
|
|
|
|
|
{ |
978
|
424
|
|
|
424
|
1
|
487674
|
my $this=shift; |
979
|
424
|
|
|
|
|
3614
|
$this->send_to_server(@_); |
980
|
424
|
|
|
|
|
1502
|
return $this->receive_from_server(); |
981
|
|
|
|
|
|
|
} |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
=head2 connect_to_server( ) |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
Connects to the server |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
=head4 Parameters |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
=over |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
=item * --none-- |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
=item * Returns true if successful |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
=back |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
=head4 Usage |
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
This method is automatically called when needed. It only needs to be called directly if you want to be sure that the connection to server succeeds before proceeding. |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
Changed in v0.03_01: return true/false if connect successful/unsuccessful. Previously died if connect fails. Failure to resolve remote internet address/port address is still fatal. |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
=cut |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
# TODO would be nice to have a way to specify backup server(s) if 1st connection fails. Also nice to have a way to specify round-robin servers for load balancing. |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
sub _socket($) |
1008
|
|
|
|
|
|
|
{ |
1009
|
493
|
|
|
493
|
|
765
|
my $this=shift; |
1010
|
493
|
|
|
|
|
3189
|
my $socket=shift; |
1011
|
493
|
|
50
|
|
|
4892
|
my $protocol = $this->{protocol}||'tcp'; |
1012
|
493
|
50
|
|
|
|
253395
|
my $proto = getprotobyname($protocol) or die "Can't getprotobyname\n"; |
1013
|
493
|
50
|
|
|
|
2240
|
my $sock = $protocol eq 'udp' ? SOCK_DGRAM : SOCK_STREAM ; |
1014
|
|
|
|
|
|
|
|
1015
|
493
|
50
|
|
|
|
28418
|
socket($this->{$socket}, PF_INET, $sock, $proto) or confess "Fatal: Can't create $protocol socket: $!"; |
1016
|
|
|
|
|
|
|
} |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
sub connect_to_server() |
1019
|
|
|
|
|
|
|
{ |
1020
|
489
|
|
|
489
|
1
|
837
|
my $this=shift; |
1021
|
489
|
100
|
|
|
|
1738
|
return if $this->{SERVER}; |
1022
|
324
|
|
|
|
|
987
|
$this->_socket("SERVER"); |
1023
|
324
|
50
|
|
|
|
1174
|
confess "remote_ip_address unexpectedly not known" if !$this->{remote_ip_address}; |
1024
|
324
|
50
|
|
|
|
104756
|
my $remote_ip_aton = inet_aton( $this->{remote_ip_address} ) or croak "Fatal: Cannot resolve internet address: '$this->{remote_ip_address}'\n"; |
1025
|
324
|
50
|
|
|
|
5688
|
my $remote_port_address = sockaddr_in($this->{remote_port_num}, $remote_ip_aton ) or die "Fatal: Can't get port address: $!"; # TODO Is die the way to go here? Not sure it isn't. Not sure it is. |
1026
|
324
|
|
|
|
|
106957
|
$this->echo("Connecting to $this->{remote_ip_address}\:$this->{remote_port_num} [verbose=$this->{verbose}]\n"); |
1027
|
324
|
100
|
|
|
|
542859
|
my $connect = connect($this->{SERVER}, $remote_port_address) or return undef; |
1028
|
323
|
|
|
|
|
6123
|
$this->{SERVER}->autoflush(1); |
1029
|
323
|
|
|
|
|
34364
|
binmode($this->{SERVER}); |
1030
|
323
|
|
|
|
|
945
|
return $connect; |
1031
|
|
|
|
|
|
|
} |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
=head2 disconnect_from_server( ) |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
Disconnects from the server |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
=head4 Parameters |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
=over |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
=item * --none-- |
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
=item * Returns --none-- |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
=back |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
=head4 Usage |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
disconnect_from_server closes any connections. |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
It is only intended to be called on clients. |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
For MitM, like for any server, disconnection is best triggered by the other party disconnecting, not by the server. If a server disconnects while it has an active client connection open and exits or otherwise stops listening, it will not be able to reopen the same port for listening until the old connection has timed out which can take up to a few minutes. |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
=cut |
1056
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
sub disconnect_from_server() |
1058
|
|
|
|
|
|
|
{ |
1059
|
292
|
|
|
292
|
1
|
24078
|
my $this=shift; |
1060
|
292
|
|
|
|
|
2031
|
$this->log("initiating disconnect"); |
1061
|
292
|
|
|
|
|
861
|
$this->_destroy(); |
1062
|
292
|
|
|
|
|
6229
|
return undef; |
1063
|
|
|
|
|
|
|
} |
1064
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
sub _pause($){ |
1066
|
|
|
|
|
|
|
# warning - select may return early if, for eg, process catches a signal (if it survives the signal) |
1067
|
0
|
|
|
0
|
|
0
|
select undef,undef,undef,shift; |
1068
|
0
|
|
|
|
|
0
|
return undef; |
1069
|
|
|
|
|
|
|
} |
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
sub _message_from_client_to_server(){ # TODO Too many too similar sub names, some of which maybe should be public |
1072
|
122
|
|
|
122
|
|
287
|
my $this=shift; |
1073
|
|
|
|
|
|
|
# optional sleep to reduce risk of split messages |
1074
|
122
|
50
|
|
|
|
429
|
_pause($this->{defrag_delay}) if $this->{defrag_delay}; |
1075
|
|
|
|
|
|
|
# It would be possible to be more agressive by repeatedly waiting until there is a break, but that would probably err too much towards concatenating seperate messages - especially under load. |
1076
|
122
|
|
|
|
|
216
|
my $msg; |
1077
|
122
|
|
|
|
|
6594
|
sysread($this->{CLIENT},$msg,10000); |
1078
|
|
|
|
|
|
|
# (0 length message means connection closed) |
1079
|
122
|
100
|
|
|
|
464
|
if(length($msg) == 0) { |
1080
|
44
|
|
|
|
|
223
|
$this->echo("Client disconnected\n"); |
1081
|
44
|
|
|
|
|
286
|
$this->_destroy(); |
1082
|
44
|
|
|
|
|
115
|
return undef; |
1083
|
|
|
|
|
|
|
} |
1084
|
|
|
|
|
|
|
# Send message to server, if any. Else 'send' to callback function and return result to client. |
1085
|
78
|
100
|
|
|
|
669
|
if($this->{SERVER}){ |
|
|
50
|
|
|
|
|
|
1086
|
35
|
|
|
|
|
263
|
$this->send_to_server($msg); |
1087
|
|
|
|
|
|
|
}elsif($this->{server_callback}){ |
1088
|
43
|
|
|
|
|
231
|
$this->send_to_client( $this->{server_callback}($msg) ); |
1089
|
|
|
|
|
|
|
}else{ |
1090
|
0
|
|
|
|
|
0
|
confess "$this->{name}: Did not expect to have neither a connection to a SERVER nor a server_callback"; |
1091
|
|
|
|
|
|
|
} |
1092
|
78
|
|
|
|
|
226
|
return undef; |
1093
|
|
|
|
|
|
|
} |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
=head2 graceful_shut_down( ) |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
Shut down the server gracefully |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
=head4 Parameters |
1100
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
=over |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
=item * --none-- |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
=item * Returns --none-- |
1106
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
=back |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
=head4 Usage |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
graceful_shut_down closes the LISTEN socket so that no more clients will be accepted. When the last client has exited, mainloop will exit. |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
If running in parallel mode, graceful_shut_down will take effect immediately, the children will keep running. This might change in a future release. |
1114
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
=cut |
1116
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
sub graceful_shut_down() |
1118
|
|
|
|
|
|
|
{ |
1119
|
0
|
|
|
0
|
1
|
0
|
my $this=shift; |
1120
|
0
|
|
|
|
|
0
|
$this->log("initiating disconnect"); |
1121
|
0
|
|
|
|
|
0
|
$this->_destroy_fh("LISTEN"); |
1122
|
0
|
|
|
|
|
0
|
return undef; |
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
sub _message_from_server_to_client(){ # TODO Too many too similar sub names |
1126
|
33
|
|
|
33
|
|
110
|
my $this=shift; |
1127
|
|
|
|
|
|
|
# sleep to avoid splitting messages |
1128
|
33
|
50
|
|
|
|
135
|
_pause($this->{defrag_delay}) if $this->{defrag_delay}; |
1129
|
|
|
|
|
|
|
# Read from SERVER and copy to CLIENT |
1130
|
33
|
|
|
|
|
571
|
my $msg = $this->receive_from_server(); |
1131
|
33
|
50
|
|
|
|
147
|
if(!defined $msg){ |
1132
|
0
|
|
|
|
|
0
|
$this->_destroy(); |
1133
|
0
|
|
|
|
|
0
|
return undef; |
1134
|
|
|
|
|
|
|
} |
1135
|
33
|
|
|
|
|
2141
|
$this->send_to_client($msg); |
1136
|
33
|
|
|
|
|
80
|
return undef; |
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
sub _cull_child() |
1140
|
|
|
|
|
|
|
{ |
1141
|
43
|
50
|
|
43
|
|
167
|
my $this=shift or die; |
1142
|
43
|
50
|
|
|
|
155
|
my $child=shift or die; |
1143
|
43
|
|
|
|
|
95
|
for my $i (0 .. @{$this->{children}}){ |
|
43
|
|
|
|
|
1249
|
|
1144
|
43
|
50
|
|
|
|
259
|
if($child==$this->{children}[$i]){ |
1145
|
43
|
50
|
|
|
|
253
|
$this->echo("Child $child->{name} is done, cleaning it up") if $this->{verbose}>1; |
1146
|
43
|
|
|
|
|
95
|
splice @{$this->{children}}, $i,1; |
|
43
|
|
|
|
|
204
|
|
1147
|
43
|
|
|
|
|
123
|
return; |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
} |
1150
|
0
|
|
|
|
|
0
|
confess "Child $child->{name} is finished, but I can't find it to clean it up"; |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
# _main_loop is called both by listeners and by forked children. When called by listeners, it also includes any children running in serial |
1154
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
my $warned_about_deprecation=0; |
1156
|
|
|
|
|
|
|
sub _main_loop() |
1157
|
|
|
|
|
|
|
{ |
1158
|
25
|
|
|
25
|
|
197
|
my $this=shift; |
1159
|
25
|
|
|
|
|
697
|
my $last_time; |
1160
|
|
|
|
|
|
|
my $target_time; |
1161
|
25
|
100
|
66
|
|
|
1161
|
if($this->{timer_interval}&&$this->{timer_callback}){ |
1162
|
23
|
|
|
|
|
722
|
$last_time=time(); |
1163
|
23
|
|
|
|
|
384
|
$target_time=$last_time+$this->{timer_interval}; |
1164
|
|
|
|
|
|
|
} |
1165
|
|
|
|
|
|
|
# Main Loop |
1166
|
25
|
|
|
|
|
72
|
MAINLOOP: while(1) |
1167
|
|
|
|
|
|
|
{ |
1168
|
|
|
|
|
|
|
# Build file descriptor list for select call |
1169
|
226
|
|
|
|
|
1196
|
my $rin = ""; |
1170
|
226
|
100
|
|
|
|
917
|
if($this->{LISTEN}){ |
1171
|
219
|
50
|
|
|
|
4633
|
confess "LISTEN is unexpectedly not a filehandle" if !fileno($this->{LISTEN}); |
1172
|
219
|
|
|
|
|
1882
|
vec($rin, fileno($this->{LISTEN}), 1) = 1; |
1173
|
|
|
|
|
|
|
} |
1174
|
226
|
|
|
|
|
869
|
foreach my $each ($this, @{$this->{children}}) { |
|
226
|
|
|
|
|
1510
|
|
1175
|
517
|
100
|
|
|
|
9466
|
vec($rin, fileno($each->{CLIENT}), 1) = 1 if $each->{CLIENT}; # TODO if no client, child should probably be dead |
1176
|
517
|
100
|
|
|
|
9269
|
vec($rin, fileno($each->{SERVER}), 1) = 1 if $each->{SERVER}; |
1177
|
|
|
|
|
|
|
} |
1178
|
|
|
|
|
|
|
# and listen... |
1179
|
226
|
|
|
|
|
1295
|
my $rout = $rin; |
1180
|
226
|
|
|
|
|
380
|
my $delay; |
1181
|
226
|
100
|
|
|
|
968
|
if($this->{timer_interval}){ |
1182
|
215
|
100
|
|
|
|
1897
|
if(time() > $target_time){ |
1183
|
18
|
|
|
|
|
313
|
my $resp = $this->{timer_callback}($this); |
1184
|
17
|
100
|
|
|
|
92675
|
if($resp){ |
1185
|
|
|
|
|
|
|
# TODO Add a deprecated warning? |
1186
|
|
|
|
|
|
|
}else{ |
1187
|
7
|
|
|
|
|
28
|
last MAINLOOP; |
1188
|
|
|
|
|
|
|
} |
1189
|
10
|
|
|
|
|
56
|
$last_time=$target_time; |
1190
|
10
|
|
|
|
|
48
|
$target_time+=$this->{timer_interval}; |
1191
|
|
|
|
|
|
|
} |
1192
|
207
|
|
|
|
|
860
|
$delay=$target_time-time(); |
1193
|
207
|
50
|
|
|
|
664
|
$delay=0 if($delay<0); |
1194
|
207
|
50
|
|
|
|
652
|
$this->echo("delay=$delay") if $this->{verbose} > 1; |
1195
|
|
|
|
|
|
|
}else{ |
1196
|
11
|
|
|
|
|
57
|
$delay=undef; |
1197
|
|
|
|
|
|
|
} |
1198
|
218
|
|
|
|
|
15153711
|
my $status=select( $rout, "", "", $delay ); |
1199
|
218
|
50
|
|
|
|
1499
|
if($status==-1){ |
1200
|
0
|
|
|
|
|
0
|
warn "something happened - were we signalled? if so, why do we live?\n"; |
1201
|
|
|
|
|
|
|
} |
1202
|
218
|
100
|
100
|
|
|
3401
|
if( $this->{LISTEN} && vec($rout,fileno($this->{LISTEN}),1) ) { |
1203
|
45
|
|
|
|
|
624
|
my $child = $this->_spawn_child(); |
1204
|
44
|
100
|
|
|
|
209
|
push @{$this->{children}}, $child if $child; |
|
43
|
|
|
|
|
225
|
|
1205
|
44
|
|
|
|
|
169
|
next; |
1206
|
|
|
|
|
|
|
} |
1207
|
173
|
|
|
|
|
369
|
CHILDREN: foreach my $each($this, @{$this->{children}}) { |
|
173
|
|
|
|
|
997
|
|
1208
|
368
|
50
|
66
|
|
|
15092
|
confess "We have a child with no CLIENT\n" if !$each->{CLIENT} && $each!=$this; |
1209
|
368
|
100
|
100
|
|
|
3965
|
if($each->{CLIENT} && vec($rout,fileno($each->{CLIENT}),1) ) { |
1210
|
122
|
|
|
|
|
1873
|
$each->_message_from_client_to_server(); # TODO Too many too similar sub names |
1211
|
122
|
100
|
|
|
|
433
|
if(!$each->{CLIENT}){ |
1212
|
44
|
|
|
|
|
147
|
$each->log("No Client\n"); |
1213
|
|
|
|
|
|
|
# client has disconnected |
1214
|
44
|
100
|
|
|
|
555
|
if($each==$this){ |
1215
|
|
|
|
|
|
|
# we are the child - OK to exit |
1216
|
1
|
|
|
|
|
4
|
$each->log("We are the child"); |
1217
|
1
|
|
|
|
|
4
|
return; |
1218
|
|
|
|
|
|
|
}else{ |
1219
|
|
|
|
|
|
|
# we are the parent - clean up child |
1220
|
43
|
|
|
|
|
270
|
$each->log("We are the parent"); |
1221
|
43
|
|
100
|
|
|
352
|
$each->log("stop_when_idle is: ",$this->{stop_when_idle}||'--undefined--'); |
1222
|
43
|
|
|
|
|
73
|
$each->log("number of children (before cull): ",scalar(@{$this->{children}})); |
|
43
|
|
|
|
|
220
|
|
1223
|
43
|
|
|
|
|
204
|
$this->_cull_child($each); |
1224
|
43
|
|
|
|
|
70
|
$each->log("number of children (after cull): ",scalar(@{$this->{children}})); |
|
43
|
|
|
|
|
166
|
|
1225
|
|
|
|
|
|
|
# keep going? |
1226
|
43
|
100
|
66
|
|
|
314
|
if($this->{stop_when_idle} && (!@{$this->{children}})){ |
|
15
|
|
|
|
|
111
|
|
1227
|
15
|
|
|
|
|
73
|
$this->log("idle exiting mainloop"); |
1228
|
15
|
|
|
|
|
51
|
return undef; |
1229
|
|
|
|
|
|
|
} |
1230
|
28
|
50
|
|
|
|
90
|
$each->log("continuing: ",$this->{stop_when_idle}?'y':'n',!@{$this->{children}}); |
|
28
|
|
|
|
|
100
|
|
1231
|
28
|
|
|
|
|
653
|
last CHILDREN; # _cull_child impacts the children array - not safe to continue without regenerating rout |
1232
|
|
|
|
|
|
|
} |
1233
|
|
|
|
|
|
|
}else{ |
1234
|
78
|
50
|
|
|
|
319
|
$each->echo("We still have a client") if $this->{verbose}>1; |
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
} |
1237
|
324
|
100
|
100
|
|
|
2425
|
if($each->{SERVER} && vec($rout,fileno($each->{SERVER}),1) ) { |
1238
|
33
|
|
|
|
|
264
|
$each->_message_from_server_to_client(); # TODO Too many too similar sub names |
1239
|
33
|
50
|
|
|
|
542
|
if(!$each->{SERVER}){ |
1240
|
|
|
|
|
|
|
# server has disconnected |
1241
|
0
|
0
|
|
|
|
0
|
if($each==$this){ |
1242
|
|
|
|
|
|
|
# we are the child - OK to exit |
1243
|
0
|
|
|
|
|
0
|
return; #might be better to die or exit at this point instead? |
1244
|
|
|
|
|
|
|
}else{ |
1245
|
0
|
|
|
|
|
0
|
$this->_cull_child($each); |
1246
|
0
|
0
|
0
|
|
|
0
|
if($this->{stop_when_idle} && !@{$this->{children}}){ |
|
0
|
|
|
|
|
0
|
|
1247
|
0
|
|
|
|
|
0
|
$this->log("idle exiting mainloop - server disconnected"); |
1248
|
0
|
|
|
|
|
0
|
return undef; |
1249
|
|
|
|
|
|
|
} |
1250
|
0
|
|
|
|
|
0
|
last CHILDREN; # _cull_child impacts the children array - not safe to continue without regenerating rout |
1251
|
|
|
|
|
|
|
} |
1252
|
|
|
|
|
|
|
} |
1253
|
|
|
|
|
|
|
} |
1254
|
|
|
|
|
|
|
} # foreach CHILDREN |
1255
|
|
|
|
|
|
|
} |
1256
|
7
|
|
|
|
|
28
|
return undef; |
1257
|
|
|
|
|
|
|
} |
1258
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
=head2 hhmmss( ) |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
The default timestamp function - returns localtime in hh:mm:ss format |
1262
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
=head4 Parameters |
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
=over |
1266
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
=item * --none-- |
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
=item * Returns - current time in hh:mm:ss format |
1270
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
=back |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
=head4 Usage |
1274
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
This function is, by default, called when a message is written to the log file. |
1276
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
It may be overridden by calling mydate(). |
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
=cut |
1280
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
sub hhmmss() |
1282
|
|
|
|
|
|
|
{ |
1283
|
1662
|
|
|
1662
|
1
|
171277
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); |
1284
|
1662
|
|
|
|
|
207582
|
return sprintf "%02d:%02d:%02d",$hour,$min,$sec; |
1285
|
|
|
|
|
|
|
} |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
=head2 mydate( ) |
1288
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
Override the standard hh:mm:ss datestamp |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
=head4 Parameters |
1292
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
=over |
1294
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
=item * datestamp_callback - a reference to a function that returns a datestamp |
1296
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
=item * Returns - a reference to the current or updated callback function |
1298
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
=back |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
=head4 Usage |
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
For example: |
1304
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
sub yymmddhhmmss { |
1306
|
|
|
|
|
|
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); |
1307
|
|
|
|
|
|
|
return sprintf "%02d/%02d/%02d %02d:%02d:%02d", |
1308
|
|
|
|
|
|
|
$year+1900,$mon+1,$mday,$hour,$min,$sec; |
1309
|
|
|
|
|
|
|
} |
1310
|
|
|
|
|
|
|
mydate(\&yymmddhhmmss); |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
=cut |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
sub mydate(;$) |
1315
|
|
|
|
|
|
|
{ |
1316
|
0
|
|
|
0
|
1
|
0
|
my $this=shift; |
1317
|
0
|
|
0
|
|
|
0
|
my $mydate=shift||undef; |
1318
|
0
|
0
|
|
|
|
0
|
if(defined $mydate){ |
1319
|
0
|
|
|
|
|
0
|
$this->{mydate} = $mydate; |
1320
|
|
|
|
|
|
|
} |
1321
|
0
|
|
|
|
|
0
|
return $this->{mydate}; |
1322
|
|
|
|
|
|
|
} |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
=head2 listen( ) |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
Listen on local_port and prepare to accept incoming connections |
1327
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
=head4 Parameters |
1329
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
=over |
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
=item * --none-- |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
=item * Return --none-- |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
=back |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
=head4 Usage |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
This method is called by go(). It only needs to be called directly if go() is being bypassed for some reason. |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
=cut |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
sub listen() |
1345
|
|
|
|
|
|
|
{ |
1346
|
192
|
|
|
192
|
1
|
1180
|
my $this=shift; |
1347
|
192
|
100
|
|
|
|
974
|
return if $this->{LISTEN}; |
1348
|
169
|
100
|
|
|
|
3044
|
$this->echo(sprintf "Server %u listening on port %d (%s)\n",$$,$this->{local_port_num},$this->{parallel}?"parallel":"serial"); |
1349
|
169
|
|
|
|
|
696
|
$this->_socket("LISTEN"); |
1350
|
169
|
50
|
|
|
|
1128
|
bind($this->{LISTEN}, sockaddr_in($this->{local_port_num}, INADDR_ANY)) or confess "Fatal: $this->{name} can't bind LISTEN socket [$this->{LISTEN}] to $this->{local_port_num}: (",$!+0,") $!"; |
1351
|
169
|
50
|
|
|
|
5587
|
listen($this->{LISTEN},1) or confess "Fatal: Can't listen to socket: $!"; |
1352
|
169
|
|
|
|
|
1427
|
$this->echo("Waiting on port $this->{local_port_num}\n"); |
1353
|
169
|
|
|
|
|
677
|
return undef; |
1354
|
|
|
|
|
|
|
} |
1355
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
sub _accept($) |
1357
|
|
|
|
|
|
|
{ |
1358
|
|
|
|
|
|
|
# Accept a new connection |
1359
|
45
|
|
|
45
|
|
225
|
my $this=shift; |
1360
|
45
|
|
|
|
|
79
|
my $LISTEN=shift; |
1361
|
45
|
50
|
|
|
|
3746
|
my $client_paddr = accept($this->{CLIENT}, $LISTEN) or confess "accept failed: $!"; |
1362
|
45
|
|
|
|
|
591
|
$this->{CLIENT}->autoflush(1); |
1363
|
45
|
|
|
|
|
5236
|
binmode($this->{CLIENT}); |
1364
|
45
|
|
|
|
|
500
|
my ($client_port, $client_iaddr) = sockaddr_in( $client_paddr ); |
1365
|
45
|
|
|
|
|
1527
|
$this->log("Connection accepted from", inet_ntoa($client_iaddr).":$client_port\n"); |
1366
|
45
|
100
|
|
|
|
266
|
if($this->{remote_ip_address}){ |
1367
|
18
|
50
|
|
|
|
195
|
$this->connect_to_server() or confess "Fatal: Can't connect to $this->{remote_ip_address}:$this->{remote_port_num}: $!"; |
1368
|
|
|
|
|
|
|
} |
1369
|
45
|
|
|
|
|
473
|
$this->{client_port} = $client_port; |
1370
|
45
|
|
|
|
|
587
|
$this->{client_iaddr} = inet_ntoa($client_iaddr); |
1371
|
45
|
|
|
|
|
132
|
return undef; |
1372
|
|
|
|
|
|
|
} |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
sub _new_child(){ |
1375
|
63
|
|
|
63
|
|
189
|
my $parent=shift; |
1376
|
63
|
|
|
|
|
451
|
my $child=_new(); |
1377
|
63
|
|
|
|
|
268
|
my $all_good=1; |
1378
|
63
|
|
|
|
|
127
|
foreach my $key (keys %{$parent}){ |
|
63
|
|
|
|
|
1454
|
|
1379
|
794
|
100
|
|
|
|
10689
|
if($key=~m/^(LISTEN|children|connections|timer_interval|timer_callback|is_running|stop_when_idle)$/){ |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
# do nothing - these parameters are not inherited |
1381
|
|
|
|
|
|
|
}elsif($key =~ m/^(parallel|log_file|verbose|mydate|(client_to_server|server_to_client|server)_callback(_behaviour)?|(local|remote)_(port_num|ip_address)|protocol)$/){ |
1382
|
434
|
|
|
|
|
4591
|
$child->{$key}=$parent->{$key}; |
1383
|
|
|
|
|
|
|
}elsif($key =~ m/^(name)$/){ |
1384
|
63
|
|
|
|
|
418
|
$child->{$key}=$parent->{$key}.".jr"; |
1385
|
|
|
|
|
|
|
}elsif($key eq "LOGFILE"){ |
1386
|
|
|
|
|
|
|
# TODO might want to have a different logfile for each child, or at least, an option to do so. |
1387
|
45
|
|
|
|
|
210
|
$child->{$key}=$parent->{$key}; |
1388
|
|
|
|
|
|
|
}else{ |
1389
|
0
|
|
|
|
|
0
|
warn "internal error - unexpected attribute: $key = {$parent->$key}\n"; |
1390
|
0
|
|
|
|
|
0
|
$all_good=0; |
1391
|
|
|
|
|
|
|
} |
1392
|
|
|
|
|
|
|
} |
1393
|
63
|
50
|
|
|
|
266
|
die "Internal error in _new_child()" unless $all_good; |
1394
|
63
|
|
|
|
|
305
|
$child->{parent}=$parent; |
1395
|
63
|
|
|
|
|
259
|
return bless $child; |
1396
|
|
|
|
|
|
|
} |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
sub _spawn_child(){ |
1399
|
45
|
|
|
45
|
|
135
|
my $this=shift; |
1400
|
45
|
|
|
|
|
214
|
my $child = $this->_new_child(); |
1401
|
45
|
|
|
|
|
422
|
$child->_accept($this->{LISTEN}); |
1402
|
45
|
50
|
|
|
|
200
|
confess "We have a child with no CLIENT\n" if !$child->{CLIENT}; |
1403
|
|
|
|
|
|
|
# hand-off the connection |
1404
|
45
|
|
|
|
|
586
|
$this->echo("starting connection:",++$this->{connections}); |
1405
|
45
|
100
|
|
|
|
675
|
if(!$this->{parallel}){ |
1406
|
43
|
|
|
|
|
2368
|
return $child; |
1407
|
|
|
|
|
|
|
} |
1408
|
2
|
|
|
|
|
3366
|
my $pid = fork(); |
1409
|
2
|
50
|
|
|
|
211
|
if(!defined $pid){ |
|
|
100
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
# Error |
1411
|
0
|
|
|
|
|
0
|
$this->echo("Cannot fork!: $!\nNew connection will run in the current thread\n"); |
1412
|
0
|
|
|
|
|
0
|
return $child; |
1413
|
|
|
|
|
|
|
}elsif(!$pid){ |
1414
|
|
|
|
|
|
|
# This is the child process |
1415
|
1
|
50
|
|
|
|
167
|
$child->echo(sprintf"Running %u",$$) if $child->{verbose}>1; |
1416
|
1
|
50
|
|
|
|
204
|
confess "We have a child with no CLIENT\n" if !$child->{CLIENT}; |
1417
|
|
|
|
|
|
|
# The active instance of the parent is potentially in a different process |
1418
|
|
|
|
|
|
|
# Ideally, we would have the parent go out of scope, but we can clean up the bits that matter |
1419
|
1
|
|
|
|
|
78
|
close $this->{LISTEN}; |
1420
|
1
|
|
|
|
|
19
|
$this->{LISTEN} = undef; |
1421
|
1
|
|
|
|
|
94
|
$child->_main_loop(); |
1422
|
1
|
|
|
|
|
7
|
$child->log(sprintf"Exiting %u",$$); |
1423
|
1
|
|
|
|
|
424
|
exit; |
1424
|
|
|
|
|
|
|
}else{ |
1425
|
|
|
|
|
|
|
# This is the parent process. The active child instance is in its own process, we clean up what we can |
1426
|
1
|
|
|
|
|
54
|
$child->_destroy(); |
1427
|
1
|
|
|
|
|
176
|
return undef; |
1428
|
|
|
|
|
|
|
} |
1429
|
|
|
|
|
|
|
} |
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
sub go() |
1432
|
|
|
|
|
|
|
{ |
1433
|
24
|
|
|
24
|
1
|
170391
|
my $this=shift; |
1434
|
24
|
|
|
|
|
1485
|
$this->log("go"); |
1435
|
24
|
|
|
|
|
608
|
$this->listen(); |
1436
|
24
|
|
|
|
|
352
|
$this->_main_loop(); |
1437
|
22
|
|
|
|
|
241
|
$this->log("stopped"); |
1438
|
22
|
|
|
|
|
118
|
return undef; |
1439
|
|
|
|
|
|
|
} |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
#sub _destroy_fh() { my $this=shift; my $file_handle=shift; if($this->{$file_handle}){ $this->log( "$this->{name}: closing $file_handle socket ". ($this->{local_port_num}||"")."\n") if $this->{verbose}; close $this->{$file_handle} or die; $this->{$file_handle}=undef; } return undef; } |
1442
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
sub _destroy() |
1444
|
|
|
|
|
|
|
{ |
1445
|
516
|
|
|
516
|
|
522712
|
my $this=shift; |
1446
|
|
|
|
|
|
|
# TODO? Tell children that they are being shutdown? |
1447
|
516
|
100
|
|
|
|
33404
|
close $this->{LISTEN} if($this->{LISTEN}); |
1448
|
516
|
100
|
|
|
|
6663
|
close $this->{CLIENT} if($this->{CLIENT}); |
1449
|
516
|
100
|
|
|
|
563391
|
close $this->{SERVER} if($this->{SERVER}); |
1450
|
516
|
|
|
|
|
15255
|
$this->{LISTEN}=$this->{SERVER}=$this->{CLIENT}=undef; |
1451
|
516
|
|
|
|
|
7988
|
return undef; |
1452
|
|
|
|
|
|
|
} |
1453
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
=head1 Exports |
1455
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
MitM does not export any functions or variables. |
1457
|
|
|
|
|
|
|
If parallel() is turned on, which by default it is not, MitM sets SIGCHD to IGNORE, and as advertised, it calls fork() once for each new connection. |
1458
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
=head1 AUTHOR |
1460
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
Ben AVELING, C<< >> |
1462
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
=head1 BUGS |
1464
|
|
|
|
|
|
|
|
1465
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
1466
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
1467
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
1468
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
=head1 SUPPORT |
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
1472
|
|
|
|
|
|
|
|
1473
|
|
|
|
|
|
|
perldoc Net::MitM |
1474
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
You can also look for information at: |
1476
|
|
|
|
|
|
|
|
1477
|
|
|
|
|
|
|
=over |
1478
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
1480
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
L |
1482
|
|
|
|
|
|
|
|
1483
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
1484
|
|
|
|
|
|
|
|
1485
|
|
|
|
|
|
|
L |
1486
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
=item * CPAN Ratings |
1488
|
|
|
|
|
|
|
|
1489
|
|
|
|
|
|
|
L |
1490
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
=item * Search CPAN |
1492
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
L |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
=back |
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
1498
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
I'd like to acknowledge W. Richard Steven's and his fantastic introduction to TCPIP: "TCP/IP Illustrated, Volume 1: The Protocols", Addison-Wesley, 1994. (L). |
1500
|
|
|
|
|
|
|
It got me started. Recommend. RIP. |
1501
|
|
|
|
|
|
|
The Blue Camel Book is also pretty useful, and Langworth & chromatic's "Perl Testing, A Developer's Notebook" is also worth a hat tip. |
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
=head1 ALTERNATIVES |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
If what you want is a pure proxy, especially if you want an ssh proxy or support for firewalls, you might want to evaluate Philippe "BooK" Bruhat's L. |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
And if you want a full "portable multitasking and networking framework for any event loop", you may be looking for L. |
1508
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
Copyleft 2013 Ben AVELING. |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
1514
|
|
|
|
|
|
|
under the terms of the the Artistic License (2.0). You may obtain a |
1515
|
|
|
|
|
|
|
copy of the full license at: |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
L |
1518
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
Any use, modification, and distribution of the Standard or Modified |
1520
|
|
|
|
|
|
|
Versions is governed by this Artistic License. By using, modifying or |
1521
|
|
|
|
|
|
|
distributing the Package, you accept this license. Do not use, modify, |
1522
|
|
|
|
|
|
|
or distribute the Package, if you do not accept this license. |
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
If your Modified Version has been derived from a Modified Version made |
1525
|
|
|
|
|
|
|
by someone other than you, you are nevertheless required to ensure that |
1526
|
|
|
|
|
|
|
your Modified Version complies with the requirements of this license. |
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
This license does not grant you the right to use any trademark, service |
1529
|
|
|
|
|
|
|
mark, tradename, or logo of the Copyright Holder. |
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
This license includes the non-exclusive, worldwide, free-of-charge |
1532
|
|
|
|
|
|
|
patent license to make, have made, have, hold and cherish, |
1533
|
|
|
|
|
|
|
use, offer to use, sell, offer to sell, import and |
1534
|
|
|
|
|
|
|
otherwise transfer the Package with respect to any patent claims |
1535
|
|
|
|
|
|
|
licensable by the Copyright Holder that are necessarily infringed by the |
1536
|
|
|
|
|
|
|
Package. If you institute patent litigation (including a cross-claim or |
1537
|
|
|
|
|
|
|
counterclaim) against any party alleging that the Package constitutes |
1538
|
|
|
|
|
|
|
direct or contributory patent infringement, then this Artistic License |
1539
|
|
|
|
|
|
|
to you shall terminate on the date that such litigation is filed. |
1540
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER |
1542
|
|
|
|
|
|
|
AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. |
1543
|
|
|
|
|
|
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
1544
|
|
|
|
|
|
|
PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY |
1545
|
|
|
|
|
|
|
YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR |
1546
|
|
|
|
|
|
|
CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR |
1547
|
|
|
|
|
|
|
CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, |
1548
|
|
|
|
|
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SO THERE. |
1549
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
=cut |
1551
|
|
|
|
|
|
|
|
1552
|
|
|
|
|
|
|
1; # End of Net::MitM |