From (spam-protected) Wed May 3 10:57:04 2006 From: (spam-protected) (Andreas Tønnesen) Date: Wed, 03 May 2006 08:57:04 +0000 Subject: [Olsr-cvs] olsrd-current/lib/bmf - New directory Message-ID: Update of /cvsroot/olsrd/olsrd-current/lib/bmf In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv608/bmf Log Message: Directory /cvsroot/olsrd/olsrd-current/lib/bmf added to the repository From (spam-protected) Wed May 3 10:57:30 2006 From: (spam-protected) (Andreas Tønnesen) Date: Wed, 03 May 2006 08:57:30 +0000 Subject: [Olsr-cvs] olsrd-current/lib/bmf/src - New directory Message-ID: Update of /cvsroot/olsrd/olsrd-current/lib/bmf/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1083/src Log Message: Directory /cvsroot/olsrd/olsrd-current/lib/bmf/src added to the repository From (spam-protected) Wed May 3 10:59:06 2006 From: (spam-protected) (Andreas Tønnesen) Date: Wed, 03 May 2006 08:59:06 +0000 Subject: [Olsr-cvs] olsrd-current/lib Makefile,1.4,1.5 Message-ID: Update of /cvsroot/olsrd/olsrd-current/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2222 Modified Files: Makefile Log Message: Initial addittion of the BMF multicast plugin Index: Makefile =================================================================== RCS file: /cvsroot/olsrd/olsrd-current/lib/Makefile,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** Makefile 26 May 2005 16:09:25 -0000 1.4 --- Makefile 3 May 2006 08:59:03 -0000 1.5 *************** *** 1,3 **** ! SUBDIRS = dot_draw dyn_gw httpinfo mini nameservice powerinfo secure tas .PHONY: $(SUBDIRS) --- 1,3 ---- ! SUBDIRS = dot_draw dyn_gw httpinfo mini nameservice powerinfo secure tas bmf .PHONY: $(SUBDIRS) From (spam-protected) Wed May 3 10:59:06 2006 From: (spam-protected) (Andreas Tønnesen) Date: Wed, 03 May 2006 08:59:06 +0000 Subject: [Olsr-cvs] olsrd-current/lib/bmf Copyright-Disclaimer.txt, NONE, 1.1 Makefile, NONE, 1.1 README_BMF.txt, NONE, 1.1 version-script.txt, NONE, 1.1 Message-ID: Update of /cvsroot/olsrd/olsrd-current/lib/bmf In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2222/bmf Added Files: Copyright-Disclaimer.txt Makefile README_BMF.txt version-script.txt Log Message: Initial addittion of the BMF multicast plugin --- NEW FILE: README_BMF.txt --- BASIC MULTICAST FORWARDING PLUGIN FOR OLSRD by Erik Tromp (erik_tromp at hotmail.com) 27-04-2006: Version 1.0.1 - First release. 1. Introduction --------------- The Basic Multicast Flooding Plugin forwards IP-multicast and IP-local-broacast traffic over an OLSRD network. It uses the Multi-Point Relays (MPRs) as identified by the OLSR protocol to optimize the flooding of multicast and local broadcast packets to all the nodes in the network. To prevent broadcast storms, a history of packets is kept; only packets that have not been seen in the past 3-6 seconds are forwarded. In the IP header there is room for only two IP-addresses: * the destination IP address (in our case either a multicast IP-address 224.0.0.0...239.255.255.255, or a local broadcast address e.g. 192.168.1.255), and * the source IP address (the originator). For optimized flooding, however, we need more information. Let's assume we are the BMF process on one node. We will need to know which node forwarded the IP packet to us. Since OLSR keeps track of which nodes select our node as MPR (see the olsr_lookup_mprs_set function), we can determine if the node that forwarded the packet, has selected us as MPR. If so, we must also forward the packet, replacing the 'forwarded-by' IP-address to that of us. Because we need more information than fits in a normal IP-header, the original packets are encapsulated into a new IP packet. Encapsulated packets are transported in UDP, port 50505. The source address of the encapsulation packet is set to the address of the forwarder instead of the originator. Of course, the payload of the encapsulation packet is the original IP packet. For local reception, each received encapsulated packets is unpacked and passed into a tuntap interface which is specially created for this purpose. Here is in short how the flooding works (see also the BmfEncapsulatedPacketReceived(...) function; details with respect to the forwarding towards non-OLSR enabled nodes are omitted): On all OLSR-enabled interfaces, setup reception of packets on UDP port 50505. Upon reception of such a packet: If the received packet was sent by ourselves, drop it. If the packet was recently seen, drop it. Unpack the encapsulated packet and send a copy to myself via the TunTap device. If I am an MPR for the node that forwarded the packet to me, forward the packet to all OLSR-enabled interfaces *including* the one on which it was received. As with all good things in life, it's so simple you could have thought of it yourself. 2. How to build and install --------------------------- Follow the instructions in the base directory README file under section II. - BUILDING AND RUNNING OLSRD. To be sure to install the BMF plugin, cd to the base directory and issue the follwing command at the shell prompt: make install_all Next, turn on the possibility to create a tuntap device (see also /usr/src/linux/Documentation/networking/tuntap.txt) mkdir /dev/net # if it doesn't exist already mknod /dev/net/tun c 10 200 Set permissions, e.g.: chmod 0700 /dev/net/tun Edit the file /etc/olsrd.conf to load the BMF plugin. For example: LoadPlugin "olsrd_bmf.so.1.0.1" { # No PlParam entries required for basic operation } 3. How to run ------------- After building and installing OLSRD with the BMF plugin, run the olsrd deamon by entering at the shell prompt: olsrd Look at the output; it should list the BMF plugin, e.g.: ---------- Plugin loader ---------- Library: olsrd_bmf.so.1.0.1 OLSRD Basic Multicast Forwarding plugin 1.0.1 (Apr 29 2006 12:57:57) (C) Thales Communications Huizen, Netherlands Erik Tromp (erik_tromp at hotmail.com) Checking plugin interface version... 4 - OK Trying to fetch plugin init function... OK Trying to fetch param function... OK Sending parameters... "NonOlsrIf"/"eth2"... OK "Drop"/"00:0C:29:28:0E:CC"... OK Running plugin_init function... ---------- LIBRARY LOADED ---------- 4. How to check if it works --------------------------- To check that BMF is working, enter the folliwing command on the command prompt: ping -I eth1 224.0.0.1 Replace eth1 with the name of any OLSR-enabled network interface. All OLSR-BMF nodes in the MANET should respond. For example: root at IsdbServer:~# ping -I eth1 224.0.0.1 PING 224.0.0.1 (224.0.0.1) from 192.168.151.50 eth1: 56(84) bytes of data. 64 bytes from 192.168.151.50: icmp_seq=1 ttl=64 time=0.511 ms 64 bytes from 192.168.151.53: icmp_seq=1 ttl=64 time=4.67 ms (DUP!) 64 bytes from 192.168.151.55: icmp_seq=1 ttl=63 time=10.7 ms (DUP!) 64 bytes from 192.168.151.50: icmp_seq=2 ttl=64 time=0.076 ms 64 bytes from 192.168.151.53: icmp_seq=2 ttl=64 time=1.23 ms (DUP!) 64 bytes from 192.168.151.55: icmp_seq=2 ttl=63 time=1.23 ms (DUP!) 64 bytes from 192.168.151.50: icmp_seq=3 ttl=64 time=0.059 ms 64 bytes from 192.168.151.53: icmp_seq=3 ttl=64 time=2.94 ms (DUP!) 64 bytes from 192.168.151.55: icmp_seq=3 ttl=63 time=5.62 ms (DUP!) 64 bytes from 192.168.151.50: icmp_seq=4 ttl=64 time=0.158 ms 64 bytes from 192.168.151.53: icmp_seq=4 ttl=64 time=1.14 ms (DUP!) 64 bytes from 192.168.151.55: icmp_seq=4 ttl=63 time=1.16 ms (DUP!) 5. Adding non-OLSR interfaces to the multicast flooding ------------------------------------------------------- As a special feature, it is possible to have multicast and local-broadcast IP packets forwarded also on non-OLSR interfaces. If you have network interfaces on which OLSR is *not* running, but you *do* want to forward multicast and local-broadcast IP packets, specify these interfaces one by one as "NonOlsrIf" parameters in the BMF plugin section of /etc/olsrd.conf. For example: LoadPlugin "olsrd_bmf.so.1.0.1" { # Non-OLSR interfaces to participate in the multicast flooding PlParam "NonOlsrIf" "eth2" PlParam "NonOlsrIf" "eth3" } If an interface is listed both as NonOlsrIf for BMF, and in the Interfaces { ... } section of olsrd.conf, it will be seen by BMF as an OLSR-enabled interface. Duh.... 6. Testing in a lab environment ------------------------------- Setup IP-tables to drop packets from nodes which are not direct (1-hop) neigbors. For example, to drop all packets from a host with MAC address 00:0C:29:28:0E:CC, enter at the shell prompt: iptables -A INPUT -m mac --mac-source 00:0C:29:28:0E:CC -j DROP Edit the file /etc/olsrd.conf, and specify the MAC addresses of the nodes we do not want to see; even though packets from these nodes are dropped by iptables, they are still received on network interfaces which are in promiscuous mode. For example: LoadPlugin "olsrd_bmf.so.1.0.1" { # Drop all packets received from the following MAC sources PlParam "Drop" "00:0C:29:C6:E2:61" # RemoteClient1 PlParam "Drop" "00:0C:29:61:34:B7" # SimpleClient1 PlParam "Drop" "00:0C:29:28:0E:CC" # SimpleClient2 } 7. Common problems, FAQ ----------------------- Question: When starting OLSRD with the BMF plugin, I can see the following error messages: OLSRD Basic Multicast Forwarding plugin: open() error: No such file or directory OLSRD Basic Multicast Forwarding plugin: error creating local EtherTunTap OLSRD Basic Multicast Forwarding plugin: could not initialize network interfaces! Wat to do? Answer: Turn on the possibility to create a tuntap device; see section 2 of this file. --- NEW FILE: Makefile --- # # OLSR Basic Multicast Forwarding (BMF) plugin. # Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. # Written by Erik Tromp. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # * Neither the name of Thales, BMF nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # $Id: Makefile,v 1.1 2006/05/03 08:59:04 kattemat Exp $ OLSRD_PLUGIN = true PLUGIN_NAME = olsrd_bmf PLUGIN_VER = 1.0.1 TOPDIR = ../.. include $(TOPDIR)/Makefile.inc LIBS += -lpthread ifneq ($(OS),linux) default_target install clean: @echo "*** BMF Plugin only supported on Linux, sorry!" else default_target: $(PLUGIN_FULLNAME) $(PLUGIN_FULLNAME): $(OBJS) $(CC) $(LDFLAGS) -o $(PLUGIN_FULLNAME) $(OBJS) $(LIBS) install: $(PLUGIN_FULLNAME) $(STRIP) $(PLUGIN_FULLNAME) $(INSTALL_LIB) clean: rm -f $(OBJS) $(SRCS:%.c=%.d) $(PLUGIN_FULLNAME) endif --- NEW FILE: Copyright-Disclaimer.txt --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ --- NEW FILE: version-script.txt --- VERS_1.0 { global: olsrd_plugin_interface_version; olsrd_plugin_register_param; olsrd_plugin_init; local: *; }; From (spam-protected) Wed May 3 10:59:18 2006 From: (spam-protected) (Andreas Tønnesen) Date: Wed, 03 May 2006 08:59:18 +0000 Subject: [Olsr-cvs] olsrd-current Makefile,1.69,1.70 Message-ID: Update of /cvsroot/olsrd/olsrd-current In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2553 Modified Files: Makefile Log Message: Initial addittion of the BMF multicast plugin Index: Makefile =================================================================== RCS file: /cvsroot/olsrd/olsrd-current/Makefile,v retrieving revision 1.69 retrieving revision 1.70 diff -C2 -d -r1.69 -r1.70 *** Makefile 6 Jan 2006 06:52:17 -0000 1.69 --- Makefile 3 May 2006 08:59:16 -0000 1.70 *************** *** 161,164 **** --- 161,169 ---- $(MAKE) -C lib/pgraph install + bmf: + $(MAKE) -C lib/bmf clean + $(MAKE) -C lib/bmf + $(MAKE) -C lib/bmf install + build_all: cfgparser olsrd libs install_all: install install_libs From (spam-protected) Wed May 3 10:59:06 2006 From: (spam-protected) (Andreas Tønnesen) Date: Wed, 03 May 2006 08:59:06 +0000 Subject: [Olsr-cvs] olsrd-current/lib/bmf/src Address.c, NONE, 1.1 Address.h, NONE, 1.1 Bmf.c, NONE, 1.1 Bmf.h, NONE, 1.1 DropList.c, NONE, 1.1 DropList.h, NONE, 1.1 NetworkInterfaces.c, NONE, 1.1 NetworkInterfaces.h, NONE, 1.1 Packet.c, NONE, 1.1 Packet.h, NONE, 1.1 PacketHistory.c, NONE, 1.1 PacketHistory.h, NONE, 1.1 olsrd_plugin.c, NONE, 1.1 Message-ID: Update of /cvsroot/olsrd/olsrd-current/lib/bmf/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2222/bmf/src Added Files: Address.c Address.h Bmf.c Bmf.h DropList.c DropList.h NetworkInterfaces.c NetworkInterfaces.h Packet.c Packet.h PacketHistory.c PacketHistory.h olsrd_plugin.c Log Message: Initial addittion of the BMF multicast plugin --- NEW FILE: Packet.h --- #ifndef _BMF_PACKET_H #define _BMF_PACKET_H /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: Packet.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ /* System includes */ #include /* IFNAMSIZ, IFHWADDRLEN */ #include /* u_int8_t, u_int16_t */ /* Offsets and sizes into IP-ethernet packets */ #define IPV4_ADDR_SIZE 4 #define ETH_TYPE_OFFSET (2*IFHWADDRLEN) #define ETH_TYPE_LEN 2 #define IP_HDR_OFFSET (ETH_TYPE_OFFSET + ETH_TYPE_LEN) #define IPV4_OFFSET_SRCIP 12 #define IPV4_OFFSET_DSTIP (IPV4_OFFSET_SRCIP + IPV4_ADDR_SIZE) #define IPV4_TYPE 0x0800 struct TSaveTtl { u_int8_t ttl; u_int16_t check; }; int GetIpTtl(unsigned char* buffer); void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl); void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl); void PacketDecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer); #endif /* _BMF_PACKET_H */ --- NEW FILE: Address.h --- #ifndef _BMF_ADDRESS_H #define _BMF_ADDRESS_H /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: Address.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #include "olsr_types.h" /* olsr_ip_addr */ #include "interfaces.h" /* struct interface */ int IsMulticast(union olsr_ip_addr* ipAddress); int IsLocalBroadcast(union olsr_ip_addr* destIp, struct interface* ifFrom); int IsOlsrOrBmfPacket(unsigned char* buffer, ssize_t len); #endif /* _BMF_ADDRESS_H */ --- NEW FILE: DropList.h --- #ifndef _BMF_DROPLIST_H #define _BMF_DROPLIST_H /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: DropList.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ struct TMacAddress { unsigned char addr[6]; struct TMacAddress* next; }; int DropMac(const char* macStr); int IsInDropList(const unsigned char* macAddress); #endif /* _BMF_DROPLIST_H */ --- NEW FILE: Packet.c --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: Packet.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #include "Packet.h" /* System includes */ #include /* assert() */ #include /* u_int32_t */ #include /* ntohs(), htons() */ #include /* Retrieve the TTL (Time To Live) value from the IP header of the * passed ethernet packet */ int GetIpTtl(unsigned char* buffer) { struct iphdr* iph; assert(buffer != NULL); iph = (struct iphdr*) (buffer + IP_HDR_OFFSET); return iph->ttl; } void SaveTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl) { struct iphdr* iph; assert(buffer != NULL && sttl != NULL); iph = (struct iphdr*) (buffer + IP_HDR_OFFSET); sttl->ttl = iph->ttl; sttl->check = ntohs(iph->check); } void RestoreTtlAndChecksum(unsigned char* buffer, struct TSaveTtl* sttl) { struct iphdr* iph; assert(buffer != NULL && sttl != NULL); iph = (struct iphdr*) (buffer + IP_HDR_OFFSET); iph->ttl = sttl->ttl; iph->check = htons(sttl->check); } /* For an IP packet, decrement the TTL value and update the IP header * checksum accordingly. See also RFC1141. */ void PacketDecreaseTtlAndUpdateHeaderChecksum(unsigned char* buffer) { struct iphdr* iph; u_int32_t sum; assert(buffer != NULL); iph = (struct iphdr*) (buffer + IP_HDR_OFFSET); iph->ttl--; /* decrement ttl */ sum = ntohs(iph->check) + 0x100; /* increment checksum high byte */ iph->check = htons(sum + (sum>>16)); /* add carry */ } --- NEW FILE: olsrd_plugin.c --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: olsrd_plugin.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ /* * Dynamic linked library for olsr.org olsrd */ /* System includes */ #include /* assert() */ #include /* OLSRD includes */ #include "olsrd_plugin.h" /* BMF includes */ #include "Bmf.h" /* InitBmf(), CloseBmf(), RegisterBmfParameter() */ static void __attribute__ ((constructor)) my_init(void); static void __attribute__ ((destructor)) my_fini(void); void olsr_plugin_exit(void); /* Plugin interface version * Used by main olsrd to check plugin interface version */ int olsrd_plugin_interface_version() { return OLSRD_PLUGIN_INTERFACE_VERSION; } int olsrd_plugin_init() { return InitBmf(); } /* destructor - called at unload */ void olsr_plugin_exit() { CloseBmf(); } /* Register parameters from config file * Called for all plugin parameters */ int olsrd_plugin_register_param(char* key, char* value) { assert(key != NULL && value != NULL); return RegisterBmfParameter(key, value); } static void my_init() { /* Print plugin info to stdout */ printf("%s\n", MOD_DESC); return; } static void my_fini() { olsr_plugin_exit(); } --- NEW FILE: DropList.c --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: DropList.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #include "DropList.h" /* System includes */ #include /* assert() */ #include /* NULL */ #include /* malloc */ #include /* memcmp */ /* OLSRD includes */ #include "olsr.h" /* olsr_printf */ /* Plugin includes */ #include "Bmf.h" /* PLUGIN_NAME */ #include "Packet.h" /* IFHWADDRLEN */ static struct TMacAddress* DroppedMacAddresses = NULL; /* Register a MAC address in the drop list. The registered MAC address will be matched * to the source MAC address of incoming multicast packets. If matched, the multicast * packet will be silently dropped. * The drop list is needed only in lab environments, where hidden nodes are simulated * by using iptables with the -m mac --mac-source option (as in: * "iptables -A INPUT -m mac --mac-source 00:0C:29:EE:C9:D0 -j DROP") * The drop list is needed because network interfaces in promiscuous mode will still * capture packets even if they are specified to be dropped by iptables. */ int DropMac(const char* macStr) { unsigned int mac[6]; int n; struct TMacAddress* newMacAddress; int i; assert(macStr != NULL); n = sscanf(macStr, "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); if (n != 6) { olsr_printf(1, "%s: Invalid Ethernet address '%s'\n", PLUGIN_NAME, macStr); return 0; } newMacAddress = malloc(sizeof(struct TMacAddress)); for (i = 0; i < 6; i++) { newMacAddress->addr[i] = (unsigned char) mac[i]; } newMacAddress->next = DroppedMacAddresses; DroppedMacAddresses = newMacAddress; return 1; } /* Return 1 if macAddress is in the drop list, else 0 */ int IsInDropList(const unsigned char* macAddress) { struct TMacAddress* ma = DroppedMacAddresses; assert(macAddress != NULL); while (ma != NULL) { if (memcmp(ma->addr, macAddress, IFHWADDRLEN) == 0) return 1; ma = ma->next; } return 0; } --- NEW FILE: Address.c --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: Address.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #include "Address.h" /* System includes */ #include /* assert() */ /* OLSRD includes */ #include "defs.h" /* COMP_IP */ /* Plugin includes */ #include "Bmf.h" /* BMF_ENCAP_PORT */ int IsMulticast(union olsr_ip_addr* ipAddress) { assert(ipAddress != NULL); return (ntohl(ipAddress->v4) & 0xF0000000) == 0xE0000000; } int IsLocalBroadcast(union olsr_ip_addr* destIp, struct interface* ifFrom) { struct sockaddr_in* sin; assert(destIp != NULL); /* Protect ourselves against bogus input */ if (ifFrom == NULL) return 0; /* Cast down to correct sockaddr subtype */ sin = (struct sockaddr_in*)&(ifFrom->int_broadaddr); /* Just in case OLSR does not have int_broadaddr filled in for this * interface. */ if (sin == NULL) return 0; return COMP_IP(&(sin->sin_addr.s_addr), destIp); } int IsOlsrOrBmfPacket(unsigned char* buffer, ssize_t len) { u_int16_t port; assert(buffer != NULL); /* Consider OLSR and BMF packets not to be local broadcast * OLSR packets are UDP - port 698 * BMF packets are UDP - port 50505 */ memcpy(&port, buffer + 0x24, 2); port = ntohs(port); if (len > 0x25 && buffer[0x17] == 0x11 && /* UDP */ (port == OLSRPORT || port == BMF_ENCAP_PORT)) { return 1; } return 0; } --- NEW FILE: Bmf.h --- #ifndef _BMF_BMF_H #define _BMF_BMF_H /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: Bmf.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ /* BMF plugin data */ #define PLUGIN_NAME "OLSRD Basic Multicast Forwarding plugin" #define PLUGIN_VERSION "1.0.1 (" __DATE__ " " __TIME__ ")" #define PLUGIN_COPYRIGHT " (C) Thales Communications Huizen, Netherlands" #define PLUGIN_AUTHOR " Erik Tromp (erik_tromp at hotmail.com)" #define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION "\n" PLUGIN_COPYRIGHT "\n" PLUGIN_AUTHOR /* UDP-Port on which multicast packets are encapsulated */ #define BMF_ENCAP_PORT 50505 int InitBmf(void); void CloseBmf(void); int RegisterBmfParameter(char* key, char* value); #endif /* _BMF_BMF_H */ --- NEW FILE: PacketHistory.c --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: PacketHistory.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #include "PacketHistory.h" /* System includes */ #include /* assert() */ #include /* u_int16_t, u_int32_t */ #include /* memset */ /* OLSRD includes */ #include "olsr.h" /* olsr_printf */ /* Plugin includes */ #include "Packet.h" static u_int32_t PacketHistory[HISTORY_TABLE_SIZE]; /* Calculate 16-bits CRC according to CRC-CCITT specification, modified * to leave out some parts of the packet. */ static u_int16_t CalcCrcCcitt(unsigned char* buffer, ssize_t len) { /* Initial value of 0xFFFF should be 0x1D0F according to * www.joegeluso.com/software/articles/ccitt.htm */ u_int16_t crc = 0xFFFF; int i; assert(buffer != NULL); for (i = 0; i < len; i++) { /* Skip IP header checksum; we want to avoid as much as possible * calculating a checksum over data containing a checksum */ if (i >= 12 && i < 14) continue; crc = (unsigned char)(crc >> 8) | (crc << 8); crc ^= buffer[i]; crc ^= (unsigned char)(crc & 0xff) >> 4; crc ^= (crc << 8) << 4; crc ^= ((crc & 0xff) << 4) << 1; } return crc; #if 0 /* Alternative, simpler and perhaps just as good: add source IP address, * destination IP address and IP identification, in 16-bit */ return ((buffer[0x0E] << 8) + buffer[0x0F]) + ((buffer[0x10] << 8) + buffer[0x11]) + ((buffer[0x12] << 8) + buffer[0x13]) + ((buffer[0x14] << 8) + buffer[0x15]) + ((buffer[0x06] << 8) + buffer[0x07]); #endif } void InitPacketHistory() { memset(PacketHistory, 0, sizeof(PacketHistory)); } /* Record the fact that this packet was seen recently */ void MarkRecentPacket(unsigned char* buffer, ssize_t len) { u_int16_t crc; u_int32_t index; uint offset; assert(buffer != NULL); /* Start CRC calculation at ethertype; skip source and destination MAC * addresses */ crc = CalcCrcCcitt(buffer + ETH_TYPE_OFFSET, len - ETH_TYPE_OFFSET); index = crc / NPACKETS_PER_ENTRY; assert(index < HISTORY_TABLE_SIZE); offset = (crc % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET; assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET); /* Mark "seen recently" */ PacketHistory[index] = PacketHistory[index] | (0x3u << offset); } /* Check if this packet was seen recently */ int CheckMarkRecentPacket(unsigned char* buffer, ssize_t len) { u_int16_t crc; u_int32_t index; uint offset; u_int32_t bitMask; int result; assert(buffer != NULL); /* Start CRC calculation at ethertype; skip source and destination MAC * addresses */ crc = CalcCrcCcitt(buffer + ETH_TYPE_OFFSET, len - ETH_TYPE_OFFSET); index = crc / NPACKETS_PER_ENTRY; assert(index < HISTORY_TABLE_SIZE); offset = (crc % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET; assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET); bitMask = 0x1u << offset; result = ((PacketHistory[index] & bitMask) == bitMask); /* Always mark "seen recently" */ PacketHistory[index] = PacketHistory[index] | (0x3u << offset); return result; } void PrunePacketHistory(void* useless) { uint i; for (i = 0; i < HISTORY_TABLE_SIZE; i++) { if (PacketHistory[i] > 0) { uint j; for (j = 0; j < NPACKETS_PER_ENTRY; j++) { uint offset = j * NBITS_PER_PACKET; u_int32_t bitMask = 0x3u << offset; u_int32_t bitsSeenRecenty = 0x3u << offset; u_int32_t bitsTimingOut = 0x1u << offset; /* 10 should never occur */ assert ((PacketHistory[i] & bitMask) != (0x2u << offset)); if ((PacketHistory[i] & bitMask) == bitsSeenRecenty) { /* 11 -> 01 */ PacketHistory[i] &= ~bitMask | bitsTimingOut; } else if ((PacketHistory[i] & bitMask) == bitsTimingOut) { /* 01 -> 00 */ PacketHistory[i] &= ~bitMask; } } /* for (j = ...) */ } /* if (PacketHistory[i] > 0) */ } /* for (i = ...) */ } --- NEW FILE: NetworkInterfaces.h --- #ifndef _BMF_NETWORKINTERFACES_H #define _BMF_NETWORKINTERFACES_H /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: NetworkInterfaces.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ /* Plugin includes */ #include "Packet.h" /* IFHWADDRLEN */ struct TBmfInterface { /* File descriptor of raw packet socket, used for capturing multicast packets */ int capturingSkfd; /* File descriptor of UDP (datagram) socket for encapsulated multicast packets. * Set to -1 if interface is not OLSR-enabled. */ int encapsulatingSkfd; unsigned char macAddr[IFHWADDRLEN]; char ifName[IFNAMSIZ]; /* OLSRs idea of this network interface. NULL if this interface is not * OLSR-enabled. */ struct interface* olsrIntf; /* Kernels index of this network interface */ int ifIndex; /* Next element in list */ struct TBmfInterface* next; }; extern struct TBmfInterface* BmfInterfaces; extern int EtherTunTapFd; extern const char* EtherTunTapIfName; enum TTunOrTap { TT_TUN = 0, TT_TAP }; extern enum TTunOrTap TunOrTap; int CreateBmfNetworkInterfaces(void); void CloseBmfNetworkInterfaces(void); int AddNonOlsrBmfIf(const char* ifName); int IsNonOlsrBmfIf(const char* ifName); #endif /* _BMF_NETWORKINTERFACES_H */ --- NEW FILE: Bmf.c --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: Bmf.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #define _MULTI_THREADED #include "Bmf.h" /* System includes */ #include /* NULL */ #include /* ssize_t */ #include /* strerror() */ #include /* errno */ #include /* assert() */ #include /* struct sockaddr_ll, PACKET_MULTICAST */ #include /* pthread_create() */ #include /* SIGINT */ /* OLSRD includes */ #include "defs.h" /* olsr_cnf */ #include "olsr.h" /* olsr_printf */ #include "scheduler.h" /* olsr_register_scheduler_event */ #include "mid_set.h" /* mid_lookup_main_addr() */ #include "mpr_selector_set.h" /* olsr_lookup_mprs_set() */ /* Plugin includes */ #include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */ #include "Address.h" /* IsMulticast(), IsLocalBroadcast() */ #include "Packet.h" /* ETH_TYPE_OFFSET, IFHWADDRLEN etc. */ #include "PacketHistory.h" /* InitPacketHistory() */ #include "DropList.h" /* DropMac() */ static pthread_t BmfThread; static int BmfThreadRunning = 0; static void BmfPacketCaptured(struct TBmfInterface* intf, unsigned char* buffer, ssize_t len) { struct interface* ifFrom; unsigned char* srcMac; union olsr_ip_addr srcIp; union olsr_ip_addr destIp; union olsr_ip_addr* originator; struct sockaddr_in sin; struct TBmfInterface* nextFwIntf; /* Only forward IPv4 packets */ u_int16_t type; memcpy(&type, buffer + ETH_TYPE_OFFSET, 2); if (ntohs(type) != IPV4_TYPE) { return; } /* Lookup the OLSR interface on which this packet is received */ ifFrom = intf->olsrIntf; /* Only forward multicast or local broadcast packets */ COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP); if (! IsMulticast(&destIp) && ! IsLocalBroadcast(&destIp, ifFrom)) { return; } /* Discard OLSR packets (UDP port 698) and BMF encapsulated packets * (UDP port 50505) */ if (IsOlsrOrBmfPacket(buffer, len)) { return; } /* Apply drop list for testing purposes. */ srcMac = buffer + IFHWADDRLEN; if (IsInDropList(srcMac)) { return; } /* Lookup main address of source */ COPY_IP(&srcIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_SRCIP); originator = mid_lookup_main_addr(&srcIp); if (originator == NULL) { originator = &srcIp; } olsr_printf( 9, "MC pkt to %s received from originator %s (%s) via \"%s\"\n", olsr_ip_to_string(&destIp), olsr_ip_to_string(originator), olsr_ip_to_string(&srcIp), intf->ifName); /* Check if I am MPR for that originator */ if (ifFrom != NULL && olsr_lookup_mprs_set(originator) == NULL) { olsr_printf( 9, "--> Discarding pkt: I am not selected as MPR by that originator\n"); return; } /* If this packet is captured on a non-OLSR interface, decrease * the TTL and re-calculate the IP header checksum */ if (ifFrom == NULL) { PacketDecreaseTtlAndUpdateHeaderChecksum(buffer); } /* If the TTL is <= 0, do not forward this packet */ if (GetIpTtl(buffer) <= 0) { return; } /* Check if this packet was seen recently */ if (CheckMarkRecentPacket(buffer, len)) { olsr_printf( 9, "--> Discarding pkt: was a duplicate\n"); return; } /* Encapsulate and forward packet on all OLSR interfaces */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(BMF_ENCAP_PORT); nextFwIntf = BmfInterfaces; while (nextFwIntf != NULL) { struct TBmfInterface* fwIntf = nextFwIntf; nextFwIntf = fwIntf->next; if (fwIntf->olsrIntf != NULL) { int nBytesWritten; /* Change source MAC address to that of myself */ memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN); /* Destination address is local broadcast */ sin.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr; nBytesWritten = sendto( fwIntf->encapsulatingSkfd, buffer, len, MSG_DONTROUTE, (struct sockaddr*) &sin, sizeof(sin)); if (nBytesWritten != len) { olsr_printf( 1, "%s: sendto() error forwarding MC pkt for %s to \"%s\": %s\n", PLUGIN_NAME, olsr_ip_to_string(&destIp), fwIntf->olsrIntf->int_name, strerror(errno)); } else { olsr_printf( 9, "Successfully encapsulated one MC pkt for %s to \"%s\"\n", olsr_ip_to_string(&destIp), fwIntf->olsrIntf->int_name); } /* if (nBytesWritten != len) */ } /* if (fwIntf->olsrIntf != NULL) */ } /* while (nextFwIntf != NULL) */ } static void BmfEncapsulatedPacketReceived( struct TBmfInterface* intf, struct in_addr srcIp, unsigned char* buffer, ssize_t len) { union olsr_ip_addr fromAddr; struct interface* ifFrom; union olsr_ip_addr* forwarder; int nBytesToWrite; unsigned char* bufferToWrite; int nBytesWritten; int iAmMpr; struct sockaddr_in sin; struct TBmfInterface* nextFwIntf; COPY_IP(&fromAddr, &srcIp.s_addr); /* Are we talking to ourselves? */ if (if_ifwithaddr(&fromAddr) != NULL) { return; } /* Lookup the OLSR interface on which this packet is received */ ifFrom = intf->olsrIntf; /* Encapsulated packet received on non-OLSR interface? Then discard */ if (ifFrom == NULL) { return; } /* Apply drop list? No, not needed: encapsulated packets are routed, * so filtering should be done by adding a rule to the iptables FORWARD * chain, e.g.: * iptables -A FORWARD -m mac --mac-source 00:0C:29:28:0E:CC -j DROP */ /* Lookup main address of forwarding node */ forwarder = mid_lookup_main_addr(&fromAddr); if (forwarder == NULL) { forwarder = &fromAddr; olsr_printf( 9, "Encapsulated MC pkt received; forwarder to me by %s on \"%s\"\n", olsr_ip_to_string(forwarder), intf->ifName); } else { olsr_printf( 9, "Encapsulated MC pkt received; forwarder to me by %s (thru %s) on \"%s\"\n", olsr_ip_to_string(forwarder), olsr_ip_to_string(&fromAddr), intf->ifName); } /* Check if this packet was seen recently */ if (CheckMarkRecentPacket(buffer, len)) { olsr_printf( 9, "--> Discarding encapsulated pkt: was a duplicate\n"); return; } /* Unpack encapsulated packet and send a copy to myself via the EtherTunTap device */ nBytesToWrite = len; bufferToWrite = buffer; if (TunOrTap == TT_TUN) { nBytesToWrite -= IP_HDR_OFFSET; bufferToWrite += IP_HDR_OFFSET; } nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite); if (nBytesWritten != nBytesToWrite) { olsr_printf( 1, "%s: write() error sending encapsulated MC pkt to \"%s\": %s\n", PLUGIN_NAME, EtherTunTapIfName, strerror(errno)); } else { olsr_printf( 9, "Successfully unpacked and sent encapsulated MC pkt to \"%s\"\n", EtherTunTapIfName); } /* Check if I am MPR for the forwarder */ iAmMpr = (olsr_lookup_mprs_set(forwarder) != NULL); if (! iAmMpr) { olsr_printf( 9, "--> Not forwarding encapsulated pkt: I am not selected as MPR by that forwarder\n"); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(BMF_ENCAP_PORT); nextFwIntf = BmfInterfaces; while (nextFwIntf != NULL) { struct TBmfInterface* fwIntf = nextFwIntf; nextFwIntf = fwIntf->next; /* On non-OLSR interfaces: unpack encapsulated packet, decrease TTL * and send */ if (fwIntf->olsrIntf == NULL) { struct TSaveTtl sttl; /* Change source MAC address to that of sending interface */ memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN); /* Save IP header checksum and the TTL-value of the packet, then * decrease the TTL by 1 before writing */ SaveTtlAndChecksum(buffer, &sttl); PacketDecreaseTtlAndUpdateHeaderChecksum(buffer); /* If the TTL is <= 0, do not forward this packet */ if (GetIpTtl(buffer) <= 0) { return; } nBytesWritten = write(fwIntf->capturingSkfd, buffer, len); if (nBytesWritten != len) { olsr_printf( 1, "%s: write() error sending unpacked encapsulated MC pkt to \"%s\": %s\n", PLUGIN_NAME, fwIntf->ifName, strerror(errno)); } else { olsr_printf( 9, "Successfully unpacked and sent one encapsulated MC pkt to \"%s\"\n", fwIntf->ifName); } /* Restore the IP header checksum and the TTL-value of the packet */ RestoreTtlAndChecksum(buffer, &sttl); } /* if (fwIntf->olsrIntf == NULL) */ /* On OLSR interfaces, forward the packet if this node is selected as MPR by the * forwarding node */ else if (iAmMpr) { /* Change source MAC address to that of sending interface */ memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN); /* Destination address is local broadcast */ sin.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr; nBytesWritten = sendto( fwIntf->encapsulatingSkfd, buffer, len, MSG_DONTROUTE, (struct sockaddr*) &sin, sizeof(sin)); if (nBytesWritten != len) { olsr_printf( 1, "%s: sendto() error forwarding encapsulated MC pkt to \"%s\": %s\n", PLUGIN_NAME, fwIntf->olsrIntf->int_name, strerror(errno)); } else { olsr_printf( 9, "Successfully forwarded one encapsulated MC pkt to \"%s\"\n", fwIntf->olsrIntf->int_name); } } /* else if (iAmMpr) */ } /* while (nextFwIntf != NULL) */ } static void DoBmf(void* useless) { #define BUFFER_MAX 2048 struct TBmfInterface* intf; int nFdBitsSet; /* Compose set of socket file descriptors. * Keep the highest descriptor seen. */ int highestSkfd = -1; fd_set input_set; FD_ZERO(&input_set); intf = BmfInterfaces; while (intf != NULL) { FD_SET(intf->capturingSkfd, &input_set); if (intf->capturingSkfd > highestSkfd) { highestSkfd = intf->capturingSkfd; } if (intf->encapsulatingSkfd >= 0) { FD_SET(intf->encapsulatingSkfd, &input_set); if (intf->encapsulatingSkfd > highestSkfd) { highestSkfd = intf->encapsulatingSkfd; } } intf = intf->next; } assert(highestSkfd >= 0); /* Wait (blocking) for packets received on any of the sockets */ nFdBitsSet = select(highestSkfd + 1, &input_set, NULL, NULL, NULL); if (nFdBitsSet < 0) { if (errno != EINTR) { olsr_printf(1, "%s: select() error: %s\n", PLUGIN_NAME, strerror(errno)); } return; } if (nFdBitsSet == 0) { /* No packets waiting. This is unexpected; normally we would excpect select(...) * to return only if at least one packet was received (so nFdBitsSet > 0), or * if this thread received a signal (so nFdBitsSet < 0). */ return; } while (nFdBitsSet > 0) { intf = BmfInterfaces; while (intf != NULL) { int skfd = intf->capturingSkfd; if (FD_ISSET(skfd, &input_set)) { unsigned char buffer[BUFFER_MAX]; struct sockaddr_ll pktAddr; socklen_t addrLen; int nBytes; /* A packet was captured */ nFdBitsSet--; memset(&pktAddr, 0, sizeof(struct sockaddr_ll)); addrLen = sizeof(pktAddr); nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&pktAddr, &addrLen); if (nBytes < 0) { olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno)); } /* Don't let BMF crash by sending too short packets. IP packets are always * at least 14 (Ethernet header) + 20 (IP header) = 34 bytes long. */ if (nBytes >= 34) { if (pktAddr.sll_pkttype == PACKET_OUTGOING) { union olsr_ip_addr destIp; COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP); if (IsMulticast(&destIp) || IsLocalBroadcast(&destIp, intf->olsrIntf)) { if (! IsOlsrOrBmfPacket(buffer, nBytes)) { MarkRecentPacket(buffer, nBytes); } } } else if (pktAddr.sll_pkttype == PACKET_MULTICAST || pktAddr.sll_pkttype == PACKET_BROADCAST) { BmfPacketCaptured(intf, buffer, nBytes); } } /* if (nBytes >= 34) */ } /* if (FD_ISSET...) */ skfd = intf->encapsulatingSkfd; if (skfd >= 0 && (FD_ISSET(skfd, &input_set))) { unsigned char buffer[BUFFER_MAX]; struct sockaddr_in addr; socklen_t addrLen = sizeof(addr); int nBytes; /* An encapsulated packet was received */ nFdBitsSet--; memset(&addr, 0, sizeof(addr)); nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&addr, &addrLen); if (nBytes < 0) { olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno)); } if (nBytes > 0) { BmfEncapsulatedPacketReceived(intf, addr.sin_addr, buffer, nBytes); } } /* if (skfd >= 0 && (FD_ISSET...) */ intf = intf->next; } /* while (intf != NULL) */ } /* while (nFdBitsSet > 0) */ } static void BmfSignalHandler(int signo) { /* Dummy handler function */ return; } /* Thread entry function. Another thread can gracefully stop this thread by writing a * '0' into global variable 'BmfThreadRunning' followed by sending a SIGALRM signal. */ static void* BmfRun(void* useless) { sigset_t blockedSigs; sigfillset(&blockedSigs); sigdelset(&blockedSigs, SIGALRM); if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) < 0) { olsr_printf(1, "%s: pthread_sigmask() error: %s\n", PLUGIN_NAME, strerror(errno)); } /* Set up the signal handler for the process: use SIGALRM to terminate * the BMF thread. Only if a signal handler is specified, does a blocking * system call return with errno set to EINTR; if a signal hander is not * specified, any system call in which the thread may be waiting will not * return. Note that the BMF thread is usually blocked in the select() * function (see DoBmf()). */ if (signal(SIGALRM, BmfSignalHandler) == SIG_ERR) { olsr_printf(1, "%s: signal() error: %s\n", PLUGIN_NAME, strerror(errno)); } /* Call the thread function until flagged to exit */ while (BmfThreadRunning != 0) { DoBmf(useless); } return NULL; } /* Initialize the BMF plugin */ int InitBmf() { /* Check validity */ if (olsr_cnf->ip_version != AF_INET) { fprintf(stderr, PLUGIN_NAME ": This plugin only supports IPv4!\n"); return 0; } /* Clear the packet history */ InitPacketHistory(); if (CreateBmfNetworkInterfaces() < 0) { fprintf(stderr, PLUGIN_NAME ": could not initialize network interfaces!\n"); return 0; } /* Run the multicast packet processing thread */ BmfThreadRunning = 1; pthread_create(&BmfThread, NULL, BmfRun, NULL); /* Register the duplicate registration pruning process */ olsr_register_scheduler_event(&PrunePacketHistory, NULL, 3.0, 2.0, NULL); return 1; } /* Close the BMF plugin */ void CloseBmf() { /* Signal BmfThread to exit */ BmfThreadRunning = 0; if (pthread_kill(BmfThread, SIGALRM) < 0) /* Strangely enough, all running threads receive the SIGALRM signal. But only the * BMF thread is affected by this signal, having specified a handler for this * signal in its thread entry function BmfRun(...). */ { olsr_printf(1, "%s: pthread_kill() error: %s\n", PLUGIN_NAME, strerror(errno)); } /* Wait for BmfThread to acknowledge */ if (pthread_join(BmfThread, NULL) < 0) { olsr_printf(1, "%s: pthread_join() error: %s\n", PLUGIN_NAME, strerror(errno)); } /* Time to clean up */ CloseBmfNetworkInterfaces(); } int RegisterBmfParameter(char* key, char* value) { if (strcmp(key, "Drop") == 0) { return DropMac(value); } else if (strcmp(key, "NonOlsrIf") == 0) { return AddNonOlsrBmfIf(value); } return 0; } --- NEW FILE: NetworkInterfaces.c --- /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: NetworkInterfaces.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #include "NetworkInterfaces.h" /* System includes */ #include /* syslog() */ #include /* strerror() */ #include /* errno */ #include /* close() */ #include /* ioctl() */ #include /* fcntl() */ #include /* assert() */ #include /* if_indextoname() */ #include /* htons() */ #include /* ETH_P_ALL */ #include /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */ #include /* IFF_TAP */ /* OLSRD includes */ #include "olsr.h" /* olsr_printf */ #include "defs.h" /* olsr_cnf */ /* Plugin includes */ #include "Packet.h" /* IFHWADDRLEN */ #include "Bmf.h" /* PLUGIN_NAME */ /* List of network interfaces used by BMF plugin */ struct TBmfInterface* BmfInterfaces = NULL; /* File descriptor of EtherTunTap device */ int EtherTunTapFd = -1; /* Network interface name of EtherTunTap device. If the name starts with "tun", an * IP tunnel interface will be used. Otherwise, an EtherTap device will be used. */ const char* EtherTunTapIfName = "tun0"; /* "tap0"; */ /* If the network interface name starts with "tun", an IP tunnel interface will be * used, and this variable will be set to TUN. Otherwise, an EtherTap device will * be used, and this variable will be set to TAP. */ enum TTunOrTap TunOrTap; /* Create raw packet socket for capturing multicast IP traffic. Returns * the socket descriptor, or -1 if an error occurred. */ static int CreateCaptureSocket(int ifIndex) { struct packet_mreq mreq; struct ifreq req; struct sockaddr_ll iface_addr; /* Open raw packet socket */ int skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (skfd < 0) { olsr_printf(1, "%s: socket(PF_PACKET) error: %s\n", PLUGIN_NAME, strerror(errno)); return -1; } /* Set interface to promiscuous mode */ memset(&mreq, 0, sizeof(struct packet_mreq)); mreq.mr_ifindex = ifIndex; mreq.mr_type = PACKET_MR_PROMISC; if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { olsr_printf(1, "%s: setsockopt(PACKET_MR_PROMISC) error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } /* Get hardware (MAC) address */ memset(&req, 0, sizeof(struct ifreq)); if (if_indextoname(ifIndex, req.ifr_name) == NULL || ioctl(skfd, SIOCGIFHWADDR, &req) < 0) { olsr_printf(1, "%s: error retrieving MAC address: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } /* Bind the socket to the specified interface */ memset(&iface_addr, 0, sizeof(iface_addr)); iface_addr.sll_protocol = htons(ETH_P_ALL); iface_addr.sll_ifindex = ifIndex; iface_addr.sll_family = AF_PACKET; memcpy(iface_addr.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN); iface_addr.sll_halen = IFHWADDRLEN; if (bind(skfd, (struct sockaddr*)&iface_addr, sizeof(iface_addr)) < 0) { olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } /* Set socket to blocking operation */ if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) { olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } return skfd; } /* Create UDP (datagram) over IP socket to send encapsulated multicast packets over. * Returns the socket descriptor, or -1 if an error occurred. */ static int CreateEncapsulateSocket(int ifIndex) { int on = 1; char ifName[IFNAMSIZ]; struct sockaddr_in sin; /* Open UDP-IP socket */ int skfd = socket(PF_INET, SOCK_DGRAM, 0); if (skfd < 0) { olsr_printf(1, "%s: socket(PF_INET) error: %s\n", PLUGIN_NAME, strerror(errno)); return -1; } /* Enable sending to broadcast addresses */ if (setsockopt(skfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } /* Bind to the specific network interfaces indicated by ifIndex */ if (if_indextoname(ifIndex, ifName) == NULL || setsockopt(skfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, strlen(ifName) + 1) < 0) { olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(BMF_ENCAP_PORT); sin.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(skfd, (struct sockaddr*)&sin, sizeof(sin)) < 0) { olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } /* Set socket to blocking operation */ if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) { olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); return -1; } return skfd; } /* To save the state of the IP spoof filter for the EtherTunTap device */ static char EthTapSpoofState = '1'; static int DeactivateSpoofFilter(const char* ifName) { FILE* procSpoof; char procFile[FILENAME_MAX]; assert(ifName != NULL); /* Generate the procfile name */ sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName); procSpoof = fopen(procFile, "r"); if (procSpoof == NULL) { fprintf( stderr, "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n" "Are you using the procfile filesystem?\n" "Does your system support IPv4?\n" "I will continue (in 3 sec) - but you should manually ensure that IP spoof\n" "filtering is disabled!\n\n", procFile); sleep(3); return 0; } EthTapSpoofState = fgetc(procSpoof); fclose(procSpoof); procSpoof = fopen(procFile, "w"); if (procSpoof == NULL) { fprintf(stderr, "Could not open %s for writing!\n", procFile); fprintf( stderr, "I will continue (in 3 sec) - but you should manually ensure that IP" " spoof filtering is disabled!\n\n"); sleep(3); return 0; } syslog(LOG_INFO, "Writing \"0\" to %s", procFile); fputs("0", procSpoof); fclose(procSpoof); return 1; } static void RestoreSpoofFilter(const char* ifName) { FILE* procSpoof; char procFile[FILENAME_MAX]; assert(ifName != NULL); /* Generate the procfile name */ sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName); procSpoof = fopen(procFile, "w"); if (procSpoof == NULL) { fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procFile); } else { syslog(LOG_INFO, "Resetting %s to %c\n", procFile, EthTapSpoofState); fputc(EthTapSpoofState, procSpoof); fclose(procSpoof); } } /* Creates and brings up an EtherTunTap device e.g. "tun0" or "tap0" * (as specified in const char* EtherTunTapIfName) */ static int CreateLocalEtherTunTap(void) { struct ifreq ifreq; int etfd = open("/dev/net/tun", O_RDWR); int skfd; int ioctlres = 0; if (etfd < 0) { olsr_printf(1, "%s: open() error: %s\n", PLUGIN_NAME, strerror(errno)); return -1; } memset(&ifreq, 0, sizeof(ifreq)); /* Specify either the IFF_TAP flag for Ethernet frames, or the IFF_TUN flag for IP. * Specify IFF_NO_PI for not receiving extra meta packet information. */ if (strncmp(EtherTunTapIfName, "tun", 3) == 0) { ifreq.ifr_flags = IFF_TUN; TunOrTap = TT_TUN; } else { ifreq.ifr_flags = IFF_TAP; TunOrTap = TT_TAP; } ifreq.ifr_flags |= IFF_NO_PI; strcpy(ifreq.ifr_name, EtherTunTapIfName); if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0) { olsr_printf(1, "%s: ioctl() error: %s\n", PLUGIN_NAME, strerror(errno)); close(etfd); return -1; } memset(&ifreq, 0, sizeof(ifreq)); strcpy(ifreq.ifr_name, EtherTunTapIfName); ifreq.ifr_addr.sa_family = AF_INET; skfd = socket(PF_INET, SOCK_DGRAM, 0); if (skfd >= 0) { if (ioctl(skfd, SIOCGIFADDR, &ifreq) < 0) { /* EtherTunTap interface does not yet have an IP address. * Give it a dummy IP address "1.2.3.4". */ struct sockaddr_in *inaddr = (struct sockaddr_in *)&ifreq.ifr_addr; inet_aton("1.2.3.4", &inaddr->sin_addr); ioctlres = ioctl(skfd, SIOCSIFADDR, &ifreq); if (ioctlres >= 0) { /* Bring EtherTunTap interface up (if not already) */ ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq); if (ioctlres >= 0) { ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING); ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq); } } /* if (ioctlres >= 0) */ } /* if (ioctl...) */ } /* if (skfd >= 0) */ if (skfd < 0 || ioctlres < 0) { olsr_printf( 1, "%s: Error bringing up EtherTunTap interface: %s\n", PLUGIN_NAME, strerror(errno)); close(etfd); if (skfd >= 0) { close(skfd); } return -1; } /* if (skfd < 0 || ioctlres < 0) */ /* Set the multicast flag on the interface. TODO: Maybe also set * IFF_ALLMULTI. */ memset(&ifreq, 0, sizeof(ifreq)); strcpy(ifreq.ifr_name, EtherTunTapIfName); ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq); if (ioctlres >= 0) { ifreq.ifr_flags |= IFF_MULTICAST; ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq); } if (ioctlres < 0) { olsr_printf( 1, "%s: Error setting the multicast flag on EtherTunTap interface: %s\n", PLUGIN_NAME, strerror(errno)); } close(skfd); /* Deactivate IP spoof filter for EtherTunTap device */ DeactivateSpoofFilter(ifreq.ifr_name); return etfd; } static int IsNullMacAddress(char* mac) { int i; assert(mac != NULL); for (i = 0; i < IFHWADDRLEN; i++) { if (mac[i] != 0) return 0; } return 1; } int CreateBmfNetworkInterfaces(void) { int skfd; struct ifconf ifc; int numreqs = 30; struct ifreq* ifr; int n; EtherTunTapFd = CreateLocalEtherTunTap(); if (EtherTunTapFd < 0) { olsr_printf(1, "%s: error creating local EtherTunTap\n", PLUGIN_NAME); return -1; } skfd = socket(PF_INET, SOCK_DGRAM, 0); if (skfd < 0) { olsr_printf( 1, "%s: No inet socket available: %s\n", PLUGIN_NAME, strerror(errno)); return -1; } /* Retrieve the network interface configuration list */ ifc.ifc_buf = NULL; for (;;) { ifc.ifc_len = sizeof(struct ifreq) * numreqs; ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len); if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { olsr_printf(1, "%s: SIOCGIFCONF error: %s\n", PLUGIN_NAME, strerror(errno)); close(skfd); free(ifc.ifc_buf); return -1; } if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs) { /* Assume it overflowed; double the space and try again */ numreqs *= 2; assert(numreqs < 1024); continue; /* for (;;) */ } break; /* for (;;) */ } /* for (;;) */ /* For each item in the interface configuration list... */ ifr = ifc.ifc_req; for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++) { struct interface* olsrIntf; struct ifreq ifrAddr; int capturingSkfd; int encapsulatingSkfd = -1; struct TBmfInterface* newBmfInterface; /* ...find the OLSR interface structure, if any */ union olsr_ip_addr ipAddr; COPY_IP(&ipAddr, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr.s_addr); olsrIntf = if_ifwithaddr(&ipAddr); if (olsrIntf == NULL && ! IsNonOlsrBmfIf(ifr->ifr_name)) { /* Interface is neither OLSR interface, nor specified as non-OLSR BMF * interface in the BMF plugin parameter list */ continue; /* for (n = ...) */ } /* Retrieve the MAC address */ memset(&ifrAddr, 0, sizeof(struct ifreq)); strcpy(ifrAddr.ifr_name, ifr->ifr_name); if (ioctl(skfd, SIOCGIFHWADDR, &ifrAddr) < 0) { olsr_printf( 1, "%s: SIOCGIFHWADDR error for device \"%s\": %s\n", PLUGIN_NAME, ifrAddr.ifr_name, strerror(errno)); continue; /* for (n = ...) */ } if (IsNullMacAddress(ifrAddr.ifr_hwaddr.sa_data)) { continue; /* for (n = ...) */ } /* Create socket for capturing and sending multicast packets */ capturingSkfd = CreateCaptureSocket(if_nametoindex(ifr->ifr_name)); if (capturingSkfd < 0) { continue; /* for (n = ...) */ } if (olsrIntf != NULL) { /* Create socket for encapsulating and forwarding multicast packets */ encapsulatingSkfd = CreateEncapsulateSocket(olsrIntf->if_index); if (encapsulatingSkfd < 0) { close(capturingSkfd); continue; /* for (n = ...) */ } } newBmfInterface = malloc(sizeof(struct TBmfInterface)); if (newBmfInterface == NULL) { close(capturingSkfd); close(encapsulatingSkfd); continue; /* for (n = ...) */ } newBmfInterface->capturingSkfd = capturingSkfd; newBmfInterface->encapsulatingSkfd = encapsulatingSkfd; memcpy(newBmfInterface->macAddr, ifrAddr.ifr_hwaddr.sa_data, IFHWADDRLEN); memcpy(newBmfInterface->ifName, ifr->ifr_name, IFNAMSIZ); newBmfInterface->olsrIntf = olsrIntf; newBmfInterface->next = BmfInterfaces; BmfInterfaces = newBmfInterface; } /* for (n = ...) */ if (BmfInterfaces == NULL) { olsr_printf(1, "%s: could not initialize any network interface\n", PLUGIN_NAME); return -1; } close(skfd); free(ifc.ifc_buf); return 0; } /* Closes every socket on each network interface used by BMF: * -- the local EtherTunTap interface (e.g. "tun0" or "tap0") * -- for each OLSR-enabled interface: * - the socket used for capturing multicast packets * - the socket used for encapsulating packets * Also restores the network state to the situation before OLSR was * started */ void CloseBmfNetworkInterfaces() { int nClosed = 0; /* Close all opened sockets */ struct TBmfInterface* nextBmfIf = BmfInterfaces; while (nextBmfIf != NULL) { struct TBmfInterface* bmfIf = nextBmfIf; nextBmfIf = bmfIf->next; close(bmfIf->capturingSkfd); nClosed++; if (bmfIf->encapsulatingSkfd >= 0) { close(bmfIf->encapsulatingSkfd); nClosed++; } free(bmfIf); } /* Restore IP spoof filter for EtherTunTap device */ RestoreSpoofFilter(EtherTunTapIfName); close(EtherTunTapFd); nClosed++; olsr_printf(1, "%s: closed %d sockets\n", PLUGIN_NAME, nClosed); } #define MAX_NON_OLSR_IFS 10 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ]; static int nNonOlsrIfs = 0; int AddNonOlsrBmfIf(const char* ifName) { assert(ifName != NULL); if (nNonOlsrIfs >= MAX_NON_OLSR_IFS) { olsr_printf( 1, "%s: too many non-OLSR interfaces specified, maximum %d\n", PLUGIN_NAME, MAX_NON_OLSR_IFS); return 0; } strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ); nNonOlsrIfs++; return 1; } int IsNonOlsrBmfIf(const char* ifName) { int i; assert(ifName != NULL); for (i = 0; i < nNonOlsrIfs; i++) { if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0) return 1; } return 0; } --- NEW FILE: PacketHistory.h --- #ifndef _BMF_PACKETHISTORY_H #define _BMF_PACKETHISTORY_H /* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: PacketHistory.h,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */ #include /* ssize_t */ /* 2 bits per seen packet fingerping: * 11 = "seen recently", * 01 = "timing out" * 00 = "not seen recently" * Note that 10 is unused */ #define NBITS_PER_PACKET 2 #define NBITS_IN_UINT16 (sizeof(u_int16_t) * 8) #define NBITS_IN_UINT32 (sizeof(u_int32_t) * 8) #define NPACKETS_PER_ENTRY (NBITS_IN_UINT32 / NBITS_PER_PACKET) #define HISTORY_TABLE_SIZE ((1 << NBITS_IN_UINT16) / NPACKETS_PER_ENTRY) void InitPacketHistory(void); void MarkRecentPacket(unsigned char* buffer, ssize_t len); int CheckMarkRecentPacket(unsigned char* buffer, ssize_t len); void PrunePacketHistory(void*); #endif /* _BMF_PACKETHISTORY_H */