]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/perl | |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5 | # Copyright (C) 2007-2012 IPFire Team <info@ipfire.org> # | |
6 | # # | |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | use strict; | |
23 | ||
24 | use Net::IPv4Addr qw( :all ); | |
25 | use Switch; | |
26 | ||
27 | # enable only the following on debugging purpose | |
28 | #use warnings; | |
29 | #use CGI::Carp 'fatalsToBrowser'; | |
30 | ||
31 | require '/var/ipfire/general-functions.pl'; | |
32 | require "${General::swroot}/lang.pl"; | |
33 | require "${General::swroot}/header.pl"; | |
34 | ||
35 | &Header::showhttpheaders(); | |
36 | ||
37 | my @network=(); | |
38 | my @masklen=(); | |
39 | my @colour=(); | |
40 | ||
41 | my %netsettings=(); | |
42 | &General::readhash("${General::swroot}/ethernet/settings", \%netsettings); | |
43 | ||
44 | #workaround to suppress a warning when a variable is used only once | |
45 | my @dummy = ( ${Header::table1colour} ); | |
46 | undef (@dummy); | |
47 | ||
48 | # Read the connection tracking table. | |
49 | open(CONNTRACK, "/usr/local/bin/getconntracktable | sort -k 5,5 --numeric-sort --reverse |") or die "Unable to read conntrack table"; | |
50 | my @conntrack = <CONNTRACK>; | |
51 | close(CONNTRACK); | |
52 | ||
53 | # Collect data for the @network array. | |
54 | ||
55 | # Add Firewall Localhost 127.0.0.1 | |
56 | push(@network, '127.0.0.1'); | |
57 | push(@masklen, '255.255.255.255'); | |
58 | push(@colour, ${Header::colourfw}); | |
59 | ||
60 | if (open(IP, "${General::swroot}/red/local-ipaddress")) { | |
61 | my $redip = <IP>; | |
62 | close(IP); | |
63 | ||
64 | chomp $redip; | |
65 | push(@network, $redip); | |
66 | push(@masklen, '255.255.255.255'); | |
67 | push(@colour, ${Header::colourfw}); | |
68 | } | |
69 | ||
70 | # Add STATIC RED aliases | |
71 | if ($netsettings{'RED_DEV'}) { | |
72 | my $aliasfile = "${General::swroot}/ethernet/aliases"; | |
73 | open(ALIASES, $aliasfile) or die 'Unable to open aliases file.'; | |
74 | my @aliases = <ALIASES>; | |
75 | close(ALIASES); | |
76 | ||
77 | # We have a RED eth iface | |
78 | if ($netsettings{'RED_TYPE'} eq 'STATIC') { | |
79 | # We have a STATIC RED eth iface | |
80 | foreach my $line (@aliases) { | |
81 | chomp($line); | |
82 | my @temp = split(/\,/,$line); | |
83 | if ($temp[0]) { | |
84 | push(@network, $temp[0]); | |
85 | push(@masklen, $netsettings{'RED_NETMASK'} ); | |
86 | push(@colour, ${Header::colourfw} ); | |
87 | } | |
88 | } | |
89 | } | |
90 | } | |
91 | ||
92 | # Add Green Firewall Interface | |
93 | push(@network, $netsettings{'GREEN_ADDRESS'}); | |
94 | push(@masklen, "255.255.255.255" ); | |
95 | push(@colour, ${Header::colourfw} ); | |
96 | ||
97 | # Add Green Network to Array | |
98 | push(@network, $netsettings{'GREEN_NETADDRESS'}); | |
99 | push(@masklen, $netsettings{'GREEN_NETMASK'} ); | |
100 | push(@colour, ${Header::colourgreen} ); | |
101 | ||
102 | # Add Green Routes to Array | |
103 | my @routes = `/sbin/route -n | /bin/grep $netsettings{'GREEN_DEV'}`; | |
104 | foreach my $route (@routes) { | |
105 | chomp($route); | |
106 | my @temp = split(/[\t ]+/, $route); | |
107 | push(@network, $temp[0]); | |
108 | push(@masklen, $temp[2]); | |
109 | push(@colour, ${Header::colourgreen} ); | |
110 | } | |
111 | ||
112 | # Add Blue Firewall Interface | |
113 | push(@network, $netsettings{'BLUE_ADDRESS'}); | |
114 | push(@masklen, "255.255.255.255" ); | |
115 | push(@colour, ${Header::colourfw} ); | |
116 | ||
117 | # Add Blue Network | |
118 | if ($netsettings{'BLUE_DEV'}) { | |
119 | push(@network, $netsettings{'BLUE_NETADDRESS'}); | |
120 | push(@masklen, $netsettings{'BLUE_NETMASK'} ); | |
121 | push(@colour, ${Header::colourblue} ); | |
122 | ||
123 | # Add Blue Routes to Array | |
124 | @routes = `/sbin/route -n | /bin/grep $netsettings{'BLUE_DEV'}`; | |
125 | foreach my $route (@routes) { | |
126 | chomp($route); | |
127 | my @temp = split(/[\t ]+/, $route); | |
128 | push(@network, $temp[0]); | |
129 | push(@masklen, $temp[2]); | |
130 | push(@colour, ${Header::colourblue} ); | |
131 | } | |
132 | } | |
133 | ||
134 | # Add Orange Network | |
135 | if ($netsettings{'ORANGE_DEV'}) { | |
136 | push(@network, $netsettings{'ORANGE_NETADDRESS'}); | |
137 | push(@masklen, $netsettings{'ORANGE_NETMASK'} ); | |
138 | push(@colour, ${Header::colourorange} ); | |
139 | # Add Orange Routes to Array | |
140 | @routes = `/sbin/route -n | /bin/grep $netsettings{'ORANGE_DEV'}`; | |
141 | foreach my $route (@routes) { | |
142 | chomp($route); | |
143 | my @temp = split(/[\t ]+/, $route); | |
144 | push(@network, $temp[0]); | |
145 | push(@masklen, $temp[2]); | |
146 | push(@colour, ${Header::colourorange} ); | |
147 | } | |
148 | } | |
149 | ||
150 | # Add OpenVPN net and RED/BLUE/ORANGE entry (when appropriate) | |
151 | if (-e "${General::swroot}/ovpn/settings") { | |
152 | my %ovpnsettings = (); | |
153 | &General::readhash("${General::swroot}/ovpn/settings", \%ovpnsettings); | |
154 | my @tempovpnsubnet = split("\/",$ovpnsettings{'DOVPN_SUBNET'}); | |
155 | ||
156 | # add OpenVPN net | |
157 | push(@network, $tempovpnsubnet[0]); | |
158 | push(@masklen, $tempovpnsubnet[1]); | |
159 | push(@colour, ${Header::colourovpn} ); | |
160 | ||
161 | # add BLUE:port / proto | |
162 | if (($ovpnsettings{'ENABLED_BLUE'} eq 'on') && $netsettings{'BLUE_DEV'}) { | |
163 | push(@network, $netsettings{'BLUE_ADDRESS'} ); | |
164 | push(@masklen, '255.255.255.255' ); | |
165 | push(@colour, ${Header::colourovpn}); | |
166 | } | |
167 | ||
168 | # add ORANGE:port / proto | |
169 | if (($ovpnsettings{'ENABLED_ORANGE'} eq 'on') && $netsettings{'ORANGE_DEV'}) { | |
170 | push(@network, $netsettings{'ORANGE_ADDRESS'} ); | |
171 | push(@masklen, '255.255.255.255' ); | |
172 | push(@colour, ${Header::colourovpn} ); | |
173 | } | |
174 | } | |
175 | ||
176 | open(IPSEC, "${General::swroot}/vpn/config"); | |
177 | my @ipsec = <IPSEC>; | |
178 | close(IPSEC); | |
179 | ||
180 | foreach my $line (@ipsec) { | |
181 | my @vpn = split(',', $line); | |
182 | my ($network, $mask) = split("/", $vpn[12]); | |
183 | ||
184 | if (!&General::validip($mask)) { | |
185 | $mask = ipv4_cidr2msk($mask); | |
186 | } | |
187 | ||
188 | push(@network, $network); | |
189 | push(@masklen, $mask); | |
190 | push(@colour, ${Header::colourvpn}); | |
191 | } | |
192 | ||
193 | if (-e "${General::swroot}/ovpn/n2nconf") { | |
194 | open(OVPNN2N, "${General::swroot}/ovpn/ovpnconfig"); | |
195 | my @ovpnn2n = <OVPNN2N>; | |
196 | close(OVPNN2N); | |
197 | ||
198 | foreach my $line (@ovpnn2n) { | |
199 | my @ovpn = split(',', $line); | |
200 | next if ($ovpn[4] ne 'net'); | |
201 | ||
202 | my ($network, $mask) = split("/", $ovpn[12]); | |
203 | if (!&General::validip($mask)) { | |
204 | $mask = ipv4_cidr2msk($mask); | |
205 | } | |
206 | ||
207 | push(@network, $network); | |
208 | push(@masklen, $mask); | |
209 | push(@colour, ${Header::colourovpn}); | |
210 | } | |
211 | } | |
212 | ||
213 | # Show the page. | |
214 | &Header::openpage($Lang::tr{'connections'}, 1, ''); | |
215 | &Header::openbigbox('100%', 'left'); | |
216 | &Header::openbox('100%', 'left', $Lang::tr{'connection tracking'}); | |
217 | ||
218 | # Print legend. | |
219 | print <<END; | |
220 | <table width='100%'> | |
221 | <tr> | |
222 | <td align='center'> | |
223 | <b>$Lang::tr{'legend'} : </b> | |
224 | </td> | |
225 | <td align='center' bgcolor='${Header::colourgreen}'> | |
226 | <b><font color='#FFFFFF'>$Lang::tr{'lan'}</font></b> | |
227 | </td> | |
228 | <td align='center' bgcolor='${Header::colourred}'> | |
229 | <b><font color='#FFFFFF'>$Lang::tr{'internet'}</font></b> | |
230 | </td> | |
231 | <td align='center' bgcolor='${Header::colourorange}'> | |
232 | <b><font color='#FFFFFF'>$Lang::tr{'dmz'}</font></b> | |
233 | </td> | |
234 | <td align='center' bgcolor='${Header::colourblue}'> | |
235 | <b><font color='#FFFFFF'>$Lang::tr{'wireless'}</font></b> | |
236 | </td> | |
237 | <td align='center' bgcolor='${Header::colourfw}'> | |
238 | <b><font color='#FFFFFF'>IPFire</font></b> | |
239 | </td> | |
240 | <td align='center' bgcolor='${Header::colourvpn}'> | |
241 | <b><font color='#FFFFFF'>$Lang::tr{'vpn'}</font></b> | |
242 | </td> | |
243 | <td align='center' bgcolor='${Header::colourovpn}'> | |
244 | <b><font color='#FFFFFF'>$Lang::tr{'OpenVPN'}</font></b> | |
245 | </td> | |
246 | </tr> | |
247 | </table> | |
248 | <br> | |
249 | END | |
250 | ||
251 | # Print table header. | |
252 | print <<END; | |
253 | <table width='100%'> | |
254 | <tr> | |
255 | <th align='center'> | |
256 | $Lang::tr{'protocol'} | |
257 | </th> | |
258 | <th align='center'> | |
259 | $Lang::tr{'source ip and port'} | |
260 | </th> | |
261 | <th> </th> | |
262 | <th align='center'> | |
263 | $Lang::tr{'dest ip and port'} | |
264 | </th> | |
265 | <th> </th> | |
266 | <th align='center'> | |
267 | $Lang::tr{'download'} / | |
268 | <br>$Lang::tr{'upload'} | |
269 | </th> | |
270 | <th align='center'> | |
271 | $Lang::tr{'connection'}<br>$Lang::tr{'status'} | |
272 | </th> | |
273 | <th align='center'> | |
274 | $Lang::tr{'expires'}<br>($Lang::tr{'seconds'}) | |
275 | </th> | |
276 | </tr> | |
277 | END | |
278 | ||
279 | foreach my $line (@conntrack) { | |
280 | my @conn = split(' ', $line); | |
281 | ||
282 | # The first bit is the l3 protocol. | |
283 | my $l3proto = $conn[0]; | |
284 | ||
285 | # Skip everything that is not IPv4. | |
286 | if ($l3proto ne 'ipv4') { | |
287 | next; | |
288 | } | |
289 | ||
290 | # L4 protocol (tcp, udp, ...). | |
291 | my $l4proto = $conn[2]; | |
292 | ||
293 | # Translate unknown protocols. | |
294 | if ($l4proto eq 'unknown') { | |
295 | my $l4protonum = $conn[3]; | |
296 | if ($l4protonum eq '2') { | |
297 | $l4proto = 'IGMP'; | |
298 | } elsif ($l4protonum eq '4') { | |
299 | $l4proto = 'IPv4 Encap'; | |
300 | } elsif ($l4protonum eq '33') { | |
301 | $l4proto = 'DCCP'; | |
302 | } elsif ($l4protonum eq '41') { | |
303 | $l4proto = 'IPv6 Encap'; | |
304 | } elsif ($l4protonum eq '50') { | |
305 | $l4proto = 'ESP'; | |
306 | } elsif ($l4protonum eq '51') { | |
307 | $l4proto = 'AH'; | |
308 | } elsif ($l4protonum eq '132') { | |
309 | $l4proto = 'SCTP'; | |
310 | } else { | |
311 | $l4proto = $l4protonum; | |
312 | } | |
313 | } else { | |
314 | $l4proto = uc($l4proto); | |
315 | } | |
316 | ||
317 | # Source and destination. | |
318 | my $sip; | |
319 | my $dip; | |
320 | my $sport; | |
321 | my $dport; | |
322 | my @packets; | |
323 | my @bytes; | |
324 | ||
325 | my $ttl = $conn[4]; | |
326 | my $state; | |
327 | if ($l4proto eq 'TCP') { | |
328 | $state = $conn[5]; | |
329 | } | |
330 | ||
331 | # Kick out everything that is not IPv4. | |
332 | foreach my $item (@conn) { | |
333 | my ($key, $val) = split('=', $item); | |
334 | ||
335 | switch ($key) { | |
336 | case "src" { | |
337 | $sip = $val; | |
338 | } | |
339 | case "dst" { | |
340 | $dip = $val; | |
341 | } | |
342 | case "sport" { | |
343 | $sport = $val; | |
344 | } | |
345 | case "dport" { | |
346 | $dport = $val; | |
347 | } | |
348 | case "packets" { | |
349 | push(@packets, $val); | |
350 | } | |
351 | case "bytes" { | |
352 | push(@bytes, $val); | |
353 | } | |
354 | } | |
355 | } | |
356 | ||
357 | my $sip_colour = ipcolour($sip); | |
358 | my $dip_colour = ipcolour($dip); | |
359 | ||
360 | my $sserv = ''; | |
361 | if ($sport < 1024) { | |
362 | $sserv = uc(getservbyport($sport, lc($l4proto))); | |
363 | if ($sserv ne '') { | |
364 | $sserv = " ($sserv)"; | |
365 | } | |
366 | } | |
367 | ||
368 | my $dserv = ''; | |
369 | if ($dport < 1024) { | |
370 | $dserv = uc(getservbyport($dport, lc($l4proto))); | |
371 | if ($dserv ne '') { | |
372 | $dserv = " ($dserv)"; | |
373 | } | |
374 | } | |
375 | ||
376 | my $bytes_in = format_bytes($bytes[0]); | |
377 | my $bytes_out = format_bytes($bytes[1]); | |
378 | ||
379 | # Format TTL | |
380 | $ttl = format_time($ttl); | |
381 | ||
382 | print <<END; | |
383 | <tr> | |
384 | <td align='center'>$l4proto</td> | |
385 | <td align='center' bgcolor='$sip_colour'> | |
386 | <a href='/cgi-bin/ipinfo.cgi?ip=$sip'> | |
387 | <font color='#FFFFFF'>$sip</font> | |
388 | </a> | |
389 | </td> | |
390 | <td align='center' bgcolor='$sip_colour'> | |
391 | <a href='http://isc.sans.org/port_details.php?port=$sport' target='top'> | |
392 | <font color='#FFFFFF'>$sport$sserv</font> | |
393 | </a> | |
394 | </td> | |
395 | <td align='center' bgcolor='$dip_colour'> | |
396 | <a href='/cgi-bin/ipinfo.cgi?ip=$dip'> | |
397 | <font color='#FFFFFF'>$dip</font> | |
398 | </a> | |
399 | </td> | |
400 | <td align='center' bgcolor='$dip_colour'> | |
401 | <a href='http://isc.sans.org/port_details.php?port=$dport' target='top'> | |
402 | <font color='#FFFFFF'>$dport$dserv</font> | |
403 | </a> | |
404 | </td> | |
405 | <td align='center'> | |
406 | $bytes_in / $bytes_out | |
407 | </td> | |
408 | <td align='center'>$state</td> | |
409 | <td align='center'>$ttl</td> | |
410 | </tr> | |
411 | END | |
412 | } | |
413 | ||
414 | # Close the main table. | |
415 | print "</table>"; | |
416 | ||
417 | &Header::closebox(); | |
418 | &Header::closebigbox(); | |
419 | &Header::closepage(); | |
420 | ||
421 | sub format_bytes($) { | |
422 | my $bytes = shift; | |
423 | my @units = ("B", "k", "M", "G", "T"); | |
424 | ||
425 | foreach my $unit (@units) { | |
426 | if ($bytes < 1024) { | |
427 | return sprintf("%d%s", $bytes, $unit); | |
428 | } | |
429 | ||
430 | $bytes /= 1024; | |
431 | } | |
432 | ||
433 | return sprintf("%d%s", $bytes, $units[$#units]); | |
434 | } | |
435 | ||
436 | sub format_time($) { | |
437 | my $time = shift; | |
438 | ||
439 | my $seconds = $time % 60; | |
440 | my $minutes = $time / 60; | |
441 | ||
442 | my $hours = 0; | |
443 | if ($minutes >= 60) { | |
444 | $hours = $minutes / 60; | |
445 | $minutes %= 60; | |
446 | } | |
447 | ||
448 | return sprintf("%3d:%02d:%02d", $hours, $minutes, $seconds); | |
449 | } | |
450 | ||
451 | sub ipcolour($) { | |
452 | my $id = 0; | |
453 | my $colour = ${Header::colourred}; | |
454 | my ($ip) = $_[0]; | |
455 | my $found = 0; | |
456 | ||
457 | foreach my $line (@network) { | |
458 | if ($network[$id] eq '') { | |
459 | $id++; | |
460 | } else { | |
461 | if (!$found && ipv4_in_network($network[$id], $masklen[$id], $ip) ) { | |
462 | $found = 1; | |
463 | $colour = $colour[$id]; | |
464 | } | |
465 | $id++; | |
466 | } | |
467 | } | |
468 | ||
469 | return $colour; | |
470 | } | |
471 | ||
472 | 1; |