1. 程式人生 > >海康 裝置 發現(SADPTool原理)

海康 裝置 發現(SADPTool原理)

SADPTool原理:

向239.255.255.250:37020傳送基於ONVIF協議的 udp 組播,裝置會監聽 239.255.255.250:37020,收到指令,會向 傳送組播的機器,返回裝置資訊,也會向239.255.255.250:37020 傳送 裝置資訊的 組播。

傳送 報文(Uuid是Guid,每次都生成一個新的,用同一個,我沒有試過,可不可以)

<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>12D17626-0DE1-48DB-97E3-40B106467932</Uuid><Types>inquiry</Types></Probe>

返回報文
<?xml version="1.0" encoding="UTF-8" ?>
<ProbeMatch>
<Uuid>12D17626-0DE1-48DB-97E3-40B106467932</Uuid>
<Types>inquiry</Types>
<DeviceType>139991</DeviceType>
<DeviceDescription>CS-C6TC-32WFR</DeviceDescription>
<DeviceSN>CS-C6TC-32WFR0120170327CCCH738231995</DeviceSN>
<CommandPort>8000</CommandPort>
<HttpPort>80</HttpPort>
<MAC>54-c4-15-9a-38-72</MAC>
<IPv4Address>172.20.20.100</IPv4Address>
<IPv4SubnetMask>255.255.255.0</IPv4SubnetMask>
<IPv4Gateway>172.20.20.254</IPv4Gateway>
<DHCP>false</DHCP>
<AnalogChannelNum>0</AnalogChannelNum>
<DigitalChannelNum>1</DigitalChannelNum>
<SoftwareVersion>V5.2.3build 180804</SoftwareVersion>
<DSPVersion>V1.0 build 180731</DSPVersion>
<BootTime>2018-10-18 21:30:10</BootTime>
<OEMInfo>N/A</OEMInfo>
<Activated>true</Activated>
<PasswordResetAbility>false</PasswordResetAbility>
</ProbeMatch>

通過 wireshark 抓包發現,傳送 ONVIF協議後,還會 廣播 一個 包

但是不知道,是做何作用,我用SharpPcap 模擬傳送了一個EarthNet II 的包,這個包 是固定不變的。

EarthNet II 的包,C# 原生 Socket 貌似不支援,raw_Socket 寫起來太繁瑣了,SharpPcap 另一個用處是可以基於網絡卡抓包。

搜尋裝置程式碼:


        public void SearchDecives()
        {
            //EtherNetII 協議
            byte[] SearchIpCameraByte = new byte[]{
                0xff ,0xff ,0xff ,0xff ,0xff ,0xff ,//目的地Mac
                0x00 ,0x15 ,0x5d ,0xe6 ,0xaa ,0x0b ,//源地址Mac
                0x80 ,0x33 ,//協議型別(0x8033螢石自定義型別)
                0x21 ,0x02,//傳送資料   
                0x01 ,0x42 ,0x00 ,0x00 ,0x24 ,0x03 ,0x06 ,0x04 ,0x03 ,0x00 ,0x13 ,0x82 ,0x00 ,0x15 ,0x5d ,0xe6,  
                0xaa ,0x0b ,0xa9 ,0xfe ,0x50 ,0x50 ,0xff ,0xff ,0xff ,0xff ,0xff ,0xff ,0x00 ,0x00 ,0x00 ,0x00,  
                0x00 ,0x00 ,0x00 ,0x00 ,0xfe ,0x80 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x64 ,0x7e ,0x5d ,0xb0,  
                0x9e ,0x93 ,0xcd ,0x07 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,  
            };
            var devices = CaptureDeviceList.Instance;
            Console.Write("---------------------------");
            // differentiate based upon types
            foreach (ICaptureDevice dev in devices)
            {
                if (dev is AirPcapDevice)
                {
                    // process as an AirPcapDevice
                }
                else if (dev is WinPcapDevice)
                {
                    dev.Open();
                    //dev.Capture();
                    //dev.StartCapture();
                    dev.SendPacket(SearchIpCameraByte);
                    Thread.Sleep(1000);
                    //dev.StopCapture();
                    //dev.Close();
                    // process as an WinPcapDevice
                }
                else if (dev is LibPcapLiveDevice)
                {
                    // process as an LibPcapLiveDevice
                }
            }
            return;
        }

        /// <summary>
        /// 查詢裝置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            SendInQuiry();
            SearchDecives();
            SendMSearch();
        }

        /// <summary>
        /// 搜尋upnp 裝置
        /// 向ssdp服務地址239.255.255.250:1900組播發送資料
        /// </summary>
        public void SendMSearch()
        {
            //向ssdp服務地址239.255.255.250:1900組播發送資料
            IPEndPoint ipend = new IPEndPoint(IPAddress.Any, 0);
            UdpClient client = new UdpClient(ipend);
            client.EnableBroadcast = false;
            client.JoinMulticastGroup(IPAddress.Parse("239.255.255.250"));
            IPEndPoint multicast = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900);
            byte[] buf = Encoding.Default.GetBytes("M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:upnp:rootdevice\r\nMX:3\r\n\r\n");
            client.Send(buf, buf.Length, multicast);
                          
            //非同步接收資料
            //client.BeginReceive(new AsyncCallback(ReceiveBack), client);

            //設定網路超時時間,一段時間未接收到資料時自動退出
            //client.Client.ReceiveTimeout = 150;

            //單播接收資料
            //while (true)
            //{
            //    byte[] value = client.Receive(ref ipend);
            //    string msg = Encoding.Default.GetString(value);
            //    //OLog.Info(msg);
            //    Console.WriteLine(msg + "-" + ipend.Address.ToString());
            //}
        }

        /// <summary>
        /// 傳送裝置探究
        /// 向ssdp服務地址239.255.255.250:37020組播發送資料
        /// </summary>
        public void SendInQuiry()
        {
            var uuid = Guid.NewGuid().ToString().ToUpper();
            //<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>A207AD1A-962B-480B-A32C-4B0D98CBA0D4</Uuid><Types>inquiry</Types></Probe>
            var InQuiry = new byte[]{
                    0x3c ,0x3f ,0x78 ,0x6d ,0x6c ,0x20,   
                    0x76 ,0x65 ,0x72 ,0x73 ,0x69 ,0x6f ,0x6e ,0x3d ,0x22 ,0x31 ,0x2e ,0x30 ,0x22 ,0x20 ,0x65 ,0x6e,   
                    0x63 ,0x6f ,0x64 ,0x69 ,0x6e ,0x67 ,0x3d ,0x22 ,0x75 ,0x74 ,0x66 ,0x2d ,0x38 ,0x22 ,0x3f ,0x3e,   
                    0x3c ,0x50 ,0x72 ,0x6f ,0x62 ,0x65 ,0x3e ,0x3c ,0x55 ,0x75 ,0x69 ,0x64 ,0x3e
                }.
                Concat(System.Text.Encoding.UTF8.GetBytes(uuid)).//uuid
                Concat(new byte[]{
                    0x3c ,0x2f ,0x55 ,0x75 ,0x69 ,0x64 ,0x3e ,0x3c ,0x54 ,0x79 ,0x70 ,0x65 ,0x73 ,0x3e ,0x69,   
                    0x6e ,0x71 ,0x75 ,0x69 ,0x72 ,0x79 ,0x3c ,0x2f ,0x54 ,0x79 ,0x70 ,0x65 ,0x73 ,0x3e ,0x3c ,0x2f,   
                    0x50 ,0x72 ,0x6f ,0x62 ,0x65 ,0x3e
                }).ToArray();
            IPEndPoint ipend = new IPEndPoint(IPAddress.Any, 0);
            UdpClient client = new UdpClient(ipend);
            client.EnableBroadcast = false;
            client.JoinMulticastGroup(IPAddress.Parse("239.255.255.250"));
            IPEndPoint multicast = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 37020);
            client.Send(InQuiry, InQuiry.Length, multicast);
        }

監聽組播程式碼:

private void button2_Click(object sender, EventArgs e)
        {
            //接收組播資料
            Thread t = new Thread(new ThreadStart(RecvThread));
            t.IsBackground = true;
            t.Start();
            //Socket recv_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //recv_socket.Bind(new IPEndPoint(IPAddress.Any, 1900));
            //recv_socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveMessage, recv_socket);
        }

        /// <summary>
        /// 獲取 ssdp 組播
        /// ssdp地址固定:239.255.255.250:1900
        /// 海康裝置組播到 37020 埠
        /// </summary>
        void RecvThread()
        {
            //繫結組播埠   
            UdpClient client = new UdpClient(37020);
            client.EnableBroadcast = false;
            client.JoinMulticastGroup(IPAddress.Parse("239.255.255.250"));
            IPEndPoint mult = null;
            while (true)
            {
                byte[] buf = client.Receive(ref mult);
                string msg = Encoding.Default.GetString(buf);
                Console.WriteLine(msg);
                MessageBox.Show(msg);
                //Console.WriteLine(mult.Address.ToString());
            }
        }

還可以用 ARP 對映原理 獲取 區域網 所有機器的MAC地址,根據MAC 前6位判斷是 哪家生產的裝置,同一企業生產的 網路裝置mac地址 前6位一般是固定的。

海康裝置Mac地址 都是54-c4-15 開頭的

我這裡用的是 cmd arp -a,取arp對映的,也可以 sharppcap抓包,或者Windows api 傳送arp 協議 包,取返回值

private static string GetARPResult()
        {
            Process p = null;
            string output = string.Empty;
            try
            {
                p = Process.Start(new ProcessStartInfo("arp", "-a")
                {
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    RedirectStandardOutput = true
                });
                output = p.StandardOutput.ReadToEnd();
            }
            catch (Exception ex)
            {
                throw new Exception("IPInfo: Error Retrieving 'arp -a' Results", ex);
            }
            finally
            {
                if (p != null)
                {
                    p.Close();
                }
            }
            return output;
        }