Iptables: Matching packets leaving a bridged interface - linux-kernel

Apologies if you've already seen this over on serverfault, but it's been on there for several days now, and I've had absolutely no traction...
I'm building a firewall configuration tool based on iptables, and trying to get a "bump in the wire" scenario working.
Given a setup with eth0 and eth1 in a bridge br0 and a third interface eth2:
| | |
eth0 eth1 eth2
| == br0== | |
| |
| |
--- linux node ---
In this scenario, lets say I want TCP port 80 traffic to be dropped if it is going to the network attached to eth0, but allow it to eth1.
I am therefore trying to reliably match packets that go out over the specific interface eth0.
If I add the following iptables rule in the filter table:
-A FORWARD -o br0 --physdev-out eth0 -j LOG
Given a packet that originates from eth1 (the other half of the bridge), then the rule matches just fine, logging:
... IN=br0 OUT=br0 PHYSIN=eth2 PHYSOUT=eth1 ...
However if the packet origniates from eth2, then the rule no longer matches.
I appears that the routing algorithm can't determine which of the bridged interfaces to choose, so the packet is sent out over both interfaces in the bridge.
If I add another more promiscuous log rule, then I get the following log output for that packet:
... IN=eth2 OUT=br0 ...
My guess is that in the first case, the routing algorithm can just choose the other interface on the bridge since that packet shouldn't go out the way it came. In the second case, it hasn't chosen a specific interface and you then get no physdev information at all!
However, if the bridge has learned the destination MAC address (as shown by brctl showmacs br0) then it can determine the correct interface, and you get physdev informatino again.
(There is also a third case: where the bridge comprises three interfaces that this seems to apply to , then it still can't establish a single interface to send the packet on just be excluding the source interface.)
So, the question is, how can I reliably match packets the go out over eth0 regardless?
Given the example I gave at the start, it is not enough to just match packets that will be routed out over multiple interfaces, one of which is eth0 (though that would be useful in other scenarios). I want to be able to treat the traffic for eth0 and eth1 differently, allowing the traffic to eth1, but not eth0.

Reasons for observed behviour
The reason that iptables doesn't get the physical bridge information when the packet arrives from a non-bridged interface is that the packet has never been near the bridging mechanism, even though at this point we know we are sending it out on the bridge.
In the case where the packet did arrive over a bridge port, but it is an N>2 bridge, the problem is that the iptables PHYSDEV extention only provides for their being one value for "out", so it just doesn't bother telling us if there are two.
Solution
Use ebtables instead of iptables. The ebtables OUTPUT chain will know which physical bridged interface it is sending packets out on.
In the scenario above, where you want to filter packets that are leaving via a specific bridged interface (eth0), regardless of how it arrived into the system, add an ebtables rule along the following lines:
-A OUTPUT -o eth0 -j <target>
In a more complex scenario, where you want to filter packets arriving from a specific interface, and leaving via a bridged interface, it gets harder. Say we want to drop all traffic from eth2 (non-bridged) going to eth0 (bridged as part of br0) we need to add this rule to iptables:
-A FORWARD -i eth2 -o br0 -j MARK --set-mark 1234
This will mark any packet that comes from eth2 and is bound for the bridge. Then we add this rule to ebtables:
-A OUTPUT -o eth0 --mark 1234 -j DROP
Which will DROP any packet marked by iptables (as being from eth2) that is egressing via the specific bridge port eth0.
Acknowledgements
Thanks goes out to Pascal Hambourg over at the netfilter iptables mailing list for his help in coming up with this solution.

Related

Is tcpdump 100% reliable on outgoing connection?

I'm working on a server.
Its doing health check to another server, like a simple tcp open connection
Basically my tcpdump says that the packet (the health check tcp sYn packet) is going out of my interface.
But, the Firewall doesnt see anything.
I have doubt if the packet is going outside the server at all, or the problem is on the switch.
Is there a way to be sure about this?
Captured traffic == source of truth
It's possible for tcpdump to have false negatives (i.e. packets are sent but tcpdump doesn't record them). This can be due to hardware (CPU, RAM, disk) being maxed or if tcpdump's buffer size (-B) is too small. Likewise, it's possible your firewall isn't picking it up where it should.
It's highly unlikely for tcpdump to report a false positive. Tcpdump copies bytes from your network interface [0] and summarizes them in a text line (depending on your output options). If firewall rules from e.g. iptables would block traffic, tcpdump won't see the traffic. If tcpdump reports a packet, you can be sure it transited that interface.
[0]: If you're curious how tcpdump works at a lower level, use strace.
Flow-based troubleshooting
Flow-based troubleshooting can be required to figure out where packets get dropped in a network. For your network of server:A <-> B:switch:C <-> D:Firewall, we know that A sends it and D does not receive it. Thus you should check ports B and C to determine where the packet loss occurs. It's also possible that D reports a false negative. You can test both of these things by plugging this server directly into a different firewall that can take packet captures/monitor traffic.

Scapy Packet Filtering FROM an IP and with Destination Port 23

I am trying to set a scapy packet filter to ONLY capture packets that are coming FROM a particular source or IP address AND that are destined for PORT 23. This is the syntax I have so far but I think it is wrong because I think this syntax tells scapy to capture ONLY packets that are GOING TO this IP address.
pkt = sniff(filter='host 8.8.8.8 and port 23', prn=print_pkt)
I think this syntax is not doing what I need it do. I've tried searching for syntax that would tell scapy to only capture packets COMING FROM 8.8.8.8 but this is all I could find and I think it tells scapy to capture packets GOING TO 8.8.8.8. Is this correct?
Scapy filters are from a type called BPF, you can see the syntax here.
In your case, I think what you want to do is-
filter='src host 8.8.8.8 and dst port 23'
Your original syntax is not distinguishig between source and destination, so it will filter packets from/to ip 8.8.8.8 and from/to port 23.

Does Windows 7 store information about the MTU of a network?

I have the following network setup:
[Customizable Wireless AP] ----- [Windows 7 Laptop]
In other words, my Win7 laptop is connected to a wireless access point which I can configure. I am using the Wireshark packet analyzer to monitor ping traffic.
My process is:
Set MTU of the AP very low (500)
Verify AP MTU has taken effect
Start packet analyzer in Wireshark
Use ping www.google.com -f -l 700 to send an oversized packet
Actual Output:
Ping shows Packet needs to be fragmented but DF set., indicating that the MTU has been observed
Wireshark shows no traffic. No ICMP messages or traffic of any king.
Expected Output:
I expect ping to show Packet needs to be fragmented but DF set., indicating that the MTU has been observed
I expect Wireshark to show ICMP traffic where the AP informs Win7 that the packet is too large.
My Question:
How is Windows discovering or remembering the MTU without the AP (seemingly) ever informing it? Is there an MTU discovery mechanism built into Win7 that operates prior to the ping?
IPv4 uses Path MTU Discovery (PMTUD) to figure out the MTU and control the fragmentation. There is a 3-bit flag field in IP header that will determine how fragmentation of a packet should be performed:
bit 0: Reserved; must be zero
bit 1: Don't Fragment (DF)
bit 2: More Fragments (MF)
If the DF bit is set, then any device along the path with MTU smaller than the packet will drop it and send back an ICMP message requesting fragmentation. However, ICMP message might blocked due to security reason. Therefore you cannot see any of it.

Get data from the port of the switch a pc is connected to

I'm developing an inventory and audit of laboratories in our school. It needs to keep track if there are transfers of PCs in each laboratory. Each lab has its own network. So it's not even possible to know the transfers if by ip address alone. Is it possible to get data from the port of the switch the PCs are connected to?
Yes, if your switches support SNMP. You can track the PCs by the MAC addresses of their network interface cards (as long as they don't change). There is a few OIDs that might be interesting for getting this info. First of them is:
1.3.6.1.2.1.17.4.3.1.1 (dot1dTpFdbAddress):
A unicast MAC address for which the bridge has forwarding and/or filtering information.
If your network is really simple like one switch for the lab, no VLANs, etc. you can just walk the first OID and get the MAC addresses from the switch, cross-reference them with your database of PCs and check whatever you need to check.
If you do have VLANs or there are multiple labs connected to the single switch you would need to go deeper and find the port to which the PC is connected.
1.3.6.1.2.1.17.4.3.1.2 (dot1dTpFdbPort):
Either the value "0", or the port number of the port on which a frame having a source address equal to the value of the corresponding instance of dot1dTpFdbAddress has been seen.
1.3.6.1.2.1.17.1.4.1.2 (dot1dBasePortIfIndex):
The value of the instance of the ifIndex object, defined in MIB-II, for the interface corresponding to this port.
1.3.6.1.2.1.31.1.1.1.1 (ifName):
The textual name of the interface. The value of this object should be the name of the interface as assigned by the local device and should be suitable for use in commands entered at the device's `console'.
Below is the example (on some Linksys switch) of doing this manually but you can easily write a script to do just that and return the list of MAC addresses and ports they're learned on.
# snmpwalk -v2c -c "your_community" switch.example.com 1.3.6.1.2.1.17.4.3.1.1
SNMPv2-SMI::mib-2.17.4.3.1.1.64.85.57.242.44.224 = Hex-STRING: 40 55 39 F2 2C E0
Walking trough this OID will list all MAC addresses the switch has learned. In my example for simplicity there is only one MAC address (40:55:39:f2:2c:e0). Next you want to find the number of the bridge port that MAC address:
# snmpget -v2c -c "your_community" switch.example.com 1.3.6.1.2.1.17.4.3.1.2.64.85.57.242.44.224
SNMPv2-SMI::mib-2.17.4.3.1.2.64.85.57.242.44.224 = INTEGER: 6
The additional numbers you see in the OID are the dotted-decimal representation of the MAC address. After this you get the interface index from the bridge port number and finally the interface name (port name).
# snmpget -v2c -c "your_community" switch.example.com 1.3.6.1.2.1.17.1.4.1.2.6
SNMPv2-SMI::mib-2.17.1.4.1.2.6 = INTEGER: 6
# snmpget -v2c -c "your_community" switch.example.com 1.3.6.1.2.1.31.1.1.1.1.6
IF-MIB::ifName.6 = STRING: Port6
And you found out that a host with 40:55:39:f2:2c:e0 MAC address is connected to Port6. If you're dealing with some higher quality equipment (like Cisco) you should know that they might keep separate instances for each VLAN and use something called SNMP Community String Indexing where you add the Vlan index to your community string like this (for Vlan 123):
# snmpwalk -v2c -c "your_community"#123 switch.example.com 1.3.6.1.2.1.17.4.3.1.1

Multicast propagation with daisy chained multi NIC card PCs

Here is the topology under discussion:
NIC0 NIC0 NIC0
| | |
+-----+-----+ +------+-----+ +------+------+
---NIC1 NIC2---------NIC1 NIC2-----NIC1 NIC2---- . .
+----PC1----+ +----PC2-----+ +-----PC3-----+
I have stack of PC Boxes each having multiple (3) Nic Cards, one to interface with outside world, and others to be used to daisy chain for communication among themselves.
Q(1) Can someone suggest if I can somehow control "multicast traffic" on daisy chained systems without letting that mixed with traffic coming from NIC0(diagram below) Cards?
I am running Linux kernel on each boxes. I can give multicast address in the interface name, but my guess is that it would not guarantee the mixing of traffic if the NIC0 traffic also has same multicast IP, so, is ACL a answer?
Q(2) My application needs subscribe-notify setup, and that's why I need multicast. There are options such as using 0MQ that also use TCP based multicast(PGM). Will that protect me here somehow?
I don't know why you would daisy chain these computers. Before going any further, you should connect these machines with a switch.
Really, though, I don't understand what your questions is...

Resources