The essence of the problem
One of the worst scourges of an ethernet network are the so-called loops. They occur when (mainly due to the human factor) a ring is formed in the network topology. For example, two switch ports connected a patch cord (it often happens when two switches are replaced with one and without sticking stick everything that was) or they started a node along a new line and forgot to turn off the old one (the consequences can be sad and difficult to detect). As a result of such a loop, the packets begin to multiply, the switching tables get lost and the avalanche-like growth of traffic begins. In such conditions, the possible hang of network equipment and a complete disruption of the network.
In addition to these loops, it is not uncommon when a port (switch or network card) burns out, it begins to return received packets back to the network, most often the connection is negotiated at 10M, and the link rises even when the cable is disconnected. When there is only one such port in the segment, the consequences may not be so dire, but still very sensitive (users of whists and sevens are particularly affected). In any case, such things need to be fought mercilessly and understand the fact that intentionally or accidentally creating a loop, albeit for a short period of time, you can turn off a whole network segment.
Materiel
Fortunately, most modern managed switches, in one form or another, have loop detection functions (loopdetect, stp), and even more so, the stp protocol family allows you to specifically build a ring topology (to increase resiliency and reliability). But there is also a reverse side of the medal, it is not rare that one burned-down port can leave the whole area without communication. Or, say the same stp, the reorganization of the topology is far from instantaneous, the connection at this moment, of course, leaves much to be desired. In addition, some manufacturers are very careless about the implementation of loop detection protocols, say, DES-3016 (Glink) cannot define a loop at all if you simply connect its two ports.
Principles of detection
The principle of loop detection (loopdetect) is quite simple. A special packet with a broadcast address (intended for everyone) is sent to the network, and if it comes back, we consider that the network is looped off behind this interface. Further actions depend on the type of equipment and settings. Most often, the port is completely or partially blocked (in a separate vlan), the event is recorded in the logs, and snmp traps are sent. Here come the system administrators and emergency service.
')
If the entire network is managed, then it is not difficult to identify and eliminate the loop. But there are not so few networks where a chain of 5-6 unmanaged switches is connected to one port. Removing such a loop can take a lot of time and effort. The search process is reduced to the sequential disabling (enabling) of ports. To determine the presence of a loop, either the upstream managed switch or some sniffer (wireshark, tcpdump) is used. The first method is very dangerous due to the delay between turning the lock on and off, at best, users will simply have lags, and at worst, the loopdetect will work higher up the line and the much larger segment will fall off. In the second case, there is no danger for users, but it is much more difficult to determine the presence of a loop (especially in a small segment where there is little traffic), it’s still a sniffer thing, by definition, passive.
Do it yourself
As mentioned above, the hardware implementations of the loop search are more than enough. So without hesitation, I turn on wireshark and configure the filter and see what the switch does and how. Actually, everything is simple: an ethernet packet is sent to the port with the destination address
cf: 00: 00: 00: 00: 00 , type
0x9000 (
CTP ) and with unknown function number 256 (only two documents I found found). The destination address is Broadcast, so if there are loops back on the network, several copies of this packet should be returned.
First I decided on the libraries:
- I will use the pcapy library to capture and send raw packets;
- Dpkt will help me with packet generation;
- To play the sound, use pyaudeo and wave;
- Well, a few standard libraries.
Then everything is easy and simple. I create an instance of the pcapy.open_live class with the selected interface and add a filter to it. I create the first cycle, which will periodically send a packet, and inside it the second one, in order to capture and process the returned packets. If the captured packet is identical to the one sent, then +1 is added to the counter. If after the timeout expires more than one copy of the packet is received, the sound is played, and a loop message is displayed on the console.
The resulting script can be found below.
import pcapy, dpkt , sys import time , random, socket import pyaudio , wave def packetBody(length): rez = [] for x in range(0,length): rez.append(random.choice('0123456789abcdef') + random.choice('0123456789abcdef')) return rez class loopDetector: packetCount = 0 loopCount = 0 timeout = 1 def __init__(self,iface): self.iface = iface self.pcaper = pcapy.open_live(iface,100,1,500) self.Mac = '00:19:5b:'+':'.join(packetBody(3)) self.pcaper.setfilter('ether dst cf:00:00:00:00:00 and ether src %s' % self.Mac) wf = wave.open('alarm.wav', 'rb') self.pyA = pyaudio.PyAudio() self.stream = self.pyA.open(format = self.pyA.get_format_from_width(wf.getsampwidth()), channels = wf.getnchannels(), rate = wf.getframerate(), output = True) self.wfData = wf.readframes(100000) wf.close() def __del__(self): self.stream.stop_stream() self.stream.close() self.pyA.terminate() def PlayAlarm(self): self.stream.write(self.wfData) def Capture(self,hdr,data): if data == str(self.sPkt): self.packetReceived += 1 def Process(self): while 1: try: pktData = '00000001' + ''.join(packetBody(42)) self.sPkt = dpkt.ethernet.Ethernet(dst="cf0000000000".decode('hex'), src=''.join(self.Mac.split(':')).decode('hex'), type=36864,data=pktData.decode('hex')) endTime = time.time() + self.timeout print "Send packet to %s" % self.iface self.packetCount += 1 self.pcaper.sendpacket(str(self.sPkt)) self.packetReceived = 0 while time.time() < endTime: try: self.pcaper.dispatch(-1,self.Capture) except socket.timeout: pass if self.packetReceived > 1: self.loopCount += 1 print "Loop Detected. Duplication found %s" % self.packetReceived self.PlayAlarm() except KeyboardInterrupt: break print "Packets sent: ", self.packetCount , "Loops discovered : " , self.loopCount def main(): dev_list = {} n = 0 iface = '' for x in pcapy.findalldevs(): dev_list[n] = x n += 1 try: iface = dev_list[0] except KeyError: print "No device found" exit(1) if len(sys.argv) == 2: try: if sys.argv[1] in ['list','ls','all']: for x in dev_list: print 'Index:', x, 'Device name:' ,dev_list[x] return 0 else: iface = dev_list[int(sys.argv[1])] except KeyError: print "Invalid device id, trying use first" iface = dev_list[0] ld = loopDetector(iface) ld.Process() if __name__ == "__main__": main()
Link to the
original and source