Ejemplo n.º 1
0
        public new EthernetPort this[string name]
        {
            get
            {
                if (!_switchPortInfos.ContainsKey(name))
                {
                    _switchPortInfos[name] = new SwitchPortInfo {
                        Mode = AccessMode.ACCESS, Vlan = Vlan.Get(1).Get()
                    };
                }

                return(base[name]);
            }
        }
Ejemplo n.º 2
0
        public void SetPort(string port, AccessMode mode, Option <ushort> vlan)
        {
            Log.Info(Hostname, $"Setting port {port} to {mode.ToString().ToLower()} mode");
            if (mode == AccessMode.TRUNK)
            {
                if (vlan != null)
                {
                    throw new Exception("Can't set VLAN for a trunking port!");
                }
            }

            if (vlan != null)
            {
                Log.Debug(Hostname, $"Accessing VLAN {vlan.Get()} on port {port}");
            }
            else
            {
                vlan = Vlan.Get(1);
            }

            _switchPortInfos[port] = new SwitchPortInfo {
                Mode = mode, Vlan = vlan.Get()
            };
        }
Ejemplo n.º 3
0
        protected virtual async Task Main()
        {
            Log.SetLevel(Log.Level.TRACE, Log.Groups.SHOW);
            Vlan.Register(1, "DEFAULT");
            Global.SetDeviceAutoStartup(true);
            //Global.SetPortAutoInit(true);

            /*
             * PC1 ---  eth0/1
             *       |
             *       | fa0/1
             *      SW1
             *       |  fa0/2
             *       |
             *       | fa0/1
             *      SW2
             *       |  fa0/1
             *       |
             * PC2 --- eth0/1
             */

            Log.Group("Initialize devices");

            var pc1 = new EthernetDevice("pc1");
            var pc2 = new EthernetDevice("pc2");

            var sw1 = new EthernetSwitch("sw1");
            var sw2 = new EthernetSwitch("sw2");

            Log.Group("Initialize ports");

            //pc ports
            pc1[ETH01].Init();
            pc2[ETH01].Init();

            //Connection from sw1 to pc1
            sw1[FA01].Init();

            //Connection from sw2 to pc2
            sw2[FA01].Init();

            //Connection from sw1 to sw2
            sw1[FA02].Init();
            sw2[FA02].Init();

            Log.Group("Connect ports");

            //Connect the pcs to the switches
            pc1[ETH01].ConnectTo(sw1[FA01]);
            pc2[ETH01].ConnectTo(sw2[FA01]);

            //Connect the switches to each other
            sw1[FA02].ConnectTo(sw2[FA02]);

            Log.Group("Set switchport modes");
            //Set the ports from pc to switch to access vlan 1
            sw1.SetPort(FA01, EthernetSwitch.AccessMode.ACCESS, Vlan.Get(1));
            sw2.SetPort(FA01, EthernetSwitch.AccessMode.ACCESS, Vlan.Get(1));

            //Set the ports from switch to switch to trunk
            sw1.SetPort(FA02, EthernetSwitch.AccessMode.TRUNK, null);
            sw2.SetPort(FA02, EthernetSwitch.AccessMode.TRUNK, null);

            //Log.Group("Current state");
            //Log.PrintState();

            //Learn MAC Addresses
            Log.Group("Learn MAC Addresses");

            /*
             * The API can be used with constructors (like this)
             */
            pc1[ETH01].SendSync(new EthernetFrame(Constants.ETHERNET_BROADCAST_PORT, pc1[ETH01], Vlan.Get(1), new RawPacket(new byte[100])));

            //Wait for all sending operations to be finished (you don't HAVE to wait...I just prefer doing so, cause the log is more readable)
            //This is necessary cause even tho you send this frame synchronously, all the connected devices create new tasks for incoming frames
            await Global.WaitForOperationsFinished();

            /*
             * Or like this (with a static methods and a scapy-esque construction method)
             */
            pc2[ETH01].SendSync(Ethernet(Constants.ETHERNET_BROADCAST_ADDRESS, pc2[ETH01]) < -/*Yes...this is indeed valid C#*/ Dot1Q(Vlan.Get(1)) < -RawPacket(new byte[100]));
            await Global.WaitForOperationsFinished();

            Log.Group("Send Ethernet frame over learned ports");
            pc1[ETH01].SendAsync(Ethernet(pc2[ETH01], pc1[ETH01]) | Dot1Q(Vlan.Get(1)) | RawPacket(new byte[100]));
            await Global.WaitForOperationsFinished();

            pc1[ETH01].Disconnect();
            pc2[ETH01].Disconnect();

            pc1.Shutdown();
            pc2.Shutdown();

            Log.PrintState();
            //Console.ReadKey();
        }
Ejemplo n.º 4
0
        public EthernetSwitch(string name) : base(name, null)
        {
            Log.Info(Hostname, "Initializing switch...");

            OnReceive = (frame, port) =>
            {
                if (frame.Data.Header.EtherType <= 1500)
                {
                    //Ok...so apparently, an Ethernet 2 frame is constructed the same way a normal Ethernet Frame is
                    //The only difference is in the Type field
                    //In Ethernet 2 this is 2 bytes which, in decimal, is >= 1536
                    //And in Ethernet <= 1500
                    //We also expect this frame to be untagged
                    //https://networkengineering.stackexchange.com/questions/5300/what-is-the-difference-between-ethernet-ii-and-802-3-ethernet

                    //TODO: Handle STP BPDU
                    return;
                }

                //If an untagged frame comes in, tag it
                if (!(frame.Data.Payload is Dot1QPDU))
                {
                    var type    = frame.Data.Header.EtherType;
                    var payload = frame.Data.Payload;

                    var dot1q = new Dot1QPDU
                    {
                        Header = new Dot1QHeader
                        {
                            Type   = type,
                            VlanID = _switchPortInfos[port.Name].Vlan == 0
                                ? Vlan.Get(1).Get()
                                : _switchPortInfos[port.Name].Vlan
                        },
                        Payload = payload
                    };

                    frame.Data.Payload          = dot1q;
                    frame.Data.Header.EtherType = 0x8100;

                    frame.Data.FCS = Util.GetFCS(frame);
                }

                lock (MACTable)
                {
                    if (!(MACTable.Any(a => a.Key == ((Dot1QPDU)frame.Data.Payload).Header.VlanID) &&
                          MACTable
                          .Where(a => a.Key == ((Dot1QPDU)frame.Data.Payload).Header.VlanID)
                          .Select(a => a.Value).FirstOr(new Dictionary <MACAddress, string>())
                          .Any(a => a.Key == frame.Data.Header.Src)))
                    {
                        Log.Warn(Hostname, $"Unknown MAC Address {frame.Data.Header.Src} for VLAN {((Dot1QPDU) frame.Data.Payload).Header.VlanID.ToMACAddressString()}");
                        Log.Debug(Hostname, $"Adding MAC Address {frame.Data.Header.Src} to MAC Address table for VLAN {((Dot1QPDU) frame.Data.Payload).Header.VlanID.ToMACAddressString()}...");

                        if (MACTable.All(a => a.Key != ((Dot1QPDU)frame.Data.Payload).Header.VlanID))
                        {
                            MACTable[((Dot1QPDU)frame.Data.Payload).Header.VlanID] = new Dictionary <MACAddress, string>();
                        }

                        var id = MACTable.Where(a => a.Key == ((Dot1QPDU)frame.Data.Payload).Header.VlanID).Select(a => a.Key).First();
                        MACTable[id].Add(frame.Data.Header.Src, port.Name);
                    }
                }

                var dstPort = string.Empty;
                if (frame.Data.Header.Dst != Constants.ETHERNET_BROADCAST_ADDRESS.Get())
                {
                    dstPort = MACTable.Where(a => a.Key == ((Dot1QPDU)frame.Data.Payload).Header.VlanID && a.Value.Any(b => b.Key == frame.Data.Header.Dst)).Select(a => a.Value.Where(b => b.Key == frame.Data.Header.Dst).Select(b => b.Value).FirstOr(null)).FirstOr(null);
                }

                //Flooding
                if (string.IsNullOrEmpty(dstPort))
                {
                    //Send to all ports except for source port
                    //Send to all access ports in the same VLAN
                    //Send to all trunk ports
                    var dstPorts = _switchPortInfos.Where(a => a.Key != port.Name && (a.Value.Vlan == ((Dot1QPDU)frame.Data.Payload).Header.VlanID || a.Value.Mode == AccessMode.TRUNK)).Select(a => a.Key).ToList();

                    if (!dstPorts.Any())
                    {
                        Log.Error(Hostname, "Can't send a frame to any possible port (Possible VLAN mismatch)! Dropping!");
                        return;
                    }

                    foreach (var s in dstPorts)
                    {
                        base[s].Send(frame, true);
                    }
                }
                else
                {
                    base[dstPort].Send(frame, true);
                }
            };

            PostConstruct();
        }