File Coverage

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


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