Broadcast detection

Hi all,
i want to flag if a given ip is an ip broadcast/multicast or not:
there are some built-in functions able to recognize an ip broadcast in
Bro?
Thanks,
Vito

This sounds like something the Hosts module in scriptland does. If not, you could define subnets of multicast/broadcast addresses in a script and check on new_connection if id.orig_h or id.resp_h is in those subnets.

-AK

One way would be to check the packet destination against the IP multicast range:

global mcast = 224.0.0.0/4;
global bcast = 255.255.255.255;
event new_packet(c:connection,p:pkt_hdr) {
    if (c$id$resp_h in mcast || c$id$resp_h == bcast)
        print "mutlicast or broadcast found";
}

You wouldn't want to use the new_packet event of course.

Hi,
thanks for your reply.
What i'm trying to do is to create a flag if an ip broadcast is found.
For example, in networks.cfg i've written this subnet
172.20.1.0/24
It's broadcast address is 172.20.1.255.
I can read all subnets written in networks.cfg with the variable
Site::local_nets_table: to calculate the ip broadcast i can use this
method
https://en.wikipedia.org/wiki/Broadcast_address
What i'm not able to do is to transform a subnet variable (in this
case 172.20.1.0/24) into an ip variable (172.20.1.0) plus a count
(24).
Any suggestion?
Thanks
Vito

Oh I see what you’re saying. What you’d like is a function that takes a subnet as input and returns the broadcast address, correct?

-AK

Correct!
Any suggestion?

The following code feels like it should work, but the last print statement breaks it.

local my_subnet: subnet = 1.1.1.1/8;
print fmt("%s", my_subnet);
print fmt("%s", |my_subnet|);
print fmt("%s", my_subnet[ |my_subnet| ]);

I don’t believe there is currently a built in way to do what you want. Is there a way to convert a subnet to a vector of addr?

-AK

I’m looking to write a bif which does this. How can I access a subnet’s prefix as an int? Here’s what I have so far.

function get_broadcast%(snet: subnet%): addr
%{
return new AddrVal( snet->Prefix() + (snet->Width() - 1) );
%}

-AK

snet->Prefix() yields an IPAddr. You don't easily get that as an int,
but it has a method for getting it as a sequence of bytes:

    int GetBytes(const uint32_t** bytes)

That works for both IPv4 and v6.

That said, I think you can solve this more easily by combining some
other methods that IPAddr offers as well:

     /**
         * Masks out lower bits of the address.
         [...]
         */
        void Mask(int top_bits_to_keep);

     /**
         * Masks out top bits of the address.
        [...]
         */
        void ReverseMask(int top_bits_to_chop);

      /**
         * Bitwise OR operator returns the IP address resulting from the bitwise
         * OR operation on the raw bytes of this address with another.
         */
       IPAddr operator|(const IPAddr& other)

You'd mask out the lower bits of the prefix, mask out the upper bits
of 255.255.255.255 (for IPv4), and then "or" the two together.

Robin

I believe I have some logic that solves this. I created an xor (^)
operator for IPAddr types similar to the inclusive or (|) and am
making use of it to calculate the broadcast address of a subnet. My
BiF follows:

function subnet_end%(snet: subnet%): addr
        %{
        IPAddr broadcast;

        if (snet->Prefix().GetFamily() == IPv4) //ipv4
                {
                broadcast = (IPAddr(string("255.255.255.255")) ^
snet->Mask()) | snet->Prefix();
                }
        else if (snet->Prefix().GetFamily() == IPv6) //ipv6
                {
                broadcast =
(IPAddr(string("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) ^
snet->Mask()) | snet->Prefix();
                }
        else
                {
                reporter->InternalError("Unsupported address size. Not
IPv4 or IPv6.");
                }

        return new AddrVal(broadcast);
        %}

When calling this from scriptland, v6 addresses work properly.
However, v4 addresses are represented as v6 addresses still. I am
missing some concept around how IPAddrs can be either v4 or v6 and how
scriptland knows the difference. How might I properly indicate the
IPAddr in the returned AddrVal is meant to represent a v4 address
instead of a v6 address?
Thanks!

-AK

Here is a simpler implementation of this function (no other
changes to Bro are needed):

function subnet_end%(s: subnet%): addr
     %{
     IPAddr mask;
     int offset = 0;

     if ( s->Prefix().GetFamily() == IPv4 )
         {
         mask = IPAddr("255.255.255.255");
         offset = 96;
         }
     else
         {
         mask = IPAddr("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
         }

     mask.ReverseMask(offset + s->Width());

     return new AddrVal(mask | s->Prefix());
     %}

That’s much cleaner and doesn’t have the v4/v6 issue I introduced. Thanks Daniel. I understand now why Robin suggested using those methods.

-AK