]> git.sesse.net Git - nms/blob - mbd/mbd.pl
Add logging to mbd.
[nms] / mbd / mbd.pl
1 #! /usr/bin/perl
2 use strict;
3 use warnings;
4 use Socket;
5 use Net::CIDR;
6 use Net::RawIP;
7 require './access_list.pl';
8 require './nets.pl';
9 require './mbd.pm';
10
11 sub fhbits {
12         my $bits = 0;
13         for my $fh (@_) {
14                 vec($bits, fileno($fh), 1) = 1;
15         }
16         return $bits;
17 }
18
19 open LOG, ">>", "mbd.log";
20
21 my @ports = mbd::find_all_ports();
22
23 # Open a socket for each port
24 my @socks = ();
25 my $udp = getprotobyname("udp");
26 for my $p (@ports) {
27         my $sock;
28         socket($sock, PF_INET, SOCK_DGRAM, $udp);
29         bind($sock, sockaddr_in($p, INADDR_ANY));
30         push @socks, $sock;
31 }
32
33 my $sendsock = Net::RawIP->new({udp => {}});
34
35 print "Listening on " . scalar @ports . " ports.\n";
36
37 # Main loop
38 while (1) {
39         my $rin = fhbits(@socks);
40         my $rout;
41
42         my $nfound = select($rout=$rin, undef, undef, undef);
43         for my $sock (@socks) {
44                 next unless (vec($rout, fileno($sock), 1) == 1);
45
46                 my $data;
47                 my $addr = recv($sock, $data, 8192, 0);   # jumbo broadcast! :-P
48                 my ($sport, $saddr) = sockaddr_in($addr);
49                 my ($dport, $daddr) = sockaddr_in(getsockname($sock));
50                 my $size = length($data);
51
52                 # We don't get the packet's destination address, but I guess this should do...
53                 # Check against the ACL.
54                 my $pass = 0;
55                 for my $rule (@Config::access_list) {
56                         next unless (mbd::match_ranges($dport, $rule->{'ports'}));
57                         next unless (mbd::match_ranges($size, $rule->{'sizes'}));
58
59                         if ($rule->{'filter'}) {
60                                 next unless ($rule->{'filter'}($data));
61                         }
62
63                         $pass = 1;
64                         last;
65                 }
66
67                 print LOG "$dport $size $pass\n";
68
69                 if (!$pass) {
70                         print "$dport, $size bytes => filtered\n";
71                 }
72
73                 next unless $pass;
74
75                 for my $net (@Config::networks) {
76                         next if (Net::CIDR::cidrlookup(inet_ntoa($saddr), $net));
77
78                         my ($range) = Net::CIDR::cidr2range($net);
79                         $range =~ /-(.*?)$/;
80                         my $broadcast = $1;
81
82                         print inet_ntoa($saddr), ", $dport, $size bytes => $broadcast\n";
83
84                         $sendsock->set({
85                                 ip => {
86                                         saddr => inet_ntoa($saddr),
87                                         daddr => $broadcast
88                                 },
89                                 udp => {
90                                         source => $sport,
91                                         dest => $dport,
92                                         data => $data
93                                 }
94                         });
95                         $sendsock->send;
96                 }
97         }
98 }
99