Example #1
0
        /// <summary>
        /// Removes a <see cref="DynDnsHostEntry" /> registration from the Dynamic
        /// DNS cluster.
        /// </summary>
        /// <param name="hostEntry">The host/IP address <see cref="DynDnsHostEntry" /> to be unregistered.</param>
        /// <remarks>
        /// <note>
        /// This method does not throw an exception if the registration is not present.
        /// </note>
        /// </remarks>
        /// <exception cref="InvalidOperationException">Thrown if the client has not been started.</exception>
        public void Unregister(DynDnsHostEntry hostEntry)
        {
            using (TimedLock.Lock(syncLock))
            {
                if (hosts.ContainsKey(hostEntry))
                {
                    // For UDP mode, we need to send two immediate Unregister message to each DNS
                    // server for the host entry.

                    if (settings.Mode == DynDnsMode.Udp && isOpen)
                    {
                        for (int i = 0; i < 2; i++)
                        {
                            DynDnsMessage message;
                            byte[]        packet;

                            message = new DynDnsMessage(DynDnsMessageFlag.OpUnregister, hostEntry);
                            packet  = message.ToArray(settings.SharedKey);

                            foreach (var nameServer in settings.NameServers)
                            {
                                socket.SendTo(packet, nameServer);
                            }
                        }
                    }

                    // Remove the host entry from the local table.

                    hosts.Remove(hostEntry);
                    Register();
                }
            }
        }
Example #2
0
        /// <summary>
        /// Completes a pending asynchronous socket connection attempt.
        /// </summary>
        /// <param name="ar">The <see cref="IAsyncResult" /> instance returned by the initiating call to <see cref="BeginConnect" />.</param>
        /// <exception cref="SocketException">Thrown if the connection could not be establised.</exception>
        /// <remarks>
        /// <note>
        /// All successful calls to <see cref="BeginConnect" /> should be eventually matched with a call to <see cref="EndConnect" />.
        /// </note>
        /// </remarks>
        public void EndConnect(IAsyncResult ar)
        {
            lock (syncLock)
            {
                if (isTcp)
                {
                    sock.EndConnect(ar);
                }
                else
                {
                    var addresses = Dns.EndGetHostAddresses(ar);

                    sock.Bind();

                    udpRemoteEndPoint = new IPEndPoint(addresses[0], remoteBinding.Port);
                    isUdpConnected    = true;

                    // $hack(jeff.lill)
                    //
                    // This is a minor hack.  Instead of adding the additional complexity of transmitting the
                    // connection packet asynchronously, I'm just going to make a synchronous call here.  This
                    // shouldn't ever block in real life since the socket send buffer starts out empty.

                    sock.SendTo(udpConnectPacket, udpRemoteEndPoint);

                    udpConnectPacket = null;   // Don't need this any longer
                }
            }
        }
Example #3
0
        /// <summary>
        /// Stops the server, removing it from the cluster.
        /// </summary>
        /// <remarks>
        /// <note>
        /// It is not an error to call this method then the instance has already been closed.
        /// </note>
        /// </remarks>
        public void Close()
        {
            lock (syncLock)
            {
                if (closePending || socket == null)
                {
                    return;
                }

                var packet = GetMessageBytes(UdpBroadcastMessageType.ServerUnregister);

                foreach (var server in settings.Servers)
                {
                    if (!PauseNetwork)
                    {
                        socket.SendTo(packet, server);
                    }
                }

                closePending = true;
            }

            // Sleep for a couple seconds so that any broadcast messages in transit
            // will still be retransmitted during the time it will take for the
            // other servers in the cluster to decide on a new master.

            Thread.Sleep(2000);

            socket.Close();
            socket = null;

            if (bkTimer != null)
            {
                bkTimer.Dispose();
                bkTimer = null;
            }

            servers.Clear();
            clients.Clear();

            GC.SuppressFinalize(this);
        }
Example #4
0
        /// <summary>
        /// Initiates an asynchronous operation to authenticate user credentials.
        /// </summary>
        /// <param name="realm">Specifies the authentication scope.</param>
        /// <param name="account">The account.</param>
        /// <param name="password">The password.</param>
        /// <param name="callback">The delegate to be called when the operation completes (or <c>null</c>).</param>
        /// <param name="state">Application defined state (or <c>null</c>).</param>
        /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the operation.</returns>
        /// <remarks>
        /// <note>
        /// All successful calls to <see cref="BeginAuthenticate" /> must eventually be
        /// matched by a call to <see cref="EndAuthenticate" />.
        /// </note>
        /// </remarks>
        public IAsyncResult BeginAuthenticate(string realm, string account, string password, AsyncCallback callback, object state)
        {
            AsyncResult     arAuth = new AsyncResult(null, callback, state);
            AuthTransaction transaction;
            RadiusPacket    packet;
            string          userName;
            int             ID;
            IPEndPoint      binding;

            using (TimedLock.Lock(this))
            {
                userName = Helper.GetUserName(realmFormat, realm, account);

                ID = GetTransactionID();
                if (ID == -1)
                {
                    throw new RadiusException("RADIUS client cannot track more than 256 simultaneous authentication requests.");
                }

                binding = GetServerBinding(ref serverPos);
                if (binding == NetworkBinding.Any)
                {
                    throw new RadiusException("None of the RADIUS server hosts resolve to an IP address.");
                }

                packet = new RadiusPacket(RadiusCode.AccessRequest, ID, Crypto.Rand(16));
                packet.Attributes.Add(new RadiusAttribute(RadiusAttributeType.UserName, userName));
                packet.Attributes.Add(new RadiusAttribute(RadiusAttributeType.UserPassword, packet.EncryptUserPassword(password, secret)));
                packet.Attributes.Add(new RadiusAttribute(RadiusAttributeType.NasIpAddress, nasIPAddress));

                transaction      = new AuthTransaction(userName, packet, serverPos, SysTime.Now + retryInterval, arAuth);;
                transactions[ID] = transaction;
                sock.SendTo(transaction.Packet.ToArray(), binding);

                arAuth.Result = null;
                arAuth.Started();
            }

            return(arAuth);
        }
Example #5
0
        /// <summary>
        /// Closes the instance, removing it from the broadcast group.
        /// </summary>
        /// <remarks>
        /// <note>
        /// It is not an error to call this method then the instance has already been closed.
        /// </note>
        /// </remarks>
        public void Close()
        {
            lock (syncLock)
            {
                if (socket != null)
                {
                    var packet = GetMessageBytes(UdpBroadcastMessageType.ClientUnregister, settings.BroadcastGroup);

                    foreach (var server in servers)
                    {
                        if (!PauseNetwork)
                        {
                            try
                            {
                                socket.SendTo(packet, server);
                            }
                            catch (Exception e)
                            {
                                SysLog.LogException(e);
                            }
                        }
                    }

                    socket.Close();
                    socket = null;
                }

                if (bkTimer != null)
                {
                    bkTimer.Dispose();
                    bkTimer = null;
                }
            }

            GC.SuppressFinalize(this);
        }
Example #6
0
        /// <summary>
        /// Asynchronously transmits the message passed to the destination
        /// indicated by the <see paramref="remoteEP" /> parameter.
        /// </summary>
        /// <param name="remoteEP">The destination SIP endpoint's <see cref="NetworkBinding" />.</param>
        /// <param name="message">The <see cref="SipMessage" /> to be transmitted.</param>
        /// <exception cref="SipTransportException">Thrown if the remote endpoint rejected the message or timed out.</exception>
        public void Send(NetworkBinding remoteEP, SipMessage message)
        {
            if (disabled)
            {
                return;
            }

            if ((traceMode & SipTraceMode.Send) != 0)
            {
                SipHelper.Trace(string.Format("UDP: sending to {0}", remoteEP), message);
            }

            try
            {
                sock.SendTo(message.ToArray(), remoteEP);
            }
            catch (SocketException e)
            {
                // $todo(jeff.lill):
                //
                // This is just copied from the TCP transport.  It probably
                // doesn't apply here.

                switch ((SocketError)e.ErrorCode)
                {
                case SocketError.ConnectionAborted:
                case SocketError.ConnectionRefused:
                case SocketError.ConnectionReset:
                case SocketError.HostDown:
                case SocketError.HostNotFound:
                case SocketError.HostUnreachable:

                    throw new SipTransportException(SipTransportException.ErrorType.Rejected, e.Message, e);

                case SocketError.TimedOut:

                    throw new SipTransportException(SipTransportException.ErrorType.Timeout, e.Message, e);

                default:

                    throw;
                }
            }
        }
Example #7
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 #8
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 #9
0
        private static int Reflector(string portArg)
        {
            try
            {
                NetReflector reflector;
                int          port;

                if (!int.TryParse(portArg, out port))
                {
                    Program.Error("Invalid network port.");
                    return(1);
                }

                Console.WriteLine();
                Console.WriteLine("Starting network reflector on port [{0}]", port);
                Console.WriteLine("Press [C] to close all connections and [X] to exit the test.");
                Console.WriteLine();

                reflector = new NetReflector(port);

                while (true)
                {
                    var ch = Console.ReadKey(true);

                    switch (ch.KeyChar)
                    {
                    case 'c':
                    case 'C':

                        reflector.CloseConnections();
                        break;

                    case 'x':
                    case 'X':

                        reflector.Stop();
                        return(0);

#if TEST
                    // UDP test code

                    case 'u':
                    case 'U':

                    {
                        var sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                        var buf  = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                        var ep   = (EndPoint) new IPEndPoint(IPAddress.Any, 0);

                        sock.Bind();
                        sock.SendTo(buf, 0, buf.Length, SocketFlags.None, new IPEndPoint(IPAddress.Loopback, port));

                        for (int i = 0; i < buf.Length; i++)
                        {
                            buf[i] = 0;
                        }

                        sock.ReceiveFrom(buf, ref ep);
                        sock.Close();
                    }
                    break;

                    // TCP test code

                    case 't':
                    case 'T':

                    {
                        var sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                        sock.NoDelay = true;
                        sock.Connect(new IPEndPoint(IPAddress.Loopback, port));

                        for (int i = 0; i < 10; i++)
                        {
                            var buf = new byte[i + 1];

                            for (int j = 0; j < i + 1; j++)
                            {
                                buf[j] = (byte)j;
                            }

                            sock.Send(buf);

                            for (int j = 0; j < i + 1; j++)
                            {
                                buf[j] = 0;
                            }

                            var cbRecv = sock.Receive(buf);
                        }

                        sock.Close();
                    }
                    break;
#endif
                    }
                }
            }
            catch (Exception e)
            {
                Program.Error("Error ({0}): {1}", e.GetType().Name, e.Message);
                return(1);
            }
        }