Author |
Topic |
|
mojo66
Germany
32 Posts |
Posted - 06/17/2021 : 01:41:11
|
I'm writing a PHP script to run on my own http server, as a replacement to log2.asp. Everything works fine, but the device, a 500+, displays "Link server failed" or "WiFi data send failed". Does it expect a particular response from the http server?
Here is an example from access.log, first one is from using "Test Connection", the second is a regular periodic send.
192.168.1.240 - - [17/Jun/2021:11:28:48 +0200] "GET /geiger.php?AID=1&GID=1&CPM=22&ACPM=23.66&uSV=0.14 HTTP/1.1" 200 117
192.168.1.240 - - [17/Jun/2021:11:28:58 +0200] "AT+CIPCLOSE" 400 226
192.168.1.240 - - [17/Jun/2021:11:29:52 +0200] "GET /geiger.php?AID=1&GID=1&CPM=30&ACPM=23.66&uSV=0.19 HTTP/1.1" 200 117
192.168.1.240 - - [17/Jun/2021:11:30:12 +0200] "-" 408 -
|
Edited by - mojo66 on 06/17/2021 01:57:31
|
|
Reply #1
mojo66
Germany
32 Posts |
Posted - 06/21/2021 : 21:07:27
|
So what should the http-server reply to make the 500+ happy? |
Edited by - mojo66 on 06/24/2021 23:07:53 |
|
|
Reply #2
EmfDev
2238 Posts |
Posted - 06/28/2021 : 09:48:59
|
Hi mojo66, I think it is OK.ERR0 |
|
|
Reply #3
mojo66
Germany
32 Posts |
Posted - 07/19/2021 : 06:38:02
|
quote: Originally posted by EmfDev
Hi mojo66, I think it is OK.ERR0
I can confirm that replying with "OK.ERR0" does indeed make my GMC-500+ happy. Thanks! |
|
|
Reply #4
jlam
5 Posts |
Posted - 08/15/2021 : 14:14:21
|
Hey! Mine is really not happy with that response, could you please share your php script?
Thanks :) |
|
|
Reply #5
ullix
Germany
1164 Posts |
|
Reply #6
jlam
5 Posts |
Posted - 08/16/2021 : 05:58:17
|
Thanks for the reply!
I've updated my server script with the hidden elements, but now getting 192.168.1.249 - - [16/Aug/2021 13:56:24] "GET /log?AID=1&GID=1&CPM=23&ACPM=14.70&uSV=0.15 HTTP/1.1" 200 - 192.168.1.249 - - [16/Aug/2021 13:56:25] code 400, message Bad request syntax ('AT+GSLP=0') 192.168.1.249 - - [16/Aug/2021 13:56:25] "AT+GSLP=0" 400 -
Have you had these responses as well?
Cheers |
|
|
Reply #7
EmfDev
2238 Posts |
Posted - 08/16/2021 : 09:58:45
|
hi jlam, maybe try log2.asp |
|
|
Reply #8
ullix
Germany
1164 Posts |
Posted - 08/17/2021 : 00:23:58
|
@jlam You get a code 400 when the server receives an invalid request from a client, i.e. you are sending the wrong thing! Make sure to really use log2.asp followed by the data string !
See the valid data examples in my post above.
What is this "AT+GSLP=0" intended for? I know it as a deep sleep command for an ESP microchip. Doesn't look relevant for dealing with the gmcmap server? I hope the gmcmap server does not respond to it?
|
Edited by - ullix on 08/17/2021 00:24:41 |
|
|
Reply #9
jlam
5 Posts |
Posted - 08/26/2021 : 03:23:08
|
Hey,
Thanks for your reply. This is just a listener I have running on one of my linux boxes. Those are the replies I get once the GMC submits a log result to it. I'm not sure using log2.asp is relevant, for example mojo66 uses geiger.php on his box. |
|
|
Reply #10
EmfDev
2238 Posts |
Posted - 08/26/2021 : 09:26:27
|
quote: Originally posted by jlam
Thanks for the reply!
Ive updated my server script with the hidden elements, but now getting 192.168.1.249 - - [16/Aug/2021 13:56:24] "GET /log?AID=1&GID=1&CPM=23&ACPM=14.70&uSV=0.15 HTTP/1.1" 200 - 192.168.1.249 - - [16/Aug/2021 13:56:25] code 400, message Bad request syntax (AT+GSLP=0) 192.168.1.249 - - [16/Aug/2021 13:56:25] "AT+GSLP=0" 400 -
Have you had these responses as well?
Cheers
The get should use log2.asp instead of just log. It is in the example "GET /log?AID=1&GID=1&CPM=23&ACPM=14.70&uSV=0.15 HTTP/1.1" ==> "GET /log2.asp?AID=1&GID=1&CPM=23&ACPM=14.70&uSV=0.15 HTTP/1.1" |
|
|
Reply #11
mojo66
Germany
32 Posts |
Posted - 08/30/2021 : 17:11:34
|
log2.asp is irrelevant. I don't know why ullix and EmfDev insist on it. You can have any URL you like, especially when using the app that allows use of AT commands.
The problem is that you can't have any Port you like because port 80 is hardcoded. That means you have to give your webserver elevated privileges (at least on a professional OS. Yes that excludes Windows). The firmware is closed source, so we are at the mercies of the devs etc p.p.
I gave up on it, I don't have the time nor nerves to discuss why the firmware of an item that I own should be open source. It's simple: I won't recommend any products by GQ.
For completeness, I had this PHP script running for a while on port 80:
<html>
<head>
<title>PHP Test</title>
</head>
<body>
<?php
$date = date("U");
$cpm = htmlspecialchars($_GET["CPM"]);
$usv = htmlspecialchars($_GET["uSV"]);
$file = 'geiger.text';
$output = $date . ',' . $cpm . "," . $usv . PHP_EOL ;
file_put_contents($file, $output, FILE_APPEND | LOCK_EX);
?>
</body>
</html>
It did work but that stupid error message would come up on the GMC on every transmit, and it had to run on port 80. Note that I don't know anything about PHP I just looked up the pieces I needed on some PHP reference site. Perhaps someone can come up with a patch that would reply with the "OK.ERR0" required to make the GMC happy.
But the PHP code was for testing anyway, I don't want to run Apache just to run 10 lines of PHP. Hence I've hacked together a piece of C code that basically does the same feel free to do with it what you like:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#import <arpa/inet.h>
#include <CoreFoundation/CoreFoundation.h>
void usage(void);
void callback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info);
int main(int argc, const char * argv[]) {
int port, ch;
char ofd; // TODO: set proper default path
port = 60999; // TODO: figure out a good default port
while ((ch = getopt(argc, argv, "p:o:")) != -1) {
switch (ch) {
case 'p':
port = atoi(optarg);
break;
case 'o':
ofd = open(optarg, O_APPEND);
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
// create socket address
struct sockaddr_in addr;
socklen_t addrLen = sizeof(addr);
memset(&addr, 0, addrLen);
addr.sin_len = addrLen;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
// create socket
CFDataRef sockData = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr, addrLen);
CFSocketSignature sockSig = { PF_INET, SOCK_STREAM, IPPROTO_TCP, sockData };
CFSocketRef sock = CFSocketCreateWithSocketSignature(kCFAllocatorDefault, &sockSig, kCFSocketAcceptCallBack, callback , NULL);
CFRelease(sockData);
// add socket to current runloop
CFRunLoopSourceRef sockRRL = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), sockRRL, kCFRunLoopDefaultMode);
CFRelease(sockRRL);
printf("Listening to port %i.\n", port);
// run forever
CFRunLoopRun();
return 0;
}
void usage(void) {
}
void callback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
if (type != kCFSocketAcceptCallBack) {
printf("WARNING: Received unexpected callback type %lu.\n", type);
return;
}
// for kCFSocketAcceptCallBack:
// address = sockaddr_in of the remote address to which s is connected
// data = a pointer to a CFSocketNativeHandle
// get host address (just for info)
struct sockaddr_in *host = (struct sockaddr_in *) CFDataGetBytePtr(address);
char *hostAddr = inet_ntoa(host->sin_addr);
printf("Host %s connected.\n", hostAddr);
// create read/write streams from socket
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFSocketNativeHandle *h = (CFSocketNativeHandle*) data;
CFStreamCreatePairWithSocket(kCFAllocatorDefault, *h, &readStream, &writeStream);
// read into buffer
int bufSize = 1024;
UInt8 buf[bufSize];
memset(buf, 0, bufSize);
CFReadStreamOpen(readStream);
CFIndex numBytesRead = CFReadStreamRead(readStream, buf, bufSize);
printf("Read %li bytes: %s\n", numBytesRead, buf);
CFReadStreamClose(readStream);
CFRelease(readStream);
// write response
UInt8 response[] = "OK.ERR0";
CFIndex respLen = 8;
CFWriteStreamOpen(writeStream);
CFIndex bytesWritten = CFWriteStreamWrite(writeStream, response, respLen);
printf("Wrote %li bytes.\n", bytesWritten);
CFWriteStreamClose(writeStream);
CFRelease(writeStream);
// write data to disk
}
I stopped work on it after I found out that the port is hardcoded. But the code does receive the data and replies properly. |
Edited by - mojo66 on 08/30/2021 17:16:58 |
|
|
Reply #12
ullix
Germany
1164 Posts |
Posted - 08/31/2021 : 01:28:15
|
quote: log2.asp is irrelevant.
I am afraid this is absolutely NOT the case!
Do a simple test: Use a correct user ID and a correct counter ID, and enter a valid url in any browser. For privacy I use UUU for user and CCC for counter. Of course, I did the calls with my real IDs.
Using the correct "log2.asp":h**p://www.gmcmap.com/log2.asp?AID=UUU&GID=CCC&CPM=15&ACPM=13.2&uSV=0.075
results in response: '\r\n<!-- sendmail.asp-->\r\n\r\nOK.ERR0'
while using the wrong "log.asp"h**p://www.gmcmap.com/log.asp?AID=UUU&GID=CCC&CPM=15&ACPM=13.2&uSV=0.075
results in response: 'Error 10.ERR3'
Obviously clearly different responses!
The extension ".asp" indicates that the website is built with "Active Server Pages". Which, to state it simply, is Microsofts's version of php.
The "log.asp" and "log2.asp" are two different files on the server coding the actions and output of the server, and you get the same result ONLY if the two files are identical (symlink, hardlink) or have the exact same content. But see above, they are different files and have different content!
You didn't say what the filename of your php code is; I suppose this is "index.php". In this case you don't have to specify it in the url, because it is called automatically if not given. But if your file were "index2.php", you'd have to explicitly name it!
Adding the "OK" response to your script is very easy. Just add these two lines to the end of your php section:
http_response_code(200);
echo("OK.ERR0"); and the webpage looks like you want it. However, this would be wrong! To see why, view the page source. It is:
<html>
<head>
<title>PHP Test</title>
</head>
<body>
OK.ERR0 </body>
</html> You are creating a full web page, but this is not what "log2.asp" sends. Instead, your complete file content should look like this:<?php
$date = date("U");
$cpm = htmlspecialchars($_GET["CPM"]);
$usv = htmlspecialchars($_GET["uSV"]);
$file = 'geiger.text';
$output = $date . ',' . $cpm . "," . $usv . PHP_EOL ;
file_put_contents($file, $output, FILE_APPEND | LOCK_EX);
http_response_code(200);
echo("\r\n<!-- sendmail.asp-->\r\n\r\nOK.ERR0");
?> Note that there is no separate html code! Since I put this into file "index2.php", I need to call it (on my local server) like this:
h**p://localhost/index2.php?CPM=22&uSV=0.33 and on Firefox the page source now has the desired layout:<!-- sendmail.asp-->
OK.ERR0
Keep in mind that there is no error checking in your php code; it will always respond with ok, even when it fails!
|
Edited by - ullix on 08/31/2021 01:35:56 |
|
|
Reply #13
mojo66
Germany
32 Posts |
Posted - 08/31/2021 : 15:06:32
|
jlam is running his own web server, and therefore log2.asp is useless to him.
This whole thread is about running your own web server. |
Edited by - mojo66 on 08/31/2021 15:07:14 |
|
|
Reply #14
ullix
Germany
1164 Posts |
Posted - 09/02/2021 : 00:15:28
|
??? really, is that the insight: when I run a completely different framework, it does not matter what code is used on another framework?
|
|
|
Reply #15
ullix
Germany
1164 Posts |
Posted - 09/02/2021 : 01:26:38
|
This seemed such a trivial task that I became curious enough for some more tests. My conclusion:
The problem is not, what the server should answer on a contact by a counter, the question is why the counter can't even make contact to any web address, unless the web address is "www.gmcmap.com".
@ZLN and @EmfDev:
Is it true that the counter cannot interact with anything, unless it is "www.gmcmap.com"? If it is not true, then how can one redirect the counter to a different web site?
Is it true that the counter cannot handle the setting of a port? E.g. I cannot even use "www.gmcmap.com:80". When I do, the counter fails to make a connection. If it is not true, how can a specify a port number?
Since there is an option in the counter to configure the web server, is it true that this is only a fake option, and the address "www.gmcmap.com" is actually hardcoded internally, and anything I enter is ignored? If it is not true, what different addresses are accepted?
|
|
|
Reply #16
ullix
Germany
1164 Posts |
Posted - 09/14/2021 : 01:37:30
|
It's been a while that I had asked the questions in Reply#15, and I am somewhat surprised to have not gotten any answer!
May I conclude that all my conclusions are true, and the GMC counters are explicitly designed to work with nothing but the GMCmap web site, and despite suggestions to the contrary, cannot be used to work with any other web server?
|
|
|
Reply #17
EmfDev
2238 Posts |
Posted - 09/14/2021 : 10:14:51
|
Hello, sorry as I thought I had posted an answer before. The website and URL from the device does matter and it can send to other servers. However looks like the port number cannot be changed. The protocol starts by connecting to server by AT+CIPSTART="TCP","WEBSITE",80. Then later on sends GET /URL?AID=USERID&GID=COUNTERID&CPM=CPM&ACPM=ACPM&uSV=uSV with Host: WEBSITE. |
|
|
Reply #18
ullix
Germany
1164 Posts |
Posted - 09/15/2021 : 00:59:43
|
@EmfDev: Thanks. If I am not mistaken the "AT" command is what you send to the ESP8266 chip in your firmware code. The ESP8266 usually works fine in the systems I have seen.
However, in the case of your counter this results in a request to web servers which is false. Tested on my Apache servers - local and on the web - it always results in these servers' answers of: "400 Bad request". Consistent with that, Apache's error logs say: "AH00566: request failed: malformed request line".
"Malformed" may be caused by a variety of things, most often by illegal characters in the TCP request or any other distortion of it. Your Microsoft ASP server for gmcmap may be programmed to cope with that, but the rest of world servers simply reject such a request.
Can you tell us how the ASP server has been adapted to a "malformed" request line?
|
|
|
Reply #19
mojo66
Germany
32 Posts |
Posted - 09/15/2021 : 14:58:19
|
Perhaps the device only sends garbage that leads to the server responding with 400 if it doesn't receive the "OK.ERR0" from the server. I'm pretty sure that if the server responds with "OK.ERR0" then the device is happy and no 400 code will be generated.
It's a weird protocol though and focusing on Microsoft crap only makes the situation worse. If they'd open-source their firmware, the community could step in and support proper operating systems. But those narrow-minded people will always argue that supporting Microsoft is enough. It's a slow process. |
|
|
Reply #20
ullix
Germany
1164 Posts |
Posted - 09/16/2021 : 00:41:30
|
I think I have found the problem, which turns out to be a combination of a bug in the firmware plus a security issue at the Microsoft server.
This problem is not about finding the proper answer to be given by the server to the counter, but instead about the counter asking a proper request!
The key problem is that the Geiger counter forms a http request which is not fully in accordance with the IETF (Internet Engineering Task Force) rules: https://datatracker.ietf.org/doc/html/rfc7230#section-3.5
Specifically, the counter concludes its http request with a LF-only, while it should have send a CRLF.
A Microsoft ASP server accepts this, while an Apache server rejects it as a security issue (https://httpd.apache.org/security/vulnerabilities_24.html, scroll to: "important: Apache HTTP Request Parsing Whitespace Defects (CVE-2016-8743)")
An Apache server can be modified to accept such ill-formed requests by inserting HttpProtocolOptions Unsafe (the default is "HttpProtocolOptions Strict") into the Apache configuration file apache2.conf
I tested this on my local Apache server, and it works. The GMC-500+ can now communicate with the Apache server at port 80. As long as the server sends a status 200 and not a 400, it needs nothing but an "ERR0" in the answer, but an "OK.ERR0", or even an "ERR0blahblah" does also do!
Though I am wondering how many server admins will enjoy explicitly converting their servers with worldwide access into an "Unsafe" condition?
One may assume that even Microsoft will eventually update their servers into a secure state. This would mean that all existing GQ counters with WiFi will then no longer be able to access the gmcmap website.
I suggest it is time to prepare for a firmware update of all WiFi counters. And while you are at it, provide an option to also select a optional Port!
Which may be a bit of a challenge, as each and every counter needs an update specific to its serial number! :-// Maybe another thing to reconsider!
This analysis comes for free. But you are also free to send a reward!
|
|
|
Reply #21
EmfDev
2238 Posts |
Posted - 09/16/2021 : 10:48:20
|
Thank you for 5-Star quality testing and analysis @ullix we appreciate all your hard work, unfortunately, we are not able to test it.
Here is more of the protocol. You can do it by sending these commands to your device and check for OK in the response for each command. Check to see if there are some garbage being sent.
AT+CIPSTART="TCP",WEBSITE,80\r\n AT+CIPMODE=1\r\n AT+CIPSEND\r\n GET /URL?AID=USERID&GID=COUNTERID&CPM=CPM&ACPM=ACPM&uSV=uSV HTTP/1.1\r\nHost: WEBSITE\r\nConnection: close\r\nAccept: */*\r\n\r\n
...wait for server reply.
|
|
|
Reply #22
ullix
Germany
1164 Posts |
Posted - 09/17/2021 : 00:02:06
|
@EmfDev: These AT commands are intended to be send to the ESP8266 by the C (C++?) code of your firmware. Can they be send to the counter from "outside"?
If so, how?
|
|
|
Reply #23
the_mike
Switzerland
53 Posts |
Posted - 09/17/2021 : 05:26:49
|
Hi @EmfDev
I'm mostly a quiet reader here now, but this issue here... Don't you think it would be wiser to switch to an opensource-software for the counters?
This forum shows so many open issues which are only firmware-related, while the hardware would be capable of doing it..?
Especially here - I mean - c'mon, with the fixed port 80; not one single server-admin would allow a configuration for a publicly available sever to be configured the way it needs to be - bc your firmware-writers hardcoded port 80 into it?! |
Edited by - the_mike on 09/17/2021 05:27:53 |
|
|
Reply #24
EmfDev
2238 Posts |
Posted - 09/17/2021 : 10:30:28
|
@ullix, you can send commands to the device like <AT>> and get the ESP8266 response. Similar to <GETVER>>. If you send <AT>> to your unit, it will send it to the module, then read the response and will send it back to the terminal. Any commands starting with AT will be sent directly to the WiFi Module. And any response that comes from it will be sent to terminal. I dont think it is possible to communicate with it from the outside unless you have a standalone module and just talk to it directly.
@the_mike, that would be a good idea, I will send it to support and see what they think. |
|
|
Reply #25
ullix
Germany
1164 Posts |
Posted - 09/19/2021 : 00:25:59
|
Indeed one can send AT commands to the counter via the Serial interface, which are internally redirected to the ESP8266. So I implemented it in GeigerLog.
I can now even set a port different from 80 with the AT command: quote: <AT+CIPSTART="TCP","10.0.0.20",8000>>
but there is no benefit, because the bug in the code is still resulting in a malformed, "Unsafe" request, preventing any decent server from accepting this request!
Issuing AT command '<AT+GMR>>' results in this answer:quote: 'AT+GMR\r\r\nAT version:1.2.0.0(Jul 1 2016 20:04:45)\r\nSDK version:1.5.4.1(39cb9a32)\r\nAi-Thinker Technology Co. Ltd.\r\nDec 2 2016 14:21:16\r\nOK\r\nWIFI DISCONNECT\r\nWIFI CONNECTED\r\nWIFI GOT IP\r\n\n'
This tells me the counter's firmware uses the AT code from July 1, 2016, more than 5 years old, and, as we see, outdated!
Thus, at present there is no value using these AT commands.
Now I went and made my local Apache server "Unsafe" as described before, to allow the counter talk to this server on port 80. Of course only my local one, because I surely don't want any security issues on my public servers! Then I programmed some php code to forward the counter's request, converted into a safe form, to GeigerLog. GeigerLog has now a full web server built into it, and can read, serve, and interpret requests submitted by WiFi. (This version is not released yet; and, by the way, GeigerLog also has a WiFi client to interact with any device acting as a server.)
The next picture shows an example 2h segment out of an overnight run, generated with a GMC-500+ counter. Light blue is Tube#1 via a regular USB cable with a 1 sec cycle time of GeigerLog, brown is CPM from the WiFi output of the counter with its fastest setting of a 1 min "Period".
The CPM averages of the data shown are:
[Unit] Avg ±StdDev Variance Range
CPM1st : [CPM] 25.670 ±5.14 26.454 9 ... 44
CPM3rd : [CPM] 25.414 ±5.42 29.346 12 ... 39 This is the same within statistics.
Obviously it can be made to work. But is seems absurd that I have to employ a full blown Apache server just to make a bug correction and port conversion!
|
|
|
Reply #26
EmfDev
2238 Posts |
Posted - 09/20/2021 : 09:42:42
|
That is unfortunate, we will check this one to see if we can fix this issue and will try to add a port selection on the firmware. |
|
|
Reply #27
paulca
1 Posts |
Posted - 04/23/2024 : 02:58:17
|
Apologies to re open an old thread, google brought me here.
I scan read the replies, but I didn't see anyone mention the actual bug...
In the OPs log output, it clearly shows that the firmware sends the AT command to close the connection over the TCP connection and NOT infact to the module UART "out of band".
Assuming they are using the Espressif AT firmware this shouldn't happen if the correct +AT is sent to close the stream. To me it looks like it's not been escaped correctly or is the incorrect AT code for the module.
The result of this, if left is that it hangs the webserver connection in ESTABLISHED until timeout. The server sees no "RST+CLOSE" on the tcp connection, so it will continue to keep the connection alive. As the device sends it's data about once a minute you end up spawning a new webserver worker thread for each new connection.
At least from this thread I have the work-around to prevent it. Send the response it wants and then forcefully terminate the connection.
Is there any fix for this in the firmware for the GMC-500+?
192.168.1.240 - - [17/Jun/2021:11:28:48 +0200] "GET /geiger.php?AID=1&GID=1&CPM=22&ACPM=23.66&uSV=0.14 HTTP/1.1" 200 117 192.168.1.240 - - [17/Jun/2021:11:28:58 +0200] "AT+CIPCLOSE" 400 226 192.168.1.240 - - [17/Jun/2021:11:29:52 +0200] "GET /geiger.php?AID=1&GID=1&CPM=30&ACPM=23.66&uSV=0.19 HTTP/1.1" 200 117 192.168.1.240 - - [17/Jun/2021:11:30:12 +0200] "-" 408 - |
|
|
Reply #28
EmfDev
2238 Posts |
Posted - 04/23/2024 : 09:44:51
|
sorry what is the exact issue? |
|
|
|
Topic |
|