File Coverage

blib/lib/Parse/Netstat/freebsd.pm
Criterion Covered Total %
statement 36 37 97.3
branch 16 20 80.0
condition 12 15 80.0
subroutine 5 5 100.0
pod 1 1 100.0
total 70 78 89.7


line stmt bran cond sub pod time code
1             package Parse::Netstat::freebsd;
2              
3             our $DATE = '2017-02-09'; # DATE
4             our $VERSION = '0.13'; # VERSION
5              
6 1     1   24 use 5.010001;
  1         1  
7 1     1   4 use strict;
  1         1  
  1         18  
8 1     1   3 use warnings;
  1         1  
  1         22  
9              
10 1     1   3 use Exporter;
  1         1  
  1         607  
11             our @ISA = qw(Exporter);
12             our @EXPORT_OK = qw(parse_netstat);
13              
14             our %SPEC;
15              
16             $SPEC{parse_netstat} = {
17             v => 1.1,
18             summary => 'Parse the output of FreeBSD "netstat" command',
19             description => <<'_',
20              
21             Netstat can be called with `-n` (show raw IP addresses and port numbers instead
22             of hostnames or port names) or without. It can be called with `-a` (show all
23             listening and non-listening socket) option or without.
24              
25             Tested with FreeBSD 10.1's netstat.
26              
27             _
28             args => {
29             output => {
30             summary => 'Output of netstat command',
31             schema => 'str*',
32             req => 1,
33             },
34             tcp => {
35             summary => 'Whether to parse TCP (and TCP6) connections',
36             schema => [bool => default => 1],
37             },
38             udp => {
39             summary => 'Whether to parse UDP (and UDP6) connections',
40             schema => [bool => default => 1],
41             },
42             unix => {
43             summary => 'Whether to parse Unix socket connections',
44             schema => [bool => default => 1],
45             },
46             },
47             };
48             sub parse_netstat {
49 8     8 1 20 my %args = @_;
50 8 50       19 my $output = $args{output} or return [400, "Please specify output"];
51 8   50     15 my $tcp = $args{tcp} // 1;
52 8   50     12 my $udp = $args{udp} // 1;
53 8   50     17 my $unix = $args{unix} // 1;
54              
55 8         7 my $in_unix;
56             my $in_unix_header;
57 0         0 my @conns;
58 8         7 my $i = 0;
59 8         406 for my $line (split /^/, $output) {
60 796         425 $i++;
61 796         435 my %k;
62 796 100 100     3334 if ($line =~ /^Registered kernel control modules/) {
    100 100        
    100 100        
    100          
    100          
    100          
63 4         5 $in_unix = 0;
64             } elsif ($line =~ /^tcp/ && $tcp) {
65             #Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
66             #tcp4 0 0 192.168.1.33.632 192.168.1.10.2049 CLOSED
67 78 50       416 $line =~ m!^(?Ptcp(?:4|6|46)?) \s+ (?P\d+) \s+ (?P\d+)\s+
68             (?P\S+?)[:.](?P\w+)\s+
69             (?P\S+?)[:.](?P\w+|\*)\s+
70             (?P\S+) (?: \s+ (?:
71             (?P\d+)/(?P.+?) |
72             -
73             ))? \s*$!x
74             or return [400, "Can't parse tcp line (#$i): $line"];
75 78         1055 %k = %+;
76             } elsif ($line =~ /^udp/ && $udp) {
77             #Proto Recv-Q Send-Q Local Address Foreign Address (state)
78             #udp4 0 0 *.879 *.*
79 48 50       194 $line =~ m!^(?Pudp(?:4|6|46)?) \s+ (?P\d+) \s+ (?P\d+) \s+
80             (?P\S+?)[:.](?P\w+|\*)\s+
81             (?P\S+?)[:.](?P\w+|\*)
82             (?: \s+
83             (?P\S+)?
84             (?: \s+ (?:
85             (?P\d+)/(?P.+?) |
86             -
87             ))?
88             )? \s*$!x
89             or return [400, "Can't parse udp line (#$i): $line"];
90 48         548 %k = %+;
91             } elsif ($in_unix && $unix) {
92             #Address Type Recv-Q Send-Q Inode Conn Refs Nextref Addr
93             #fffffe00029912d0 stream 0 0 fffffe0002d8abd0 0 0 0 /tmp/ssh-zwZwlpzaip/agent.1089
94 93 50       351 $line =~ m!^(?P
\S+) \s+ (?P\S+) \s+
95             (?P\d+) \s+ (?P\d+) \s+ (?P[0-9a-f]+) \s+ (?P[0-9a-f]+) \s+
96             (?P[0-9a-f]+) \s+ (?P[0-9a-f]+)
97             (?:
98             \s+
99             (?P.+)
100             )?
101             \s*$!x
102             or return [400, "Can't parse unix/freebsd line (#$i): $line"];
103 93         1581 %k = %+;
104 93         234 $k{proto} = 'unix';
105             } elsif ($in_unix_header) {
106 8         7 $in_unix_header = 0;
107 8         4 $in_unix++;
108             } elsif ($line =~ /^Active (UNIX|LOCAL \(UNIX\)) domain sockets/) {
109 8         8 $in_unix_header++;
110             } else {
111 557         417 next;
112             }
113 239         537 push @conns, \%k;
114             }
115              
116 8         90 [200, "OK", {active_conns => \@conns}];
117             }
118              
119             1;
120             # ABSTRACT: Parse the output of FreeBSD "netstat" command
121              
122             __END__