Example #1
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 #2
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 #3
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 #4
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 #5
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 #6
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 #7
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));
            }
        }