When trying to change http header using nf_hook .Unable to send ack to a response instead sending tcp retransmission packets - html

Aim:- Writing a kernel module,when inserted does the following things.
1.if a user wants to open a website named "abcde.in" in any browser ,he should get "google.co.in" webpage, in place of "abcde.in" web page.
Normally accessing google.in i get:-
Observation..(in http header)
302 Moved
The document has moved
HREF=http://www.google.co.in
:-) next i send an ack And i got the google homepage:-
With Modification:-
Steps i have taken
a. edited /etc/hosts
(google.in IP ) abcde.in
So that it gets ip of "google.in"'s for "abcde.in"
b.Next inserting the following piece of module in nf_hook POST_ROUTING implementation
Observation..
i am able to correctly modify and wireshark shows that in reply i am able to get 302 Moved
But i am sending Tcp retransmissions GET / HTTP/1.1. again and again.
I feel i am missing the ack which i need to send as in original case.
why am i unable to send an ack instead of that why i am retransmitting tcp packets to "GET / HTTP/1.1"
if(skb){
liph=(struct iphdr *)skb_network_header(skb);
if(liph->protocol == 6) {
ltcph = (struct tcphdr *)skb_transport_header(skb);
data=skb->data+(liph->ihl*4) + (ltcph->doff*4);
datalen=skb->len - ((liph->ihl*4)+(ltcph->doff*4));
replace_n=strstr(data,"abcde.in");
if(replace_n) {
temp = kmalloc(512 * sizeof(char), GFP_KERNEL);
memcpy(temp, data, datalen);
replace_n=strstr(temp,"abcde.in");
replace_size=strlen("google.in");
site_diff=replace_size - strlen("abcde.in");
memmove(replace_n+strlen("abcde.in")+site_diff,replace_n+strlen("abcde.in"),strlen(replace_n)-strlen("abcde.in"));
memcpy(replace_n,"google.in",strlen("google.in"));
skb_put(skb,site_diff);
memcpy(data,temp,datalen+site_diff);
liph->tot_len=htons(datalen+site_diff+20+(ltcph->doff*4)); /*modifing necessary fields*/
liph->check=0;
liph->check=ip_fast_csum((unsigned char *)liph,liph->ihl);
int ipl=liph->ihl * 4;
int ihl=ntohs(liph->tot_len);
ltcph->check = 0;
skb->csum = csum_partial(ltcph, ihl - ipl, 0);
ltcph->check = tcp_v4_check(ihl - ipl,liph->saddr, liph->daddr, skb->csum);
skb->ip_summed = CHECKSUM_NONE;
Retransmission tck packet wireshark capture

Related

Is possible to get the full json text that is sent to MSXML2.XMLHTTP?

I'm working in VFP9 sending data (in json format) to an api restfull using MSXML2.XMLHTTP.
I need to know if is possible to get the full json text that is sent. At this moment I only can get the data who is send with the "send" method. I need to see the complete json text, with the headers, data, etc. Is this possible?
Thanks in advance.
Alejandro
I use Microsoft.XMLHttp for REST API calls and works fine for me. Don't know if there would be any difference with MSXML2.XMLHTTP though.
First, here is a REST API test code (testing on typeicode.com):
clear
Local loXmlHttp As "Microsoft.XMLHTTP", lcUrl, postData,userID,id,title,body
*** We want to make this REST API call to typicode.com online test service:
***
*** https://jsonplaceholder.typicode.com/posts
*** with parameters payload
***
*** userId:12
*** title:From VFP
*** body:This is posted from VFP as a test
***
*** We do a POST call and want to 'create' a resource (insert call)
userID=12
title="From VFP"
body = "This is posted from VFP as a test"
Text to postData textmerge noshow
{
"userId":<< m.userID >>,
"title":"<< m.title >>",
"body": "<< m.body >>"
}
endtext
lcUrl = 'https://jsonplaceholder.typicode.com'
loXmlHttp = Newobject( "Microsoft.XMLHTTP" )
loXmlHttp.Open( "POST" , m.lcUrl + '/posts', .F. )
loXmlHttp.setRequestHeader("Content-Type","application/json; charset=UTF-8")
loXmlHttp.Send( m.postData )
*** Print the URL we are sending our POST REST request
? m.lcUrl + '/posts'
? "==================================="
? "Post Test", loXmlHttp.Status
? loXmlHttp.responsetext
? "==================================="
*** We get the response code back with loXmlHttp.Status
*** Since we made a POST call to create a resource, on succesful call
*** we expect an 201-Created code back
*** We also print out the full JSON response from the call
*** Which looks like:
***
*** {
*** "userId": 12,
*** "title": "From VFP",
*** "body": "This is posted from VFP as a test",
*** "id": 101
*** }
***
*** Next line simply has a MessageBox to allow you to see the results
*** of the above call before continuing. It also reminds,
*** 200 is the OK and 201 is the Created response code.
MessageBox("Continue? API Codes: 200-OK, 201-Created",0,"REST API Test",10000)
*** Then we try a new call to REST API with a GET call
*** asking to GET the post with id=3
*** If you have checked the typicode.com page there are some data there for testing:
***
***
*** /posts 100 posts
*** /comments 500 comments
*** /albums 100 albums
*** /photos 5000 photos
*** /todos 200 todos
*** /users 10 users
***
*** In our first call we ask for /posts/3
*** You could also go to this link in your browser to get the response back:
*** https://jsonplaceholder.typicode.com/posts/3
***
clear
m.id = 3
loXmlHttp.Open( "GET" , Textmerge('<< m.lcUrl >>/posts/<< m.id >>'), .F. )
loXmlHttp.Send( )
? "Get post with ID X test", loXmlHttp.Status
? loXmlHttp.responsetext
? "==================================="
*** Again we have a MessageBox to allow you to see the results
*** of the above call before continuing.
MessageBox("Continue? API Codes: 200-OK, 201-Created",0,"REST API Test",10000)
clear
*** Finally we try another GET call to REST API
*** asking to GET the comments done for the id=3
***
*** You could also go to this link in your browser to get the response back:
*** https://jsonplaceholder.typicode.com/posts/3/comments
***
loXmlHttp.Open( "GET" , Textmerge('<< m.lcUrl >>/posts/<< m.id >>/comments'), .F. )
loXmlHttp.Send( )
? "Get test post X comments", loXmlHttp.Status
? loXmlHttp.responsetext
? "==================================="
MessageBox("Continue? API Codes: 200-OK, 201-Created",0,"REST API Test",10000)
clear
*** Let's add another final request in this sample
*** to GET, posts done by the user whose userId is 2
userId = 2
loXmlHttp = Newobject( "Microsoft.XMLHTTP" )
loXmlHttp.Open( "GET" , m.lcUrl + '/posts?userId=2', .F. )
loXmlHttp.Open( "GET" , Textmerge('<< m.lcUrl >>/posts?userId=<< m.userId >>'), .F. )
loXmlHttp.Send( )
? "==================================="
? "GET posts of user X's Test", loXmlHttp.Status
? loXmlHttp.responsetext
? "==================================="
To check what you are really sending, you can use tools like postman or ngrok. I will use ngrok here as it is simple. You can use it for free. Download and then at command prompt:
ngrok http 80
80 is default http port, you might choose say 8080, too. It would start a tunnel and on screen sho you the address, and also a web interface address, likely:
http://127.0.0.1:4040
In your browser, go to that adress. In VFP, change your URL for testing and run. ie: We would test the first call in the above sample like this (the address would be different for you, grab it from ngrok's web interface that you opened in browser):
clear
Local loXmlHttp As "Microsoft.XMLHTTP", lcUrl, postData,userID,id,title,body
userID=12
title="From VFP"
body = "This is posted from VFP as a test"
Text to postData textmerge noshow
{
"userId":<< m.userID >>,
"title":"<< m.title >>",
"body": "<< m.body >>"
}
endtext
lcUrl = 'http://30dd0443adff.eu.ngrok.io'
loXmlHttp = Newobject( "Microsoft.XMLHTTP" )
loXmlHttp.Open( "POST" , m.lcUrl + '/posts', .F. )
loXmlHttp.setRequestHeader("Content-Type","application/json; charset=UTF-8")
loXmlHttp.Send( m.postData )
and run it. In ngrok web interface you would see the POST request done. Clicking it you would see details on right, summary, headers, RAW, ... tabs.
If you downloaded and use Postman (it is really great for working on REST API), you could create a POST request there and send, check response, get code in various languages etc but explaining it here is not as easy as the above ngrok. You should however check it if you would work with REST API and it takes 5 mins to start understanding making requests there.

Get only part of a JSON when using an API on NodeMCU

I am using http.get() to get a JSON from an API I am using, but it's not getting the data. I have the suspicion that this JSON is too big for the NodeMCU. I only need the information in the subpart "stats:". Is it possible to only http.get() that part of the JSON?
EDIT:
This is my code
function getstats()
http.get("https://api.aeon-pool.com/v1/stats_address?address=WmsGUrXTR7sgKmHEqRNLgPLndWKSvjFXcd4soHnaxVjY3aBWW4kncTrRcBJJgUkeGwcHfzuZABk6XK6qAp8VmSci2AyGHcUit", nil, function(code, pool)
if (code < 0) then
print("can't get stats")
else
h = cjson.decode(pool)
hashrate = h[1]["hashrate"]
print(hashrate)
dofile('update_display.lua')
end
end)
end
I also have another function getting data from another api above getstats()
function getaeonrate()
http.get("https://api.coinmarketcap.com/v1/ticker/aeon/?convert=EUR", nil, function(code, dataaeon)
if (code < 0) then
print("can't get aeon")
else
-- Decode JSON data
m = cjson.decode(dataaeon)
-- Extract AEON/EUR price from decoded JSON
aeonrate = string.format("%f", m[1]["price_eur"]);
aeonchange = "24h " .. m[1]["percent_change_24h"] .. "% 7d " .. m[1]["percent_change_7d"] .. "%"
dofile('update_display.lua')
end
end)
end
But now the weird thing is, when I want to access 'pool' from getstats() I get the json data from getaeonrate(). So "hashrate" isn't even in the json because I am getting the json from another function.
I tried making a new project only with getstats() and that doesn't work at all I always get errors like this
HTTP client: Disconnected with error: -9
HTTP client: Connection timeout
HTTP client: Connection timeout
Yesterday I thought that the response was too big from api.aeon-pool.com, I if you look at the json in your webbrowser you can see that the top entry is 'stats:' and I only need that, none of the other stuff. So If the request is to big It would be nice to only http.get() that part of the json, hence my original question. At the moment I am not even sure what is not working correctly, I read that the nodemcu firmware generally had problems with http.get() and that it didn't work correctly for a long time, but getting data from api.coinmarketcap.com works fine in the original project.
The problems with the HTTP module are with near certainty related to https://github.com/nodemcu/nodemcu-firmware/issues/1707 (SSL and HTTP are problematic).
Therefore, I tried with the more bare-bone TLS module on the current master branch. This means you need to manually parse the HTTP response including all headers looking for the JSON content. Besides, you seem to be on an older NodeMCU version as you're still using CJSON - I used SJSON below:
Current NodeMCU master branch
function getstats()
buffer = nil
counter = 0
local srv = tls.createConnection()
srv:on("receive", function(sck, payload)
print("[stats] received data, " .. string.len(payload))
if buffer == nil then
buffer = payload
else
buffer = buffer .. payload
end
counter = counter + 1
-- not getting HTTP content-length header back -> poor man's checking for complete response
if counter == 2 then
print("[stats] done, processing payload")
local beginJsonString = buffer:find("{")
local jsonString = buffer:sub(beginJsonString)
local hashrate = sjson.decode(jsonString)["stats"]["hashrate"]
print("[stats] hashrate from aeon-pool.com: " .. hashrate)
end
end)
srv:on("connection", function(sck, c)
sck:send("GET /v1/stats_address?address=WmsGUrXTR7sgKmHEqRNLgPLndWKSvjFXcd4soHnaxVjY3aBWW4kncTrRcBJJgUkeGwcHfzuZABk6XK6qAp8VmSci2AyGHcUit HTTP/1.1\r\nHost: api.aeon-pool.com\r\nConnection: close\r\nAccept: */*\r\n\r\n")
end)
srv:connect(443, "api.aeon-pool.com")
end
Note that the receive event is fired for every network frame: https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketon
NodeMCU fails to establish a connection to api.coinmarketcap.com due to a TLS handshake failure. Not sure why that is. Otherwise your getaeonrate() could be implemented likewise.
Frozen 1.5.4 branch
With the old branch the net module can connect to coinmarketcap.com.
function getaeonrate()
local srv = net.createConnection(net.TCP, 1)
srv:on("receive", function(sck, payload)
print("[aeon rate] received data, " .. string.len(payload))
local beginJsonString = payload:find("%[")
local jsonString = payload:sub(beginJsonString)
local json = cjson.decode(jsonString)
local aeonrate = string.format("%f", json[1]["price_eur"]);
local aeonchange = "24h " .. json[1]["percent_change_24h"] .. "% 7d " .. json[1]["percent_change_7d"] .. "%"
print("[aeon rate] aeonrate from coinmarketcap.com: " .. aeonrate)
print("[aeon rate] aeonchange from coinmarketcap.com: " .. aeonchange)
end)
srv:on("connection", function(sck, c)
sck:send("GET /v1/ticker/aeon/?convert=EUR HTTP/1.1\r\nHost: api.coinmarketcap.com\r\nConnection: close\r\nAccept: */*\r\n\r\n")
end)
srv:connect(443, "api.coinmarketcap.com")
end
Conclusion
The HTTP module and TLS seem a no-go for your APIs due to a bug in the firmware (1707).
The net/TLS module of the current master branch manages to connect to api.aeon-pool.com but not to api.coinmarketcap.com.
With the old and frozen 1.5.4 branch it's exactly the other way around.
There may (also) be issues with cipher suits that don't match between the firmware and the API provider(s).
-> :( no fun like that

MySql Client's Credentials Packet

How should the client's credentials packet look when communicating with a MySql server?
I am working on using a microcontroller to communicate with a MySql server on AWS.
Once I open a TCP socket to the server I receive the server's greeting packet. However, I am having trouble with the client's credentials packet.
When I send the packet I created in the code below, I do not receive a response from the server.
As a side note, I do receive the error "Got packets out of order" when I set the packet sequence number to 0 instead of 1. Any ideas?
Server's greeting:
4e0000000a352e362e33372d6c6f67006a3300005871507a363d6e3400ffff0802007fc01500000000000000000000542d2364524c65392d752659006d7973716c5f6e61746976655f70617373776f726400
Server's Error message:
21000001ff8404233038533031476f74207061636b657473206f7574206f66206f72646572
char buf[76];
memset(buf, 0, sizeof(buf));
buf[0] = 0x4C;
buf[1] = 0x00;
buf[2] = 0x00;
buf[3] = 0x01;
buf[4] = 0x08 | 0x04;
buf[5] = 0x80 | 0x02 | 0x01;
buf[6] = 0x00;
buf[7] = 0x00;
buf[8] = 0xB8;
buf[9] = 0x0B;
buf[10] = 0x00;
buf[11] = 0x00;
buf[12] = 0x35;
char username[] = "username";
size_t usernameLength = sizeof(username);
strncpy(&buf[36],username,usernameLength-1);
buf[48] = 0x00;
char password[] = "password";
size_t passwordLength = sizeof(password);
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1(password, passwordLength-1, hash);
buf[49] = 0x14;
memcpy(&buf[50],&hash[0],20);
strncpy(&buf[70],"dbname",sizeof("dbname")-1);
buf[75] = 0x00;
I understand that this was not an appropriate place to ask the question I had. However, after posting, I did find a very helpful repository on Github here: https://github.com/ChuckBell/MySQL_Connector_Arduino
The repository contains all of the source code necessary to write a client which connects to a MySQL database. Most importantly, it shows the proper way to hash the password.
I hope this helps other people since there is very little documentation of MySQL provided by Oracle unless you license the software, regular clients don't provide source code, and observing packet traffic provides limited insight into how the handshake process works.

IRC bot pong doesn't work

I've created bot, using code from this page.
Everything was good, when I was trying to reach irc.rizon.net. But problem arrives, when I've changed server to irc.alphachat.net.
#!/usr/bin/env python3
import socket
server = 'irc.alphachat.net'
channel = '#somechannel'
NICK = 'somenick'
IDENT = 'somenick'
REALNAME = 'somenick'
port = 6667
def joinchan(chan):
ircsock.send(bytes('JOIN %s\r\n' % chan, 'UTF-8'))
def ping(): # This is our first function! It will respond to server Pings.
ircsock.send(bytes("QUOTE PONG \r\n", 'UTF-8'))
def send_message(chan, msg):
ircsock.send(bytes('PRIVMSG %s :%s\r\n' % (chan, msg), 'UTF-8'))
ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ircsock.connect((server, port)) # Here we connect to the server using the port 6667
ircsock.send(bytes("USER "+ NICK +" "+ NICK +" "+ NICK +" :This bot\n", 'UTF-8')) # user authentication
ircsock.send(bytes("NICK "+ NICK +"\n", 'UTF-8')) # here we actually assign the nick to the bot
joinchan(channel) # Join the channel using the functions we previously defined
while 1: # Be careful with these! it might send you to an infinite loop
ircmsg = ircsock.recv(2048).decode() # receive data from the server
ircmsg = ircmsg.strip('\n\r') # removing any unnecessary linebreaks.
print(ircmsg) # Here we print what's coming from the server
if ircmsg.find(' PRIVMSG ')!=-1:
nick=ircmsg.split('!')[0][1:]
if ircmsg.find("PING :") != -1: # if the server pings us then we've got to respond!
ping()
if ircmsg.find(":Hello "+ NICK) != -1: # If we can find "Hello Mybot" it will call the function hello()
hello()
Problem is with ping command because I don't know how to answer to server:
:irc-us2.alphachat.net NOTICE * :*** Looking up your hostname...
:irc-us2.alphachat.net NOTICE * :*** Checking Ident
:irc-us2.alphachat.net NOTICE * :*** Found your hostname
:irc-us2.alphachat.net NOTICE * :*** No Ident response
PING :CE661578
:irc-us2.alphachat.net 451 * :You have not registered
With IRC, you should really split each line up by ' ' (space) into chunks to process it - something like this should work after your print (untested)
The reason it's not working is because you're not replying to PINGs properly
chunk = ircmsg.split(' ')
if chunk[0] == 'PING': # This is a ping
ircsock.send(bytes('PONG :%s\r\n' % (chunk[1]), 'UTF-8')) # Send a pong!
if chunk[1] == 'PRIVMSG': # This is a message
if chunk[3] == ':Hello': # Hey, someone said hello!
send_message(chunk[2], "Hi there!") # chunk[2] is channel / private!
if chunk[1] == '001': # We've logged on
joinchannel(channel) # Let's join!
send_message(channel, "I've arrived! :-)") # Announce to the channel
Normally the command / numeric is found in the second parameter (chunk[1]) - The only exception I can think of is PING which is found in the first (chunk[0])
Also note that I moved joinchannel() - you should only be doing this after you're logged on.
Edit: Didn't realise the age of this post. Sorry!
I believe you just need to make a small change to the string you send in response to the ping request.
try using:
ircsock.send(bytes("PONG pingis\n", "UTF-8"))
This ping response works for me on freenode.

AS3 Socket ProcessEvent.SOCKET_DATA seems not triggered

We use AS3 Event:ProcessEvent.SOCKET_DATA to listen for socket data.
So this is my AS3 code for socket data handle.
private function packetHandler( e:ProgressEvent ):void
{
while( m_socket.bytesAvailable && m_socket.bytesAvailable >= pLen )
{
//pLen means the packet length
//pLen init is zero
if( pLen == 0 )
{
//PACKET_LEN stands for the solid length of one packet
//PACKET_LEN = HEAD_LEN + 4
//the 4 means an unsigned int which means the packet content length
if( m_socket.bytesAvailable > PACKET_LEN )
{
m_socket.readBytes( headByteBuffer, 0, HEAD_LEN );
headByteBuffer.clear();
pLen = m_socket.readUnsignedInt() + 4;
}
else
{
break;
}
}
//recieved a whole packet now handle it
else
{
var newPacket:ByteArray = new ByteArray();
newPacket.endian = Endian.LITTLE_ENDIAN;
m_socket.readBytes( newPacket, 0, pLen );
parasMsg( newPacket, pLen-4 );
pLen = 0;
}
}
}
A whole packet can be described in this picture:
My Problem is: When there has one incomplete packet received in Flash and triggered the handle.
But the left part of the packet will never trigger the handle and it seems like that the left part of the packet has lost!!!
I used a capture tool, find that the tcp packet is ok, but why the left part doesn't trigger the event again?
You can get more debug information below. Thank you!
This is my log:
byteava means bytesAvailable of m_socket
==>sendPacket: {"rangeID":"1","uid":"145962","serviceType":"copyscene","cmd":"CopySceneMoveAsk","pathPoint":[{"col":7,"row":6},{"col":7,"row":5},{"col":7,"row":4},{"col":7,"row":3},{"col":6,"row":3}],"sn":"79","smallPathPoint":[[22,19],[22,18],[22,17],[22,16],[22,15],[22,14],[22,13],[21,13],[21,12],[21,11],[20,11],[20,10]]}, bytesLoaded = 463
ProgressEvent Triggered!0 socket byteava = 373 evt loaded:373 evt total:0 evt:[ProgressEvent type="socketData" bubbles=false cancelable=false eventPhase=2 bytesLoaded=373 bytesTotal=0]
Find a packet from socket, pLen=288 socket byteava = 276
ProgressEvent Triggered!288 socket byteava = 441 evt loaded:165 evt total:0 evt:[ProgressEvent type="socketData" bubbles=false cancelable=false eventPhase=2 bytesLoaded=165 bytesTotal=0]
Start to Read a packet to buffer, pLen=288 socket byteava = 441
whole packet content: Readed a packet to buffer, pLen=288 socket byteava = 153
Server packet content byte buffer ava:288 len:288 pos: 0
Server Paras Data : data len: 284 data content: {"cmd":"CopySceneMoveNotify","gtcmd":"108","layer":"1","pathPoint":[{"col":7,"row":6},{"col":7,"row":5},{"col":7,"row":4},{"col":7,"row":3},{"col":6,"row":3}],"smallPathPoint":[[22,19],[22,18],[22,17],[22,16],[22,15],[22,14],[22,13],[21,13],[21,12],[21,11],[20,11],[20,10]HTTP/1.1 200
_[20,10]HTTP/1.1 200_ This is what went wrong!! The incomplete packet cat with another packet's header.
Here is the capture of the TCP connections:
Hope you can vote it up so that I can put my pictures of this question on!
My English is not very good, hope you can understand what I mean.
Thank you!
The Socket's event flash.events.ProgressEvent.SOCKET_DATA will fire when you receive the data at this point you can get the received bytes ( check .bytesAvailable ). When the msg is split into multiple packages you will receive event for each packet.
In your case maybe the pLen have wrong value when check m_socket.bytesAvailable >= pLen.
I assume you send the msg size in the begging of the message ( in this case you can check if the whole msg is received ). In this case you must have a class member (ByteArray ) as buffer that holds a received bytes. When new data come you must copy the new bytes to this member and than check if you receive whole msg. If buffer contains whole msg than remove the msg from it.
In general your event handler must looks like this:
protected function onSocketData( pEvt: Event ): void
{
try
{
if ( 0 < pEvt.target.bytesAvailable )
{
var byteStream: ByteArray = new ByteArray();
pEvt.target.readBytes( byteStream, 0, Socket( pEvt.target ).bytesAvailable );
// Append readed data to your buffer
do
{
//Check if you have enough bytes to read whole msg and execute it
//do..while because maybe it can be more than one msg in buffer
}
while ( null != msgContent );
}
}
catch ( exc )
{
}
}
Problem should caused by the packet's solid header.
Below is the 93 bytes solid header of a packet.
private static const HTTP_RESPONSE_CONTENT : String = "HTTP/1.1 200 OK \r\n"
+ "Connection: keep-alive \r\n"
+ "Content-Length: 280 \r\n"
+ "Content-Type: text/html \r\n\r\n";
This header will be in every packet's header, which AS3 could treat it to a http and might cut the flow with Content-Length: 280. So the left part of the 280 bytes will never trigger the SOCKET_DATA event.
When I remove this header, it's ok now.