]> git.sesse.net Git - nms/blob - mbd/mbd.pl
Fix a bug in 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 my @ports = mbd::find_all_ports();
20
21 # Open a socket for each port
22 my @socks = ();
23 my $udp = getprotobyname("udp");
24 for my $p (@ports) {
25         my $sock;
26         socket($sock, PF_INET, SOCK_DGRAM, $udp);
27         bind($sock, sockaddr_in($p, INADDR_ANY));
28         push @socks, $sock;
29 }
30
31 my $sendsock = Net::RawIP->new({udp => {}});
32
33 print "Listening on " . scalar @ports . " ports.\n";
34
35 # Main loop
36 while (1) {
37         my $rin = fhbits(@socks);
38         my $rout;
39
40         my $nfound = select($rout=$rin, undef, undef, undef);
41         for my $sock (@socks) {
42                 next unless (vec($rout, fileno($sock), 1) == 1);
43
44                 my $data;
45                 my $addr = recv($sock, $data, 8192, 0);   # jumbo broadcast! :-P
46                 my ($sport, $saddr) = sockaddr_in($addr);
47                 my ($dport, $daddr) = sockaddr_in(getsockname($sock));
48                 my $size = length($data);
49
50                 # We don't get the packet's destination address, but I guess this should do...
51                 # Check against the ACL.
52                 my $pass = 0;
53                 for my $rule (@Config::access_list) {
54                         if (mbd::match_ranges($dport, $rule->{'ports'}) &&
55                             mbd::match_ranges($size, $rule->{'sizes'})) {
56                                 $pass = 1;
57                         }
58                 }
59
60                 if (!$pass) {
61                         print "$dport, $size bytes => filtered\n";
62                 }
63
64                 next unless $pass;
65
66                 for my $net (@Config::networks) {
67                         next if (Net::CIDR::cidrlookup(inet_ntoa($saddr), $net));
68
69                         my ($range) = Net::CIDR::cidr2range($net);
70                         $range =~ /-(.*?)$/;
71                         my $broadcast = $1;
72
73                         print inet_ntoa($saddr), ", $dport, $size bytes => $broadcast\n";
74
75                         $sendsock->set({
76                                 ip => {
77                                         saddr => inet_ntoa($saddr),
78                                         daddr => $broadcast
79                                 },
80                                 udp => {
81                                         source => $sport,
82                                         dest => $dport,
83                                         data => $data
84                                 }
85                         });
86                         $sendsock->send;
87                 }
88         }
89 }
90