/* This file is part of IFS. IFS is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. IFS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with IFS. If not, see . */ using IFS.Logging; using System; using System.Threading; namespace IFS.Gateway { public struct GatewayInformation { public byte TargetNet; public byte GatewayNet; public byte GatewayHost; public byte HopCount; } /// /// Gateway Information Protocol (see http://xeroxalto.computerhistory.org/_cd8_/pup/.gatewayinformation.press!1.pdf) /// public class GatewayInformationProtocol : PUPProtocolBase { public GatewayInformationProtocol() { _gatewayInfoThread = new Thread(GatewayInformationWorker); _gatewayInfoThread.Start(); } /// /// Called by dispatcher to send incoming data destined for this protocol /// /// public override void RecvData(PUP p) { switch (p.Type) { case PupType.GatewayInformationRequest: SendGatewayInformationResponse(p); break; case PupType.GatewayInformationResponse: // Currently a no-op. Log.Write(LogComponent.MiscServices, String.Format("Gateway Information handler unimplemented.")); break; default: Log.Write(LogComponent.MiscServices, String.Format("Unhandled Gateway protocol {0} ({1})", p.Type, (int)p.Type)); break; } } private void SendGatewayInformationResponse(PUP p) { // // Pup Type: 201 (octal) // Pup ID: same as in Request Pup // Pup Contents: one or more groups of four bytes, each providing routing information for // one network, as follows: // // // // In each group, the first byte specifies the target network number. If the gateway host is // directly connected to that network, then the is zero and the and // describe the gateway’s connection to the network. // If the gateway host is not directly connected to the target network, then the second and // third bytes give the network and host numbers of another gateway through which the // responding gateway routes Pups to that network, and the fourth byte gives the hop count, // i.e., the number of additional gateways (not including itself) through which the responding // gateway believes a Pup must pass to reach the specified network. A hop count greater than // the constant maxHops (presently 15) signifies that the target network is believed to be // inaccessible. // byte[] infoArray = GetGatewayInformationArray(); PUPPort localPort = new PUPPort(DirectoryServices.Instance.LocalHostAddress, p.DestinationPort.Socket); // Response must contain our network number; this is used to tell clients what network they're on if they don't already know. PUPPort remotePort = new PUPPort(DirectoryServices.Instance.LocalNetwork, p.SourcePort.Host, p.SourcePort.Socket); PUP response = new PUP(PupType.GatewayInformationResponse, p.ID, remotePort, localPort, infoArray); Router.Instance.SendPup(response); } private static byte[] GetGatewayInformationArray() { // // We build the gateway information response from the RoutingTable that the Router maintains. // Since we do not at this time implement multi-hop routing, all networks known by the Router // are assumed to be directly connected and to have a hop-count of 0. // byte[] knownNetworks = Router.Instance.RoutingTable.GetKnownNetworks(); byte[] infoArray = new byte[knownNetworks.Length * 4]; for (int i = 0; i < knownNetworks.Length; i++) { GatewayInformation info = new GatewayInformation(); info.TargetNet = knownNetworks[i]; info.GatewayNet = DirectoryServices.Instance.LocalNetwork; info.GatewayHost = DirectoryServices.Instance.LocalHost; info.HopCount = 0; // all networks are directly connected byte[] entry = Serializer.Serialize(info); entry.CopyTo(infoArray, i * 4); } return infoArray; } private void GatewayInformationWorker() { uint infoPupID = (uint)(new Random().Next()); while (true) { // // From gatewayinformation.press: // "Each gateway host must also periodically broadcast Gateway Information Pups, as described above, // on all directly-connected networks. The frequency of this broadcast should be approximately one // every 30 seconds, and immediately whenever the gateway’s own routing table changes (see below). // These Pups should be sent from socket 2 to socket 2." // // At this time, we don't do anything with gateway information PUPs that we receive -- they could // at some point be used as originally intended, to dynamically update routing tables, but it would // require some serious security investments to make sure that the tables don't get poisoned. // However, even though we don't use them, some Alto software does. For example, the PUP libraries // used by Mazewar expect to get periodic updates or eventually it will assume the route is no longer // viable and drop connections. // // Delay 30 seconds Thread.Sleep(30000); byte[] infoArray = GetGatewayInformationArray(); // From us, on socket 2 PUPPort localPort = new PUPPort(DirectoryServices.Instance.LocalHostAddress, 2); // // The set of known networks is by default the set of directly-connected networks. // byte[] knownNetworks = Router.Instance.RoutingTable.GetKnownNetworks(); foreach (byte network in knownNetworks) { // Send a broadcast to the specified network PUPPort remotePort = new PUPPort(network, 0, 2); PUP infoPup = new PUP(PupType.GatewayInformationResponse, infoPupID++, remotePort, localPort, infoArray); Router.Instance.SendPup(infoPup); Log.Write(LogComponent.MiscServices, "Gateway Information packet sent to network {0}", network); } } } private Thread _gatewayInfoThread; } }