Example #1
0
        /// <summary>
        /// Starts the transport.
        /// </summary>
        /// <param name="binding">The network binding the transport will use.</param>
        /// <param name="cbSocketBuffer">Size of the socket's send and receive buffers in bytes.</param>
        /// <param name="router">The <see cref="ISipMessageRouter" /> instance that will handle the routing of received messages.</param>
        /// <exception cref="SocketException">Thrown if there's a conflict with the requested and existing socket bindings.</exception>
        public void Start(NetworkBinding binding, int cbSocketBuffer, ISipMessageRouter router)
        {
            try
            {
                sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                sock.SendBufferSize           = cbSocketBuffer;
                sock.ReceiveBufferSize        = cbSocketBuffer;
                sock.IgnoreUdpConnectionReset = true;
                sock.Bind(binding);

                this.localEP   = (IPEndPoint)sock.LocalEndPoint;
                this.onRecv    = new AsyncCallback(OnReceive);
                this.recvBuf   = new byte[64 * 1024];
                this.recvEP    = new IPEndPoint(IPAddress.Any, 0);
                this.router    = router;
                this.traceMode = SipTraceMode.None;

                recvPending = true;
                sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onRecv, null);
            }
            catch
            {
                if (sock.IsOpen)
                {
                    sock.Close();
                }

                sock = null;
                throw;
            }
        }
Example #2
0
        /// <summary>
        /// Handles message packets received on the socket.
        /// </summary>
        /// <param name="ar">The async result.</param>
        private void OnSocketReceive(IAsyncResult ar)
        {
            int cb;
            Msg msg = null;

            byte[]     msgBuf;
            int        cbMsg;
            IPEndPoint fromEP = NetworkBinding.Any;

            using (TimedLock.Lock(router.SyncRoot))
            {
                if (!isOpen)
                {
                    return;
                }

                try
                {
                    cb = sock.EndReceiveFrom(ar, ref recvEP);
                    if (cb > 0)
                    {
                        msgBuf = router.DecryptFrame(recvBuf, cb, out cbMsg);
                        msg    = Msg.Load(new EnhancedMemoryStream(msgBuf));

                        fromEP = (IPEndPoint)recvEP;
                        msg._SetFromChannel(new ChannelEP(transport, fromEP));
                    }
                }
                catch (MsgException)
                {
                    // Ignore messages that can't be parsed
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }

                // Initiate the receive of the next message

                if (sock.IsOpen)
                {
                    try
                    {
                        sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onSocketReceive, null);
                    }
                    catch (Exception e)
                    {
                        SysLog.LogException(e, "LillTek UDP message channel is no longer able to receive messages.");
                    }
                }
            }

            if (msg != null)
            {
                msg._Trace(router, 2, "UDP: Recv", string.Format("From: {0}", fromEP));
                msg._Trace(router, 0, "Receive", string.Empty);
                router.OnReceive(this, msg);
            }
        }
Example #3
0
            public NetReflector(int port)
            {
                // Initialize the UDP service.

                udpSock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                udpSock.Bind(new IPEndPoint(IPAddress.Any, port));

                udpRecvBuf   = new byte[bufSize];
                udpRemoteEP  = new IPEndPoint(IPAddress.Any, 0);
                onUdpReceive = new AsyncCallback(OnUdpReceive);
                udpSock.BeginReceiveFrom(udpRecvBuf, 0, udpRecvBuf.Length, SocketFlags.None, ref udpRemoteEP, onUdpReceive, null);

                // Initialize the TCP service.

                onTcpReceive   = new AsyncCallback(OnTcpReceive);
                tcpConnections = new List <EnhancedSocket>();

                listener = new SocketListener();
                listener.SocketAcceptEvent +=
                    (s, a) =>
                {
                    lock (syncLock)
                    {
                        try
                        {
                            var sock      = (EnhancedSocket)s;
                            var remoteEP  = (IPEndPoint)sock.RemoteEndPoint;
                            var prefix    = PadPrefix(string.Format("TCP[{0}:{1}]:", remoteEP.Address, remoteEP.Port));
                            var recvState = new TcpRecvState()
                            {
                                Socket = sock, Buffer = new byte[bufSize]
                            };

                            if (TcpConnected != null)
                            {
                                TcpConnected(this, new NetReflectorEventArgs()
                                {
                                    Endpoint = remoteEP
                                });
                            }

                            Debug.WriteLine(string.Format("{0} Connect", prefix));
                            tcpConnections.Add(sock);

                            sock.BeginReceive(recvState.Buffer, 0, recvState.Buffer.Length, SocketFlags.None, onTcpReceive, recvState);
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine(string.Format("*** {0}: {1}", e.GetType().Name, e.Message));
                        }
                    }
                };

                listener.Start(new IPEndPoint(IPAddress.Any, port), 100);
            }
Example #4
0
            private void OnUdpReceive(IAsyncResult ar)
            {
                try
                {
                    var cbRecv   = udpSock.EndReceiveFrom(ar, ref udpRemoteEP);
                    var remoteEP = (IPEndPoint)udpRemoteEP;
                    var prefix   = PadPrefix(string.Format("UDP[{0}:{1}]:", remoteEP.Address, remoteEP.Port));

                    lock (syncLock)
                    {
                        Debug.WriteLine(string.Format("{0} Echoing [{1}] bytes", prefix, cbRecv));
                    }

                    var udpSendBuf = Helper.Extract(udpRecvBuf, 0, cbRecv);

                    udpSock.BeginSendTo(udpSendBuf, 0, cbRecv, SocketFlags.None, remoteEP,
                                        ar2 =>
                    {
                        try
                        {
                            udpSock.EndSendTo(ar2);
                        }
                        catch (SocketClosedException)
                        {
                            return;
                        }
                        catch
                        {
                            // Ignore
                        }
                    },
                                        null);

                    if (UdpReceived != null)
                    {
                        UdpReceived(this, new NetReflectorEventArgs()
                        {
                            Endpoint = remoteEP, Data = udpSendBuf
                        });
                    }

                    udpSock.BeginReceiveFrom(udpRecvBuf, 0, udpRecvBuf.Length, SocketFlags.None, ref udpRemoteEP, onUdpReceive, null);
                }
                catch (SocketClosedException)
                {
                    return;
                }
                catch (Exception e)
                {
                    lock (syncLock)
                    {
                        Debug.WriteLine(string.Format("*** {0}: {1}", e.GetType().Name, e.Message));
                    }
                }
            }
Example #5
0
        /// <summary>
        /// Opens a RADIUS client port using the <see cref="RadiusClientSettings" /> passed.
        /// </summary>
        /// <param name="settings">The client settings.</param>
        /// <remarks>
        /// <note>
        /// All successful calls to <see cref="Open" /> must eventually be matched
        /// with a call to <see cref="Close" /> so that system resources will be
        /// released promptly.
        /// </note>
        /// </remarks>
        public void Open(RadiusClientSettings settings)
        {
            using (TimedLock.Lock(this))
            {
                if (isOpen)
                {
                    throw new RadiusException("RADIUS client port is already open.");
                }

                sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                sock.Bind(settings.NetworkBinding);
                this.sock.SendBufferSize    = settings.SocketBuffer;
                this.sock.ReceiveBufferSize = settings.SocketBuffer;

                isOpen           = true;
                networkBinding   = settings.NetworkBinding;
                servers          = settings.Servers;
                secret           = settings.Secret;
                retryInterval    = settings.RetryInterval;
                maxTransmissions = settings.MaxTransmissions;
                realmFormat      = settings.RealmFormat;

                nextID       = 0;
                serverPos    = 0;
                transactions = new AuthTransaction[256];
                recvBuf      = new byte[TcpConst.MTU];
                sourceEP     = new IPEndPoint(IPAddress.Any, 0);
                onReceive    = new AsyncCallback(OnReceive);

                if (networkBinding.Address.Equals(IPAddress.Any))
                {
                    nasIPAddress = NetHelper.GetActiveAdapter();
                }
                else
                {
                    nasIPAddress = networkBinding.Address;
                }

                // Initiate reception of the first RADIUS packet.

                sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref sourceEP, onReceive, null);
            }
        }
Example #6
0
        /// <summary>
        /// Starts the DNS server using the settings passed.
        /// </summary>
        /// <param name="settings">The <see cref="DnsServerSettings" /> to be used to initialize the server.</param>
        /// <exception cref="InvalidOperationException">Thrown if the server has already started.</exception>
        public void Start(DnsServerSettings settings)
        {
            lock (syncLock)
            {
                if (sock != null)
                {
                    throw new InvalidOperationException("DNS server has already started.");
                }

                sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                sock.IgnoreUdpConnectionReset = true;
                sock.ReceiveBufferSize        =
                    sock.ReceiveBufferSize    = 1024 * 1024;  // $todo(jeff.lill): Hardcoded
                sock.Bind(settings.NetworkBinding);

                remoteEP = new IPEndPoint(IPAddress.Any, 0);
                sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref remoteEP, onReceive, sock);
            }
        }
Example #7
0
        /// <summary>
        /// Opens a UDP unicast socket.
        /// </summary>
        /// <param name="ep">The UDP endpoint to open.</param>
        /// <remarks>
        /// <para>
        /// Pass <b>ep.Address=IPAddress.Any</b> if the channel should be opened on all
        /// network adapters.
        /// </para>
        /// <para>
        /// Pass <b>ep.Port=0</b> if Windows should assign the socket's port.  The
        /// port assigned can be determined via the <see cref="Port" /> property.
        /// </para>
        /// </remarks>
        public void OpenUnicast(IPEndPoint ep)
        {
            using (TimedLock.Lock(router.SyncRoot))
            {
                this.sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                this.sock.Bind(ep);

                this.transport       = Transport.Udp;
                this.localEP         = router.NormalizeEP(new ChannelEP(Transport.Udp, (IPEndPoint)sock.LocalEndPoint));
                this.port            = localEP.NetEP.Port;
                this.sendQueue       = new PriorityQueue <Msg>();
                this.onSend          = new AsyncCallback(OnSend);
                this.sendMsg         = null;
                this.cbSend          = 0;
                this.sendBuf         = null;
                this.msgBuf          = new byte[TcpConst.MTU];
                this.cloudEP         = null;
                this.multicastInit   = false;
                this.broadcastClient = null;

                sendQueue.CountLimit = router.UdpMsgQueueCountMax;
                sendQueue.SizeLimit  = router.UdpMsgQueueSizeMax;

                this.onSocketReceive = new AsyncCallback(OnSocketReceive);
                this.recvBuf         = new byte[TcpConst.MTU];

                router.Trace(1, "UDP: OpenUnicast", "localEP=" + localEP.NetEP.ToString(), null);

                sock.IgnoreUdpConnectionReset = true;
                sock.SendBufferSize           = router.UdpUnicastSockConfig.SendBufferSize;
                sock.ReceiveBufferSize        = router.UdpUnicastSockConfig.ReceiveBufferSize;

                // Initiate the first async receive operation on this socket

                sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onSocketReceive, null);

                // Mark the channel as open.

                this.isOpen = true;
            }
        }
Example #8
0
        /// <summary>
        /// Handles the asynchronous reception of UDP packets on the socket.
        /// </summary>
        /// <param name="ar">The <see cref="IAsyncResult" /> instance.</param>
        private void OnReceive(IAsyncResult ar)
        {
            AuthTransaction transaction;
            RadiusPacket    response;

            byte[] rawPacket;
            int    cbPacket;

            // Complete receiving the packet and then initiate reception
            // of the next packet.  Note that I don't need a lock here
            // because there's never more than one async packet receive
            // outstanding at a given time.

            try
            {
                cbPacket  = sock.EndReceiveFrom(ar, ref sourceEP);
                rawPacket = (byte[])recvBuf.Clone();
                sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref sourceEP, onReceive, null);

                response = new RadiusPacket((IPEndPoint)sourceEP, rawPacket, cbPacket);
            }
            catch (SocketClosedException)
            {
                // We'll see this when the RADIUS server instance is closed.
                // I'm not going to report this to the event log.

                return;
            }
            catch (Exception e)
            {
                SysLog.LogException(e);
                return;
            }

            // Map the packet to a transaction and signal that the
            // authentication transaction is complete.

            using (TimedLock.Lock(this))
            {
                if (!isOpen)
                {
                    return;
                }

                transaction = transactions[response.Identifier];
                if (transaction == null)
                {
                    return;     // The transaction must have been aborted
                }
                // Validate the response authenticator, discarding the packet
                // if it's not valid.

                if (!response.VerifyResponseAuthenticator(transaction.Packet, secret))
                {
                    transaction.AsyncResult.Result = false;
                }
                else
                {
                    // Complete the outstanding transaction if the packet is a
                    // valid answer.

                    switch (response.Code)
                    {
                    case RadiusCode.AccessAccept:

                        transaction.AsyncResult.Result = true;
                        break;

                    case RadiusCode.AccessReject:

                        transaction.AsyncResult.Result = false;
                        break;

                    default:

                        return;         // Ignore all other answers
                    }
                }

                transaction.AsyncResult.Notify();
                transactions[response.Identifier] = null;
            }
        }
Example #9
0
        /// <summary>
        /// Called when a packet is received on the socket.
        /// </summary>
        /// <param name="ar">The async result.</param>
        private void OnReceive(IAsyncResult ar)
        {
            UdpBroadcastMessage message = null;
            IPEndPoint          recvEP  = null;
            int cbRecv = 0;

            lock (syncLock)
            {
                if (socket == null)
                {
                    return; // Client is closed
                }
                try
                {
                    // Parse received packet.

                    cbRecv = socket.EndReceiveFrom(ar, ref rawRecvEP);
                    recvEP = (IPEndPoint)rawRecvEP;

                    if (cbRecv == 0)
                    {
                        return;     // This happens when we receive an ICMP(connection-reset) from a
                    }
                    // remote host that's actively refusing an earlier packet transmission.
                    // We're just going to ignore this.

                    perf.TotalMessageRate.Increment();
                    perf.TotalByteRate.IncrementBy(cbRecv);

                    message = new UdpBroadcastMessage(Helper.Extract(recvBuf, 0, cbRecv), settings.SharedKey);

                    // Validate that the message timestamp is reasonable and discard
                    // messages with timestamps from too far in the past or too far
                    // in the future.

                    DateTime now = DateTime.UtcNow;

                    if (!Helper.Within(now, message.TimeStampUtc, settings.MessageTTL))
                    {
                        SysLog.LogWarning("UDP Broadcast message timestamp out of range. SystemTime={0}, Timestamp={1}, Source={2}, BroadcastGroup={3}",
                                          now.ToString("u"), message.TimeStampUtc.ToString("u"), recvEP, message.BroadcastGroup);
                        return;
                    }
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
                finally
                {
                    // Initiate the next receive.

                    try
                    {
                        rawRecvEP = new IPEndPoint(IPAddress.Any, 0);
                        socket.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref rawRecvEP, onReceive, null);
                    }
                    catch (Exception e)
                    {
                        SysLog.LogException(e);
                    }
                }

                // Process the message (if any).

                if (message == null || PauseNetwork)
                {
                    return;
                }

                ServerState server;
                ClientState client;

                switch (message.MessageType)
                {
                case UdpBroadcastMessageType.ServerRegister:

                    // Add the server to the tracking table if it's not already
                    // present and update its TTD.

                    if (!servers.TryGetValue(recvEP, out server))
                    {
                        server = new ServerState(recvEP, SysTime.Now + settings.ServerTTL);
                        servers.Add(recvEP, server);
                    }
                    else
                    {
                        server.TTD = SysTime.Now + settings.ServerTTL;
                    }

                    perf.AdminByteRate.IncrementBy(cbRecv);
                    perf.AdminMessageRate.Increment();
                    break;

                case UdpBroadcastMessageType.ServerUnregister:

                    // Remove the server from the tracking table (if present).

                    if (servers.ContainsKey(recvEP))
                    {
                        servers.Remove(recvEP);
                    }

                    perf.AdminByteRate.IncrementBy(cbRecv);
                    perf.AdminMessageRate.Increment();
                    break;

                case UdpBroadcastMessageType.ClientRegister:

                    // Add the client to the tracking table if it's not already
                    // present and update its TTD.

                    if (!clients.TryGetValue(recvEP, out client))
                    {
                        client = new ClientState(recvEP, message.BroadcastGroup, SysTime.Now + settings.ServerTTL);
                        clients.Add(recvEP, client);
                    }
                    else
                    {
                        client.TTD = SysTime.Now + settings.ServerTTL;
                    }

                    perf.AdminByteRate.IncrementBy(cbRecv);
                    perf.AdminMessageRate.Increment();
                    break;

                case UdpBroadcastMessageType.ClientUnregister:

                    // Remove the client from the tracking table (if present).

                    if (clients.ContainsKey(recvEP))
                    {
                        clients.Remove(recvEP);
                    }

                    perf.AdminByteRate.IncrementBy(cbRecv);
                    perf.AdminMessageRate.Increment();
                    break;

                case UdpBroadcastMessageType.Broadcast:

                    // Transmit the message to all clients the belong to the same broadcast group,
                    // if this is the master server.

                    if (!IsMaster)
                    {
                        return;
                    }

                    var packet     = GetMessageBytes(UdpBroadcastMessageType.Broadcast, message.SourceAddress, message.BroadcastGroup, message.Payload);
                    int cDelivered = 0;

                    foreach (var c in clients.Values)
                    {
                        if (c.BroadcastGroup == message.BroadcastGroup)
                        {
                            socket.SendTo(packet, c.EndPoint);
                            cDelivered++;
                        }
                    }

                    perf.BroadcastReceiveByteRate.IncrementBy(cbRecv);
                    perf.BroadcastReceiveMessageRate.Increment();
                    perf.BroadcastSendByteRate.IncrementBy(cbRecv * packet.Length);
                    perf.BroadcastSendMessageRate.IncrementBy(cDelivered);
                    break;
                }
            }
        }
Example #10
0
        /// <summary>
        /// Creates and starts a UDP broadcast server using the settings passed.
        /// </summary>
        /// <param name="settings">The server settings.</param>
        /// <param name="perfCounters">The application's performance counters (or <c>null</c>).</param>
        /// <param name="perfPrefix">The string to prefix any performance counter names (or <c>null</c>).</param>
        /// <remarks>
        /// <note>
        /// The <paramref name="perfCounters" /> parameter is type as <see cref="object" /> so that
        /// applications using this class will not be required to reference the <b>LillTel.Advanced</b>
        /// assembly.
        /// </note>
        /// </remarks>
        /// <exception cref="ArgumentException">Thrown if the settings passed are not valid.</exception>
        public UdpBroadcastServer(UdpBroadcastServerSettings settings, object perfCounters, string perfPrefix)
        {
            if (settings == null)
            {
                throw new ArgumentNullException("settings");
            }

            if (settings.Servers == null || settings.Servers.Length == 0)
            {
                throw new ArgumentException("Invalid UDP broadcast server settings: At least one broadcast server endpoint is required.");
            }

            if (perfCounters != null && !(perfCounters is PerfCounterSet))
            {
                throw new ArgumentException("Only instances of type [PerfCounterSet] may be passed in the [perfCounters] parameter.", "perfCounters");
            }

            this.startTime    = DateTime.UtcNow;
            this.closePending = false;
            this.settings     = settings;
            this.perf         = new Perf(perfCounters as PerfCounterSet, perfPrefix);

            bool found = false;

            for (int i = 0; i < settings.Servers.Length; i++)
            {
                var binding = settings.Servers[i];

                if (binding == settings.NetworkBinding)
                {
                    found = true;

                    // I'm going to special case the situation where the network binding address is ANY.
                    // In this case, one of the server endpoints must also include an ANY entry and I'll
                    // fill out with the loop back addres (127.1.0.1).

                    if (binding.IsAnyAddress)
                    {
                        settings.Servers[i] = new NetworkBinding(IPAddress.Loopback, settings.Servers[i].Port);
                    }

                    break;
                }
            }

            if (!found)
            {
                if (!settings.NetworkBinding.IsAnyAddress)
                {
                    throw new ArgumentException("Invalid UDP broadcast server settings: The current server's network binding must also be present in the Servers[] bindings.");
                }
            }

            // Initialize the clients and servers state.

            clients = new Dictionary <IPEndPoint, ClientState>();
            servers = new Dictionary <IPEndPoint, ServerState>();

            // Open the socket and start receiving packets.

            socket = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.IgnoreUdpConnectionReset = true;
            socket.ReceiveBufferSize        = settings.SocketBufferSize;
            socket.SendBufferSize           = settings.SocketBufferSize;

            socket.Bind(settings.NetworkBinding);

            onReceive = new AsyncCallback(OnReceive);
            recvBuf   = new byte[TcpConst.MTU];

            rawRecvEP = new IPEndPoint(IPAddress.Any, 0);
            socket.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref rawRecvEP, onReceive, null);

            // Crank up a timer to send the ClientRegister messages to the server cluster.

            registerTimer = new PolledTimer(settings.ClusterKeepAliveInterval, true);
            registerTimer.FireNow();    // Make sure that we send registration messages immediately

            bkTimer = new GatedTimer(new TimerCallback(OnBkTask), null, TimeSpan.Zero, settings.BkTaskInterval);
        }
Example #11
0
        /// <summary>
        /// Handles received packets.
        /// </summary>
        /// <param name="ar">The <see cref="IAsyncResult" /> instance.</param>
        private void OnReceive(IAsyncResult ar)
        {
            DnsRequest request = null;
            int        cbRecv;
            IPEndPoint ep;

            try
            {
                cbRecv = ((EnhancedSocket)ar.AsyncState).EndReceiveFrom(ar, ref remoteEP);
            }
            catch
            {
                cbRecv = 0;
            }

            if (sock == null)
            {
                return; // The server has stopped
            }
            if (cbRecv != 0)
            {
                // Parse the request packet

                try
                {
                    request = new DnsRequest();
                    request.ParsePacket(recvBuf, cbRecv);
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
            }

            // Save the remote EP and then initiate another async
            // packet receive.

            ep       = (IPEndPoint)remoteEP;
            remoteEP = new IPEndPoint(IPAddress.Any, 0);

            sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref remoteEP, onReceive, sock);

            // Process the request and transmit the response (if there is one).

            if (request != null && RequestEvent != null)
            {
                var args = new DnsServerEventArgs(ep, request);

                RequestEvent(this, args);
                if (args.Response != null)
                {
                    byte[] sendBuf;
                    int    cbSend;

                    // $todo(jeff.lill):
                    //
                    // Remove this exception code after figuring out why the
                    // response's QName field is sometimes NULL.

                    try
                    {
                        sendBuf = args.Response.FormatPacket(out cbSend);
                    }
                    catch
                    {
                        SysLog.LogError("DNS Formatting Error:\r\n\r\n" +
                                        args.Request.GetTraceDetails(ep.Address) +
                                        "\r\n" +
                                        args.Response.GetTraceDetails(ep.Address));
                        throw;
                    }

                    lock (syncLock)
                    {
                        if (sock != null)
                        {
                            sock.SendTo(sendBuf, cbSend, SocketFlags.None, args.RemoteEP);
                        }
                    }
                }
            }
        }
Example #12
0
        /// <summary>
        /// Handle asynchronous packet reception.
        /// </summary>
        /// <param name="ar">The operation's <see cref="IAsyncResult" /> instance.</param>
        private void OnReceive(IAsyncResult ar)
        {
            RadiusPacket request = null;
            ServerState  state   = null;
            int          cbRecv;

            using (TimedLock.Lock(this))
            {
                // Finish receiving the next request packet

                try
                {
                    cbRecv = sock.EndReceiveFrom(ar, ref remoteEP);
                }
                catch (SocketClosedException)
                {
                    // We'll see this when the RADIUS server instance is closed.
                    // I'm not going to report this to the event log.

                    return;
                }
                catch (Exception e)
                {
                    // I'm going to assume that something really bad has
                    // happened to the socket, log the exception and then
                    // return without initiating another receive.  This
                    // effectively stops the server.

                    SysLog.LogException(e);
                    return;
                }

                // Parse the request.  We're going to initiate the
                // authentication below, outside of the lock.

                try
                {
                    request = new RadiusPacket((IPEndPoint)remoteEP, recvBuf, cbRecv);

                    // Unit tests can use this hook to monitor incoming packets
                    // as well cause them to be ignored.

                    if (DiagnosticHook != null && !DiagnosticHook(this, request))
                    {
                        request = null;
                    }

                    if (request != null && request.Code == RadiusCode.AccessRequest)
                    {
                        state = new ServerState(this);
                    }
                    else
                    {
                        // Ignore all RADIUS requests except for Access-Request

                        request = null;
                    }
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }

                // Initiate reception of the next request

                try
                {
                    sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref remoteEP, onReceive, null);
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
            }

            if (request == null)
            {
                return; // We're ignoring the packet
            }
            // Validate the packet and the NAS

            RadiusNasInfo nasInfo;
            IPAddress     nasIPAddress;

            byte[] nasIdentifier;
            string userName;
            string realm;
            string account;

            byte[] encryptedPassword;
            string password;

            if (!request.GetAttributeAsAddress(RadiusAttributeType.NasIpAddress, out nasIPAddress) &&
                !request.GetAttributeAsBinary(RadiusAttributeType.NasIdentifier, out nasIdentifier))
            {
                // Access-Request packets are required by RFC 2865 to have either a NAS-IP-Address
                // or a NAS-IP-Identifier attribute.  Discard any packets that don't have one
                // of these.

                return;
            }

            if (!request.GetAttributeAsText(RadiusAttributeType.UserName, out userName) ||
                !request.GetAttributeAsBinary(RadiusAttributeType.UserPassword, out encryptedPassword))
            {
                // The User-Name attribute is required by RFC 2865 and this implementation
                // requires a User-Password attribute.  Ignore packets without these.

                return;
            }

            // Parse the realm and account from the user name

            Helper.ParseUserName(realmFormat, userName, out realm, out account);

            // Lookup the NAS shared secret and decrypt the password.

            nasInfo = GetNasInfo(state, request.SourceEP.Address);
            if (nasInfo == null)
            {
                if (defSecret == null)
                {
                    // Not being able to find information about a NAS device could
                    // represent a serious security problem or attack so I'm going
                    // to log this.

                    Log(state, false, RadiusLogEntryType.UnknownNas, realm, account, "RADIUS: Unknown NAS device NAS=[{0}].", request.SourceEP);
                    return;
                }

                nasInfo = new RadiusNasInfo(request.SourceEP.Address, defSecret);
            }

            password = request.DecryptUserPassword(encryptedPassword, nasInfo.Secret);

            // Perform the authentication, compute the response
            // authenticator and then send a response packet.

            RadiusPacket response;

            if (Authenticate(state, realm, account, password))
            {
                Log(state, true, RadiusLogEntryType.Authentication, realm, account,
                    "Authenticated: realm=[{0}] account=[{1}] NAS=[{2}]", realm, account, request.SourceEP);

                response = new RadiusPacket(RadiusCode.AccessAccept, request.Identifier, null,
                                            new RadiusAttribute(RadiusAttributeType.ServiceType, (int)RadiusServiceType.Login));
            }
            else
            {
                Log(state, false, RadiusLogEntryType.Authentication, realm, account,
                    "Authentication Fail: realm=[{0}] account=[{1}] NAS=[{2}]", realm, account, request.SourceEP);

                response = new RadiusPacket(RadiusCode.AccessReject, request.Identifier, null);
            }

            response.ComputeResponseAuthenticator(request, nasInfo.Secret);

            try
            {
                sock.SendTo(response.ToArray(), request.SourceEP);
            }
            catch (SocketClosedException)
            {
                // We'll see this when the RADIUS server instance is closed.
                // I'm not going to report this to the event log.
            }
            catch (Exception e)
            {
                SysLog.LogException(e);
            }
        }
Example #13
0
        /// <summary>
        /// Opens a UDP multicast socket.
        /// </summary>
        /// <param name="adapter">The network adapter to bind this socket.</param>
        /// <param name="cloudEP">Specifies the multicast group and port.</param>
        /// <remarks>
        /// <para>
        /// Pass <b>adapter=IPAddress.Any</b> to bind the socket to all available network
        /// adapters.
        /// </para>
        /// <note>
        /// A valid port and address must be specified in <b>cloudEP</b>.
        /// </note>
        /// </remarks>
        public void OpenMulticast(IPAddress adapter, IPEndPoint cloudEP)
        {
            if (cloudEP.Address.Equals(IPAddress.Any))
            {
                throw new MsgException("Invalid multicast address.");
            }

            if (cloudEP.Port == 0)
            {
                throw new MsgException("Invalid multicast port.");
            }

            using (TimedLock.Lock(router.SyncRoot))
            {
                this.sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                this.sock.ReuseAddress             = true;
                this.sock.EnableBroadcast          = true;
                this.sock.MulticastTTL             = MulticastTTL;
                this.sock.MulticastLoopback        = true;
                this.sock.IgnoreUdpConnectionReset = true;

                this.sock.Bind(new IPEndPoint(adapter, cloudEP.Port));

                // The framework throws an exception if there is no connected network connection
                // when we attempt to add the socket to the multicast group.  I'm going to catch
                // this exception and track that this didn't work and then periodically retry
                // the operation.

                try
                {
                    this.sock.MulticastGroup = cloudEP.Address;
                    this.multicastInit       = true;
                }
                catch
                {
                    this.multicastInit = false;
                }

                this.transport = Transport.Multicast;
                this.localEP   = router.NormalizeEP(new ChannelEP(Transport.Udp, router.UdpEP));
                this.port      = cloudEP.Port;
                this.sendQueue = new PriorityQueue <Msg>();
                this.onSend    = new AsyncCallback(OnSend);
                this.sendMsg   = null;
                this.cbSend    = 0;
                this.sendBuf   = null;
                this.msgBuf    = new byte[TcpConst.MTU];
                this.cloudEP   = cloudEP;

                this.onSocketReceive = new AsyncCallback(OnSocketReceive);
                this.recvBuf         = new byte[TcpConst.MTU];

                sendQueue.CountLimit = router.UdpMsgQueueCountMax;
                sendQueue.SizeLimit  = router.UdpMsgQueueSizeMax;

                router.Trace(1, "UDP: OpenMulticast",
                             string.Format("cloudEP={0} localEP={1} adaptor={2} NIC={3}",
                                           cloudEP, localEP.NetEP, adapter, NetHelper.GetNetworkAdapterIndex(adapter)), null);

                sock.SendBufferSize    = router.UdpMulticastSockConfig.SendBufferSize;
                sock.ReceiveBufferSize = router.UdpMulticastSockConfig.ReceiveBufferSize;

                // Initiate the first async receive operation on this socket

                sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onSocketReceive, null);

                // Mark the channel as open.

                this.isOpen = true;
            }
        }
Example #14
0
        /// <summary>
        /// Called when a packet is received by the socket from a remote endpoint.
        /// </summary>
        /// <param name="ar">The <see cref="IAsyncResult" />.</param>
        private void OnReceive(IAsyncResult ar)
        {
            byte[]     packet   = null;
            IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
            int        cb;
            SipMessage message;

            recvPending = false;

            if (sock == null || recvBuf == null)
            {
                return;
            }

            try
            {
                cb = sock.EndReceiveFrom(ar, ref recvEP);
            }
            catch (Exception e)
            {
                // Log the exception if the socket appears to be open and then submit
                // another receive request.

                if (sock.IsOpen)
                {
                    SysLog.LogException(e);

                    try
                    {
                        recvEP = new IPEndPoint(IPAddress.Any, 0);
                        sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onRecv, null);
                    }
                    catch (Exception e2)
                    {
                        SysLog.LogException(e2, "SIP UDP transport is no longer able to receive packets.");
                    }
                }

                return;
            }

            // $todo(jeff.lill): This is where I need to add source filtering.

            // Make a copy of what we received before initiating the next packet receive.

            try
            {
                packet   = Helper.Extract(recvBuf, 0, cb);
                remoteEP = (IPEndPoint)recvEP;
            }
            catch (Exception e)
            {
                SysLog.LogException(e);
            }

            // Initiate the receive of the next message

            lock (syncLock)
            {
                if (sock == null || !sock.IsOpen)
                {
                    return;
                }

                try
                {
                    recvEP      = new IPEndPoint(IPAddress.Any, 0);
                    recvPending = true;
                    sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onRecv, null);
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
            }

            // Parse and dispatch the message

            if (packet == null)
            {
                return;
            }

            // It looks like SIP clients like X-Lite send 4 byte CRLF CRLF messages
            // periodically over UDP to keep NAT mappings alive.  I'm going to
            // ignore these messages.

            if (packet.Length == 4)
            {
                return;
            }

            // Looks like we have a real message.

            try
            {
                try
                {
                    message = SipMessage.Parse(packet, true);
                }
                catch (Exception e)
                {
                    SipHelper.Trace(string.Format("UDP: UNPARSABLE message received  from {0}: [{1}]", remoteEP, e.Message), Helper.FromUTF8(packet));
                    throw;
                }

                message.SourceTransport = this;
                message.RemoteEndpoint  = remoteEP;
            }
            catch (SipException e)
            {
                e.BadPacket      = packet;
                e.SourceEndpoint = remoteEP;
                SysLog.LogException(e);
                return;
            }
            catch (Exception e)
            {
                SipException sipException;

                sipException                = new SipException("Error parsing SIP message.", e);
                sipException.Transport      = string.Format("UDP [{0}]", localEP);
                sipException.BadPacket      = packet;
                sipException.SourceEndpoint = remoteEP;

                SysLog.LogException(sipException);
                return;
            }

            if (disabled)
            {
                return;
            }

            if ((traceMode & SipTraceMode.Receive) != 0)
            {
                SipHelper.Trace(string.Format("UDP: received from {0}", remoteEP), message);
            }

            router.Route(this, message);
        }
Example #15
0
        /// <summary>
        /// Called when a packet is received on the socket.
        /// </summary>
        /// <param name="ar">The async result.</param>
        private void OnReceive(IAsyncResult ar)
        {
            UdpBroadcastMessage message = null;
            IPEndPoint          recvEP;
            int cbRecv;

            lock (syncLock)
            {
                if (socket == null)
                {
                    return; // Client is closed
                }
                try
                {
                    // Parse received packet.

                    cbRecv = socket.EndReceiveFrom(ar, ref rawRecvEP);
                    recvEP = (IPEndPoint)rawRecvEP;

                    if (cbRecv == 0)
                    {
                        return;     // This happens when we receive an ICMP(connection-reset) from a
                    }
                    // remote host that's actively refusing an earlier packet transmission.
                    // We're just going to ignore this.

                    message = new UdpBroadcastMessage(Helper.Extract(recvBuf, 0, cbRecv), settings.SharedKey);

                    // Validate that the message timestamp is reasonable and discard
                    // messages with timestamps from too far in the past or too far
                    // in the future.

                    DateTime now = DateTime.UtcNow;

                    if (!Helper.Within(now, message.TimeStampUtc, settings.MessageTTL))
                    {
                        SysLog.LogWarning("UDP Broadcast message timestamp out of range. SystemTime={0}, Timestamp={1}, Source={2}, BroadcastGroup={3}",
                                          now.ToString("u"), message.TimeStampUtc.ToString("u"), recvEP, message.BroadcastGroup);
                        return;
                    }
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
                finally
                {
                    // Initiate the next receive.

                    try
                    {
                        rawRecvEP = new IPEndPoint(IPAddress.Any, 0);
                        socket.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref rawRecvEP, onReceive, null);
                    }
                    catch (Exception e)
                    {
                        SysLog.LogException(e);
                    }
                }
            }

            // Process the message (if any) outside of the lock.  Note that only
            // broadcast messages are processed by UDP broadcast clients.

            if (message == null || message.MessageType != UdpBroadcastMessageType.Broadcast || PauseNetwork)
            {
                return;
            }

            // Ignore messages that don't match the broadcast group.

            if (settings.BroadcastGroup != message.BroadcastGroup)
            {
                return;
            }

            if (PacketReceived != null)
            {
                PacketReceived(this, new UdpBroadcastEventArgs(message.SourceAddress, message.Payload));
            }
        }
Example #16
0
        /// <summary>
        /// Creates and starts a UDP broadcast client using the settings passed.
        /// </summary>
        /// <param name="settings">The client settings.</param>
        /// <exception cref="ArgumentException">Thrown if the settings passed are not valid.</exception>
        public UdpBroadcastClient(UdpBroadcastClientSettings settings)
        {
            this.settings = settings;

            if (settings == null)
            {
                throw new ArgumentNullException("settings");
            }

            if (settings.Servers == null || settings.Servers.Length == 0)
            {
                throw new ArgumentException("Invalid UDP broadcast client settings: At least one broadcast server endpoint is required.");
            }

            this.servers = new List <IPEndPoint>();

            // $hack(jeff.lill)
            //
            // This is a bit of a hack to discover the source IP address to use for this instance.
            // If the configured NetworkBinding specifies a specific interface, then we'll use
            // this, otherwise we'll use the IPv4 address for the first active network adaptor we find.
            // In a perfect world, I'd send a packet to the broadcast servers and have it respond with
            // the UDP source address it sees that would discover the actual IP address.  This hack
            // should work 99% of the time though.

            if (!settings.NetworkBinding.Address.Equals(IPAddress.Any))
            {
                this.sourceAddress = settings.NetworkBinding.Address;
            }
            else
            {
                this.sourceAddress = NetHelper.GetActiveAdapter();
            }

            // Open the socket and start receiving packets.

            socket = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.IgnoreUdpConnectionReset = true;
            socket.ReceiveBufferSize        = settings.SocketBufferSize;
            socket.SendBufferSize           = settings.SocketBufferSize;

            socket.Bind(settings.NetworkBinding);

            onReceive = new AsyncCallback(OnReceive);
            recvBuf   = new byte[8192];

            rawRecvEP = new IPEndPoint(IPAddress.Any, 0);
            socket.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref rawRecvEP, onReceive, null);

            // Crank up the timers.

            keepAliveTimer = new PolledTimer(settings.KeepAliveInterval, false);
            keepAliveTimer.FireNow();

            serverResolveTimer = new PolledTimer(settings.ServerResolveInterval, false);
            serverResolveTimer.FireNow();

            bkTimer = new GatedTimer(new TimerCallback(OnBkTask), null, TimeSpan.Zero, settings.BkTaskInterval);

            // Sleep for a couple seconds to allow the server DNS lookups to complete.

            Thread.Sleep(2000);
        }