Closed ricardojlrufino closed 7 years ago
Linux version 2.6.21 (root@mailzxh-desktop) (gcc version 3.4.2) #636 Fri Nov 16 10:03:21 CST 2012
system type : Ralink SoC processor : 0 cpu model : MIPS 24K V4.12 BogoMIPS : 239.10 wait instruction : yes microsecond timers : yes tlb_entries : 32 extra interrupt vector : yes hardware watchpoint : yes ASEs implemented : mips16 dsp VCED exceptions : not available VCEI exceptions : not available
Does it have an ID composed by 4 letters, 6 numbers and 5 letters? Something like XXXX123456ABCDE?
My is 3 letters - 6 numbers and 5 letters
It may be compatible, but I can't tell for sure, you will have to check it. Do you know how to use wireshark?
I do not know very well, I tried to use but did not find much relevant information, or could not read ...
What I found was some requests for addresses: Destination: 174.129.229.15 Destination: 174.129.229.102 Destination: 174,129,228,173
I do not know very well, I tried to use but did not find much relevant information, or could not read ...
What I found was some requests for addresses:
Destination: 174.129.229.15 Destination: 174.129.229.102 Destination: 174,129,228,173
others: Brodcast UDP
Address: Broadcast (ff: ff: ff: ff: ff: ff) 255.255.255.255
User Datagram Protocol, Src Port: 6808 (6808), Dst Port: 6809 (6809)
Text: Hello, I'm online!
And nmap
ec2-174-129-228-173.compute-1.amazonaws.com (174.129.228.173) Host is up (0.19s latency). Not shown: 989 closed ports PORT STATE SERVICE 21/tcp filtered ftp 22/tcp open ssh 25/tcp filtered smtp 135/tcp filtered msrpc 139/tcp filtered netbios-ssn 445/tcp filtered microsoft-ds ->554/tcp filtered rtsp 1434/tcp filtered ms-sql-m ->51723/tcp filtered pptp 2008/tcp filtered conf 6667/tcp filtered irc
As I would to test, which server could I use. ? Would I have to do any modification on the camera?
Good news, the things you posted sound familiar to me. The requests to the three servers have as destination port 32100?
I did not find this request ..
But using nmap I saw that the port is open.
I had only TCP scan
I'll do the test later, I'm without the camera at the moment.. Thanks
This is required ?
Add camera address client.addCamAddress({host: "192.168.0.100", port: 10088})
The last one (174.129.228.173) seems to be working! But you have to help me understand how the ID is encoded in the packets. You should run wireshark to look at you client's traffic, to do that you can create a wifi access point on your pc, let your smartphone connect to the ap and dump the traffic. You can use as filter this string: ip.addr == 174.129.228.173 and udp.port == 32100 You should see some packets going from the client to the server that have a len=24 (i.e. 24 bytes of data). Those packets should contain the ID of the camera, if you click on them you should recognize the characters from you id. Do not post the data, just tell me if you can see that.
if you don't see packets of 24 bytes just look into each packet and search for the strings, then let me know if you find it.
Yes a found BEGIN and FINAL of ID, in this package
Nice! Let me guess, the data should be something like this: f1 20 00 14, then the first three characters, then the number converted in hexadecimal (translate it from base 16 to base 10 to confirm), (over how many bytes?), then the last 5 characters and some 00 until the end. Am I correct? Let me know exactly how many bytes compose each part of the packet so that I can adapt my code. Thanks!
you can post a screenshot of the packet censoring some details of the id if you want
DATA(24): f1670014455354000000000000010014XXXXXXXXXX000000
Yeah, the structure is definitely the same, but the fact that it begins with f1 67 and not f1 20 makes me think that it could be a slightly different variant of the protocol. I'll need your help to verify if there are more differences, but we can do it, the general protocol is the same! Let me know what you would like to do with this library so I can give you more info.
I need to develop a web application (in Java) that can access the images of the camera, but I did not find any information about the operation of this protocol.
I was able to access using the "Http API" but only on local network. Using DDNS I could not because the router of the internet carrier I do not have access.
The hope was to understand how this protocol works and get access to the camera in the same way as the App
Hi, how are you.
I've done some tests now with the camera, and your library.
Some of the communication is working, but I'm getting an unidentified packet.
client.on('stun', (e) => console.log("stun:"+JSON.stringify(e))); client.on('lookup', (e) => console.log("lookup:"+JSON.stringify(e)));
client.on('unknownMsg', (e) => console.log("unknownMsg:"+JSON.stringify(e))); client.on('pingpong', (e) => console.log("pingpong:"+JSON.stringify(e))); client.on('close', (e) => console.log("close:"+JSON.stringify(e))); client.on('confirmed', (e) => console.log("confirmed:"+JSON.stringify(e))); client.on('http', (e) => console.log("http:"+JSON.stringify(e)));
Result:
stun:{"address":{"host":"189.81.122.20X","port":35740}} stun:{"address":{"host":"189.81.122.20X","port":35740}} unknownMsg:{"header":"lookup"}
Values from unknownMsg (Uint8Array[8]): 241,33,0,4,253,0,0,0
OK, so you can use the library to help testing the protocol and implement you version in Java. What you want to do is quite simple, it will not take a lot of work. I can also help you with the knowledge I already have on the protocol, maybe I'll put all the description on the wiki. I will write in a few hours. I have to modify the code of the library to support the format of your ID, because now it only supports IDs starting with 4 chars while yours starts with 3 chars.
Hi, I would greatly appreciate it. Can you describe how the protocol flow works would be interesting. And how can I access the images from the camera, whether it opens an HTTP port or rtsp
Maybe i use your library directly from Java ...
I found this interesting project: https://github.com/apigee/trireme
In my application there is already a proposal to run JavaScript scripts within Java, But using: http://openjdk.java.net/projects/nashorn/
Very briefly, the protocol works this way:
1) the camera register itself on the servers communicating its LAN address, and continuously send packets to keep the connection alive (basically an UDP hole punching). 2) the client requests the location of the camera using its ID 3) the server responds with all known camera addresses (LAN + external) or with an OFFLINE message. 4) the client try to contact the camera using the addresses and sending the camera ID 5) two possibilities here: a) if the camera get the message, it responds with its ID and starts sending keepalive messages to keep the connection opened. The client must respond to the keepalive messages otherwise the session get closed by the camera. b) if the client can not contact the camera directly, it tries other ways with the help of the server (I still have to study these functionalities, I think there are 2 options: 1) the camera can try to contact directly the client, if this method fails: 2) the connection is established using relay servers) 6) once the connection is opened, the client can send GET requests very similar to HTTP requests but using a different protocol 7) the responses are divided in various packets (they have a sequence number) and have to be reassembled by the client 8) the client have to ACK the received packages otherwise the session get closed by the camera
I started the wiki, I'll put more info there later. I pushed a new branch 'develop' which should add support for your ID and a few more improvements. I will publish a reference client in the future, for now you can clone this repo, checkout the develop branch and create a test client using something like this:
const lib32100 = require('../lib32100')
const client1 = lib32100.client()
client1.on('stun', (e) => console.log(JSON.stringify(e)))
client1.on('http', (e) => console.log(JSON.stringify(e)))
client1.addServer({host: "174.129.228.173", port: 32100})
client1.setUid('YUOURID')
client1.setCamCredentials({user: 'admin', pass: 'password'})
client1.on('lookup', (e) => {
console.log(JSON.stringify(e))
client1.addCamAddress(e.address)
if(e.address.host.startsWith('192')) { // put the first part of your LAN ip so that you connect directly
console.log('OK')
client1.openDirectCamSession(e.address)
}
})
let cnt = 0
client1.on('confirmed', (e) => {
console.log('CAM confirmed ID!')
cnt++
if(cnt == 4) {
client1.checkCredentials()
client1.getSnapshot()
setTimeout(() => { // closing the connection after 10 seconds
client1.closeSession()
}, 10000)
}
})
if everything worked fine you should see some packages flowing! At the moment I still have to implement the code reassemble the packages so you can not automatically save the image, but should be able to strip 16 bytes of header from the first packet (of the image!) and 8 bytes from the following and reassemble the JPEG image bu hand. Let me know if you try this and it works or not! (or if you need help) I will add more functionalities in the next days
Wow, great explanation.
I did some remote testing (the camera is in my house), and the communication to be ok. Its returning the IP from my local home network. Calbacks fired: 2x stun, 2x lookup.
5.b) if the client can not contact the camera directly , this is my case now ... =]
5.b.2) the connection is established using relay servers Do you think it would be possible to use a private server? Or take the images through it ?
Calbacks fired: 2x stun, 2x lookup.
Just that? The session with the camera is not opened? (you can check that also with wireshark)
Do you think it would be possible to use a private server? Or take the images through it ?
In my opinion YES (and should be done, I don't really trust my credentials and images passing in clear through random chinese servers ;) ) In fact, one of the goals of this project is to implement also the server-side and give instructions on how to do it. This would also allow to add end-to-end encryption for example. But it will require some work, because to do that you have to intercept the packets and change them on the fly, while still keeping compatibility with the protocol.
Just that? The session with the camera is not opened? (you can check that also with wireshark)
I am accessing remotely, I'll test at home later.
You can try to connect remotely if you want, just tweak the code to use the external address instead of the internal one (for example change the '192' with the first part of the remote ip) If there is no firewall blocking the udp traffic it should work
I tested but it did not work. The home network looks like this: Router of my friend> my router> camera
Actually I discovered that I added support for your ID only for the lookup phase but not for the connection phase, it would have never worked. My bad! Now it should be fixed, pull the changes and try again.
Wow .... CAM confirmed ID! Its working , put I think the connection is not open
I can see the 'get' request but no response from cam: My cam follow the same URL, ex.: get_camera_params.cgi?loginuse=admin&loginpas=pass But it is running on port http/81
Netstat in mycam
tcp 0 0 0.0.0.0:81 0.0.0.0: LISTEN 184/encoder tcp 0 0 0.0.0.0:23 0.0.0.0: LISTEN 31/telnetd tcp 0 0 0.0.0.0:8600 0.0.0.0: LISTEN 32/daemon.v5.10 tcp 0 157 192.168.3.110:23 192.168.3.106:45418 ESTABLISHED 31/telnetd udp 236 0 127.0.0.1:8832 0.0.0.0: 184/encoder udp 0 0 127.0.0.1:6666 0.0.0.0: 184/encoder udp 0 0 0.0.0.0:3089 0.0.0.0: 184/encoder udp 0 0 0.0.0.0:3090 0.0.0.0: 184/encoder udp 0 0 0.0.0.0:8600 0.0.0.0: 32/daemon.v5.10 udp 0 0 127.0.0.1:9123 0.0.0.0: 32/daemon.v5.10 udp 0 0 127.0.0.1:9124 0.0.0.0: 184/encoder udp 0 0 0.0.0.0:32108 0.0.0.0: 184/encoder udp 0 0 127.0.0.1:8813 0.0.0.0: 184/encoder udp 0 0 127.0.0.1:8822 0.0.0.0: 184/encoder udp 0 0 127.0.0.1:8831 0.0.0.0: 33/cmd_thread
Package from APP............Data: f1d00059d1000003010a00.... Package from NODEJS....Data: f1d00059d1000000010a00
From NODEJS: I noticed you are not sending the ACKs
Wow .... CAM confirmed ID!
Cool! We are on the right path then =D
But it is running on port http/81
Yeah, they run an interface on port 81 for local access but the protocol implements a similar (it's not exactly the same) interface on the UDP socket.
With wireshark can you see small 4-byte packets flowing? You should also see them if you put a listener on 'pingpong' events.
Can you check with wireshark if the cam responds something to the GETs (it is also passible that it responds with something like 'not implemented'
Package from APP............Data: f1d00059d1000003010a00.... Package from NODEJS....Data: f1d00059d1000000010a00
Oh probably it's a problem with sequence numbers or something like that, I'll look at that ASAP
Pingpong is sent automatically or I have to send manually ? 'pingpong' listener is not fired !
With wireshark can you see small 4-byte packets flowing?
Not
the cam should send 'pings' (f1e00000) after the confirmation of the uid and the library should respond automatically with 'pongs' (f1e10000). But maybe we are sending the request too early and the cam did not yet open the session? You can try delaying the requests
Not working, The camera is not pinging !
let cnt = 0
client1.on('confirmed', (e) => {
console.log('CAM confirmed ID!')
cnt++
if(cnt == 1) {
setTimeout(() => {
console.log("sendGET");
client1.checkCredentials()
// client1.getSnapshot()
}, 5000)
setTimeout(() => { // closing the connection after 10 seconds
client1.closeCamSession()
}, 20000)
}
})
Uh ok, I guess in this case we have to start sending the pings ourselves. I pushed a new version which exposes the sendPing method, try calling it after the confirmed (maybe try also to put it in a setInterval to send it each 0.1 seconds or so)
Wow... this working remote !!!
I'm getting the answers now:
Many:
pingpong:{"subtype":"pong","raw":"f1e10000"} pingpong:{"subtype":"ping","raw":"f1e00000"} pingpong:{"subtype":"pong","raw":"f1e10000"} pingpong:{"subtype":"pong","raw":"f1e10000"} pingpong:{"subtype":"ping","raw":"f1e00000"} pingpong:{"subtype":"pong","raw":"f1e10000"} pingpong:{"subtype":"pong","raw":"f1e10000"} pingpong:{"subtype":"ping","raw":"f1e00000"} pingpong:{"subtype":"pong","raw":"f1e10000"} pingpong:{"subtype":"ping","raw":"f1e00000"} pingpong:{"subtype":"pong","raw":"f1e10000"}
And some:
ack:{"raw":"f1d10006d10000010000"} http:{"seq":0,"raw":"f1d00017d100........"} http:{"seq":0,"raw":"f1d00017d100........"} http:{"seq":0,"raw":"f1d00017d100........"} http:{"seq":0,"raw":"f1d00017d100........"}
The http always comes with seq = 0
Now i try snapshot....
let cnt = 0;
var startPing;
client1.on('confirmed', (e) => {
console.log('CAM confirmed ID!')
cnt++
if(cnt == 1) {
startPing = setInterval(() => {
client1.sendPing()
}, 200);
setTimeout(() => {
clearInterval(startPing);
client1.checkCredentials()
}, 2000);
setTimeout(() => {
console.log("getSnapshot");
client1.getSnapshot()
}, 5000)
setTimeout(() => { // closing the connection after 10 seconds
client1.closeCamSession()
}, 20000)
}
})
I'm getting the picture, incredible ...
But a receiving multiple times:
http:{"seq":0,"raw":"f1d00017d10000000 http:{"seq":1,"raw":"f1d00404d100000..... BIGGGCONTENT.......
I think I have to send an ack to the camera, right?
I have copied some returns and the data is the same (for: http:{"seq":1,"raw" ...) **md5sum lib32100/resp/***
4d2bdf2bfc43f511a4f6647434bb8955 lib32100/resp/1.txt 4d2bdf2bfc43f511a4f6647434bb8955 lib32100/resp/2.txt 4d2bdf2bfc43f511a4f6647434bb8955 lib32100/resp/3.txt 4d2bdf2bfc43f511a4f6647434bb8955 lib32100/resp/4.txt
Converted to binary: screen.bin: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 320x240, frames 3
Wow... this working remote !!!
Great! I will integrate the pings directly into the library then.
I think I have to send an ack to the camera, right?
Yeah, I have to do it in the library, I think next week.
screen.bin: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 320x240, frames 3
Seems working, right?
Enough progress thanks to your help.
I just do not understand how the final image is made ... I took the captures of Wireshark in the APP, and I observed the sequence of each.
Are in sequence: f1d001a8d1000001 f1d001a8d1000002 f1d001a8d1000003 f1d001a8d1000004 f1d001a8d1000005 f1d001a8d1000006
But when I join the bytes of the image (position 16)
dd skip=16 if=1.bin of=1.jpg bs=1 cat *.jpg > out.jpg
This is the result.
Original
You have to skip 16 bytes in the first packet and just 8 on the following! That's because the first packet contains an additional 8-bytes header that tells how many packets compose the file (that is how many packets you have to join together to get the complete file). The library should do this work but it's not implemented yet.
additional 8-bytes header
Have you been able to identify offset that represent the quantity? I already hit my head and I did not find a match ...
Have you been able to identify the format of the ack? I looked at the package (F1 D1) of various sizes: 10, 22, 28, 38 from app > cam
Have you been able to identify offset that represent the quantity?
0000 f1 d0 04 04 d1 00 00 00 01 0a 15 60 90 53 00 01
0x15 == 21 in decimal
Have you been able to identify the format of the ack?
0000 f1 d1 00 06 d1 00 00 01 00 00
00 06 -> 6-bytes payload d1 00 -> ACK 00 01 -> ACKing 1 packet 00 00 -> sequence number of packet
You can ack multiple packets by increasing 00 01 to the number of packets and adding all the sequence numbers to ACK
example:
00 08 -> 8 byte payload d1 00 -> ACK 00 02 -> ACKing 2 packet 00 00 00 01 -> sequence number of packets
See my capture:
The image is composed 12 pcks (I was able to mount the image manually following your tips) Then the ACK is sent, and some packets of the image are repeated (from pck 8 - 12).
Index 11 = 0x15 = 21 in decimal, does not seem to be correct in my case
what about index 14-13 as the size? 90 53 -> 53 90 -> 21392 bytes
Yes: 4c:2c - > 2c4c = 11340
-rwxr-xr-x 1 ricardo root 11340 Abr 9 08:47 out.jpg
Could I consider "f1: d0: 00: 58" as the end of the image?
86 img f1:d0:04:04:d1:00:00:01:01:0a:15:60:4c:2c:00:01:ff:d8:ff:e0:00:10:4a:46:
87 f1:d0:04:04:d1:00:00:02:0d:c3:b7:15:85:68:c4:1c:7e:15:ba:74:a9:35:a5:1a:
88 f1:d0:04:04:d1:00:00:03:14:80:17:84:9c:fb:f5:ae:88:0e:5b:9a:f2:e5:62:23:
89 f1:d0:04:04:d1:00:00:04:a6:32:b0:40:10:80:45:3b:a0:c9:3d:05:56:73:46:2a:
90 f1:d0:04:04:d1:00:00:05:b1:15:9e:9a:3e:9e:b2:79:9e:46:e3:e8:c7:23:f2:ab:
91 f1:d0:04:04:d1:00:00:06:24:5f:dd:6c:8f:c6:b3:53:cd:7a:13:8c:c6:0d:6a:ca:
92 f1:d0:04:04:d1:00:00:07:62:f8:2c:29:e3:91:5b:7a:eb:ec:d3:df:9c:64:81:5c:
93 f1:d0:04:04:d1:00:00:08:f3:59:49:e1:3b:30:e0:97:62:3d:2b:5a:38:ad:ac:d0:
94 f1:d0:04:04:d1:00:00:09:1b:19:04:fb:1c:d3:94:30:f9:ba:11:ea:28:a2:bb:6f:
95 f1:d0:04:04:d1:00:00:0a:6a:f5:b4:48:8a:24:9b:f2:a6:5c:5d:4b:29:f2:e1:f9:
96 f1:d0:04:04:d1:00:00:0b:ad:f7:8d:44:b2:15:6c:8e:2b:7b:4f:d7:1a:10:12:43:
97 end f1:d0:00:58:d1:00:00:0c:54:25:b7:52:ae:07:bd:60:cd:9a:d4:0a:90:36:3e:94:
98 f1:d1:00:12:d1:00:00:07:00:01:00:02:00:03:00:04:00:05:00:06:00:07
99 rep f1:d0:04:04:d1:00:00:08:f3:59:49:e1:3b:30:e0:97:62:3d:2b:5a:38:ad
100 f1:d0:04:04:d1:00:00:09:1b:19:04:fb:1c:d3:94:30:f9:ba:11:ea:28:a2
101 f1:d0:04:04:d1:00:00:0a:6a:f5:b4:48:8a:24:9b:f2:a6:5c:5d:4b:29:f2
102 f1:d0:04:04:d1:00:00:0b:ad:f7:8d:44:b2:15:6c:8e:2b:7b:4f:d7:1a:10
103 end f1:d0:00:58:d1:00:00:0c:54:25:b7:52:ae:07:bd:60:cd:9a:d4:0a:90:36
104 f1:d1:00:18:d1:00:00:0a:00:08:00:09:00:0a:00:0b:00:0c:00:08:00:09:00:0a:
105 f1:e0:00:00
106 f1:e1:00:00
107 f1:e0:00:00
108 f1:e1:00:00
109 f1:e0:00:00
Another thing I just noticed, the APP made two requests in the same package ... MGET /check_user.cgi?loginuse=admin&loginpas=XXXX&user=admin&pwd=XXXXX& KGET /snapshot.cgi?loginuse=admin&loginpas=XXXX&user=admin&pwd=XXXX&
Could I consider "f1: d0: 00: 58" as the end of the image?
No, 00 58 should be just the size of the last piece of image (88 bytes)
Another thing I just noticed, the APP made two requests in the same package
Yes, you can join multiple requests together, but the camera will respond with multiple packets This functionality is already implemented (sendMultipleGet)
I bought a Chinese camera and it works with this application. https://play.google.com/store/apps/details?id=object.aisaidezx.client
I got access via telnet, and found this configuration Upnp
Platform=RT5350
By looking at the internal executable strings, I found these addresses www.ipupnp.hk open.kaicong.info www.365home.org
Have any tips on how I can use a LIB to communicate with this camera ?