Beispiel #1
0
        /// <summary>
        /// Get all the records since the last call
        /// This method removes the returned records from its internal buffer
        /// </summary>
        /// <returns>List of captured records</returns>
        public static List <Record> GetRecords()
        {
            try
            {
                lock (records)
                {
                    // get the device ID, and store it if it's not in the config file already
                    deviceId = ConfigClient.Read(ConfigClient.DeviceId, true);
                    if (deviceId == null)
                    {
                        deviceId = devices[0].MacAddress.ToString();
                        ConfigClient.Write(ConfigClient.DeviceId, deviceId);
                    }

                    var recordList = new List <Record>(records);
                    records.Clear();
                    return(recordList);
                }
            }
            catch (Exception ex)
            {
                TraceLog.TraceException("GetRecords failed", ex);
                return(null);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Start a network capture
        /// </summary>
        public static void Start()
        {
            lock (startingLock)
            {
                try
                {
                    // Retrieve the device list
                    devices = CaptureDeviceList.Instance;

                    // If no devices were found print an error
                    if (devices.Count < 1)
                    {
                        var error = "No devices were found on this machine";
                        TraceLog.TraceFatal(error);
                        throw new Exception(error);
                    }

                    // if capture is started on all devices, nothing to do
                    var started = true;
                    foreach (var dev in devices)
                    {
                        if (!dev.Started || !string.IsNullOrEmpty(dev.LastError))
                        {
                            started = false;
                            break;
                        }
                    }
                    if (started)
                    {
                        return;
                    }

                    // Print SharpPcap version
                    string ver = SharpPcap.Version.VersionString;
                    TraceLog.TraceInfo(string.Format("Starting collector with version {0}", ver));

                    foreach (var device in devices)
                    {
                        // reset device if already started
                        if (device.Started)
                        {
                            TraceLog.TraceInfo(string.Format("Stopping {0} {1}", device.Name, device.Description));
                            device.OnPacketArrival -= new PacketArrivalEventHandler(device_OnPacketArrival);
                            device.StopCapture();
                            device.Close();
                        }

                        // Register our handler function to the 'packet arrival' event
                        device.OnPacketArrival +=
                            new PacketArrivalEventHandler(device_OnPacketArrival);

                        // Open the device for capturing
                        int readTimeoutMilliseconds = 1000;
                        device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);

                        TraceLog.TraceInfo(string.Format("Listening on {0} {1}",
                                                         device.Name, device.Description));

                        // DNS only
                        string filter = "udp dst port 53";
                        device.Filter = filter;

                        // Start the capturing process
                        device.StartCapture();
                    }

                    // get the device ID, and store it if it's not in the config file already
                    deviceId = ConfigClient.Read(ConfigClient.DeviceId);
                    if (deviceId == null)
                    {
                        deviceId = devices[0].MacAddress.ToString();
                        ConfigClient.Write(ConfigClient.DeviceId, deviceId);
                    }
                }
                catch (Exception ex)
                {
                    TraceLog.TraceException("FATAL: Start caught exception", ex);
                    throw ex;
                }
            }
        }
Beispiel #3
0
        private static void Send()
        {
            try
            {
                // snap the record list
                var recordList = CollectorClient.GetRecords();

                // if no records, may need to recover capture service
                if (recordList.Count == 0)
                {
                    if (recovering)
                    {
                        // this is the second timeout period that we didn't see records.
                        // attempt to restart the collector
                        CollectorClient.Start();
                        recovering = false;
                    }
                    else
                    {
                        // this will trigger recovery if the next run through also has zero records
                        recovering = true;
                    }

                    // nothing to do this time (no records to process)
                    return;
                }
                else
                {
                    // reset recovery mode
                    recovering = false;
                }

                // compact the record list
                var uniqueHosts = recordList.Select(r => r.HostMacAddress).Distinct();
                foreach (var host in uniqueHosts)
                {
                    var uniqueDests = recordList.Where(r => r.HostMacAddress == host).Select(r => r.WebsiteName).Distinct();
                    foreach (var dest in uniqueDests)
                    {
                        var records = recordList.Where(r => r.HostMacAddress == host && r.WebsiteName == dest).OrderBy(r => r.Timestamp);

                        // only keep the first and last record so that the duration calculated on the server will be > 0
                        var firstRecord = records.FirstOrDefault();
                        var lastRecord  = records.LastOrDefault();

                        // if the last record is a second or more later, add the duration to the first record
                        TimeSpan duration;
                        if (lastRecord != null && lastRecord != firstRecord &&
                            (duration = Convert.ToDateTime(lastRecord.Timestamp) - Convert.ToDateTime(firstRecord.Timestamp))
                            >= TimeSpan.FromSeconds(1.0))
                        {
                            firstRecord.Duration = (int)duration.TotalSeconds;
                        }

                        lock (sendQueue)
                        {
                            var existingRecord = sendQueue.FirstOrDefault(r => r.HostMacAddress == host && r.WebsiteName == dest);
                            if (existingRecord == null ||
                                Convert.ToDateTime(firstRecord.Timestamp) - (Convert.ToDateTime(existingRecord.Timestamp) + TimeSpan.FromSeconds(existingRecord.Duration)) >= TimeSpan.FromSeconds(300.0)) // more than 5 minutes between records
                            {
                                // add the record to the send queue
                                sendQueue.Add(firstRecord);
                            }
                            else
                            {
                                // augment existing record with new duration
                                duration = Convert.ToDateTime(firstRecord.Timestamp) - Convert.ToDateTime(existingRecord.Timestamp) + TimeSpan.FromSeconds(firstRecord.Duration);
                                existingRecord.Duration = (int)duration.TotalSeconds;
                            }
                        }
                    }
                }

                if (sendQueue.Count > 0)
                {
                    // snap the send queue
                    var recordBuffer = new List <Record>();
                    lock (sendQueue)
                    {
                        // clear this buffer if collection is suspended
                        if (collectionStatus == ControlMessage.SuspendCollection)
                        {
                            sendQueue.Clear();
                            TraceLog.TraceInfo("Probing for new collection status");
                        }
                        else
                        {
                            recordBuffer.AddRange(sendQueue);
                            TraceLog.TraceInfo(String.Format("Sending records: {0}", JsonConvert.SerializeObject(sendQueue)));
                        }
                    }

                    var sendList = new RecordList()
                    {
                        DeviceId        = deviceId,
                        DeviceName      = deviceName,
                        SoftwareVersion = UpdateClient.CurrentVersion.ToString(),
                        Records         = recordBuffer
                    };

                    // send the queue to the web service
                    WebServiceHelper.PostRecords(
                        credentials,
                        sendList,
                        new WebServiceHelper.PostRecordsDelegate((response) =>
                    {
                        // a callback means the service processed the records successfully; we can free them now.
                        // note a slight race condition - if the callback takes longer than the sleep interval, we
                        // could lose a buffer.  since the sleep interval is 60sec, this isn't an important issue
                        // to address.
                        lock (sendQueue)
                        {
                            sendQueue.Clear();
                        }
                        var msg = (ControlMessage)response.controlMessage;
                        if (collectionStatus == msg)
                        {
                            return;
                        }

                        // process the control message
                        lock (configLock)
                        {
                            switch (msg)
                            {
                            case ControlMessage.Normal:
                                TraceLog.TraceInfo("Changing collection status to Normal");
                                collectionStatus = msg;
                                ConfigClient.Write(ConfigClient.Disabled, Convert.ToString(false));
                                break;

                            case ControlMessage.SuspendCollection:
                                TraceLog.TraceInfo("Changing collection status to Suspended");
                                collectionStatus = msg;
                                ConfigClient.Write(ConfigClient.Disabled, Convert.ToString(true));
                                break;

                            case ControlMessage.DisableDevice:
                                TraceLog.TraceInfo("Disabling the device by wiping the config");
                                collectionStatus = msg;
                                deviceId         = null;
                                deviceName       = null;
                                // wipe the config
                                ConfigClient.Clear();
                                break;

                            default:
                                // new message we don't understand yet
                                TraceLog.TraceInfo(string.Format("Received unknown control message {0}", msg));
                                break;
                            }
                        }
                    }),
                        new WebServiceHelper.NetOpDelegate((inProgress, status) =>
                    {
                        if (status == OperationStatus.Retry)
                        {
                            // no need to do anything: next iteration will send original credentials
                        }
                        // no failure state to clean up
                    }));
                }
            }
            catch (Exception ex)
            {
                TraceLog.TraceException("Upload processing failed", ex);
            }
        }