Simulate an HTTP/2 stream with pcap4j - wireshark

I'm trying to capture the unencrypted bytes of a TLS connection and record them into a cap file for analysis of the HTTP/2 traffic. There are a lot of assumptions I am making that this is even possible. But I'm willing to fudge almost everything below the HTTP/2 layer if I can see that traffic in a useful tool like Wireshark.
https://github.com/yschimke/okhttp/commit/c6b0b4c0ba3b59d44cf292955eef2685ed6094e7#diff-d4b38ff70d61641e49af93db2892080f47a2480af92ca151b2daabb50bbc459b
My approach eventually boils down to
return object : DelegatingSSLSocket(socket) {
override fun getInputStream(): InputStream {
return object : FilterInputStream(socket.inputStream) {
override fun read(b: ByteArray, off: Int, len: Int): Int {
return super.read(b, off, len).also { readLen ->
dumper.dump(
ipv4ReadPacketBuilder.payloadBuilder(
tcpReadPacketBuilder
.payloadBuilder(
UnknownPacket.Builder().rawData(
b.sliceArray(off.rangeTo(off + readLen))
)
)
)
.build()
)
}
}
}
}
override fun getOutputStream(): OutputStream {
return object : FilterOutputStream(socket.outputStream) {
override fun write(b: ByteArray, off: Int, len: Int) {
super.write(b, off, len)
dumper.dump(
ipv4WritePacketBuilder.payloadBuilder(
tcpWritePacketBuilder
.payloadBuilder(
UnknownPacket.Builder().rawData(b.sliceArray(off.rangeTo(off + len)))
)
)
.build()
)
}
}
}
}
Does anyone have any advice on pcap4j or pcap files generally to see what I'm doing wrong?
The packets I'm writing are IPv4>TCP>Data
But Wireshark shows

For IPv4, Version is always equal to 4. Your image states that you are trying to write IPv4 Header but hex codes shows that it is not the IPv4 header.
First highlighted number is 56. Instead of 5 it should be 4. Hence Wireshark is unable to detect it as a IPv4 packet.
Refer my below link, it will help you to understand the sample format.
How to obtain the source IP from a Wireshark dump of an HTTP GET request
For TCP, it should be 06 instead of bb.
Also your source IP is 0.0.0.0. It will not generate any error but you can change it as per your requirement.

Related

Dart TCP socket concatenates all 'write' sync calls as a single packet

I'm trying to send multiple packets at once to a server, but the socket keeps "merging" all sync calls to write as a single call, I did a minimal reproducible example:
import 'dart:io';
void main() async {
// <Server-side> Create server in the local network at port <any available port>.
final ServerSocket server =
await ServerSocket.bind(InternetAddress.anyIPv4, 0);
server.listen((Socket client) {
int i = 1;
client.map(String.fromCharCodes).listen((String message) {
print('Got a new message (${i++}): $message');
});
});
// <Client-side> Connects to the server.
final Socket socket = await Socket.connect('localhost', server.port);
socket.write('Hi World');
socket.write('Hello World');
}
The result is:
> dart example.dart
> Got a new message (1): Hi WorldHello World
What I expect is:
> dart example.dart
> Got a new message (1): Hi World
> Got a new message (2): Hello World
Unfortunately dart.dev doesn't support dart:io library, so you need to run in your machine to see it working.
But in summary:
It creates a new tcp server at a random port.
Then creates a socket that connects to the previous created server.
The socket makes 2 synchronous calls to the write method.
The server only receives 1 call, which is the 2 messages concatenated.
Do we have some way to receive each synchronous write call in the server as separated packets instead buffering all sync calls into a single packet?
What I've already tried:
Using socket.setOption(SocketOption.tcpNoDelay, true); right after Socket.connect instantiation, this does modify the result:
final Socket socket = await Socket.connect('localhost', server.port);
socket.setOption(SocketOption.tcpNoDelay, true);
// ...
Using socket.add('Hi World'.codeUnits); instead of socket.write(...), also does not modify the result as expected, because write(...) seems to be just a short version add(...):
socket.add('Hi World'.codeUnits);
socket.add('Hello World'.codeUnits);
Side note:
Adding an async delay to avoid calling write synchronously:
socket.add('Hi World'.codeUnits);
await Future<void>.delayed(const Duration(milliseconds: 100));
socket.add('Hello World'.codeUnits);
make it works, but I am pretty sure this is not the right solution, and this isn't what I wanted.
Environment:
Dart SDK version: 2.18.4 (stable) (Tue Nov 1 15:15:07 2022 +0000) on "windows_x64"
This is a Dart-only environment, there is no Flutter attached to the workspace.
As Jeremy said:
Programmers coding directly to the TCP API have to implement this logic themselves (e.g. by prepending a fixed-length message-byte-count field to each of their application-level messages, and adding logic to the receiving program to parse these byte-count fields, read in that many additional bytes, and then present those bytes together to the next level of logic).
So I chose to:
Prefix each message with a - and suffix with ..
Use base64 to encode the real message to avoid conflict between the message and the previously defined separators.
And using this approach, I got this implementation:
// Send packets:
socket.write('-${base64Encode("Hi World".codeUnits)}.');
socket.write('-${base64Encode("Hello World".codeUnits)}.');
And to parse the packets:
// Cache the previous parsed packet data.
String parsed = '';
void _handleCompletePacket(String rawPacket) {
// Decode the original message from base64 using [base64Decode].
// And convert the [List<int>] to [String].
final String message = String.fromCharCodes(base64Decode(rawPacket));
print(message);
}
void _handleServerPacket(List<int> rawPacket) {
final String packet = String.fromCharCodes(rawPacket);
final String next = parsed + packet;
final List<String> items = <String>[];
final List<String> tokens = next.split('');
for (int i = 0; i < tokens.length; i++) {
final String char = tokens[i];
if (char == '-') {
if (items.isNotEmpty) {
// malformatted packet.
items.clear();
continue;
}
items.add('');
continue;
} else if (char == '.') {
if (items.isEmpty) {
// malformatted packet.
items.clear();
continue;
}
_handleCompletePacket(items.removeLast());
continue;
} else {
if (items.isEmpty) {
// malformatted packet.
items.clear();
continue;
}
items.last = items.last + char;
continue;
}
}
if (items.isNotEmpty) {
// the last data of this packet was left incomplete.
// cache it to complete with the next packet.
parsed = items.last;
}
}
client.listen(_handleServerPacket);
There are certainly more optimized solutions/approaches, but I got this just for chatting messages within [100-500] characters, so that's fine for now.

Http client mode with Contiki?

I want to make a webAPI call from a sensor using http, is it possible to do http requests using Contiki OS?
As far as I've searched I found only coap client examples.
Check the examples/http-socket example, it shows how to use CRUD methods such as PUT, GET, etc.
Here's the link to the example (working with the latest master commit)
This example relies on IP64, but can be changed to work with IPv6, basically you need to include the http-socket library. Here are the more relevant parts of the example:
#include "contiki-net.h"
#include "http-socket.h"
#include "ip64-addr.h"
#include <stdio.h>
static struct http_socket s;
static int bytes_received = 0;
static void
callback(struct http_socket *s, void *ptr,
http_socket_event_t e,
const uint8_t *data, uint16_t datalen)
{
if(e == HTTP_SOCKET_ERR) {
printf("HTTP socket error\n");
} else if(e == HTTP_SOCKET_DATA) {
bytes_received += datalen;
printf("HTTP socket received %d bytes of data\n", datalen);
}
}
PROCESS_THREAD(http_example_process, ev, data)
{
PROCESS_BEGIN();
/* Initializes the socket */
http_socket_init(&s);
/* GET request */
http_socket_get(&s, "http://www.contiki-os.org/", 0, 0,
callback, NULL);
/* Waits forever for the HTTP callback */
while(1) {
PROCESS_WAIT_EVENT_UNTIL(0);
}
PROCESS_END();
}
Yes you can do that:
What I understand is that you are looking for Websense Example in Contiki OS.it uses HTTP protocl.
A: so find this file.
~/contiki/examples/zolertia/z1/ipv6/z1-websense/z1-websense.c
Burn it on Sender Mote.
Burn border-router.c file located in /home/superuser/contiki/examples/ipv6/rpl-border-router/
Connect Border Router with tunnelslip with command make connect-router.
use the HTTP IPV6 url shown by tunnelslip on connection.
this url in browser will give you address of motes connected to it.
use that sender mote address in web browser and see the mote output.
B: or from contiki/cooja simulator:
launch this project file. this is working demo for the websense.
~contiki/examples/zolertia/z1/ipv6/z1-websense/example-z1-websense.csc
and repeat from step 3.
for further you can ask me.

http response got truncated in docker

I've built a http server using netty. Everything is fine when it's running in my mac, but when I run it in a docker image, the http response always get truncated when great than 460k.
What's the problem will be? Please help.
Do you use aggregator to aggregate the http response or not? Take a look at the source code of HttpObjectDecoder. It will chunk bigger http response no matter if the http message itself is transfer coding or not.
The default maxChunk size is 8k.And even readable bytes is enough, it will chunk it. see the code below:
` case READ_FIXED_LENGTH_CONTENT: {
int readLimit = actualReadableBytes();
// Check if the buffer is readable first as we use the readable byte count
// to create the HttpChunk. This is needed as otherwise we may end up with
// create a HttpChunk instance that contains an empty buffer and so is
// handled like it is the last HttpChunk.
//
// See https://github.com/netty/netty/issues/433
if (readLimit == 0) {
return;
}
int toRead = Math.min(readLimit, maxChunkSize);
if (toRead > chunkSize) {
toRead = (int) chunkSize;
}
ByteBuf content = readBytes(ctx.alloc(), buffer, toRead);
chunkSize -= toRead;
`

New Command 2 Apple Push Notification Not sending multiple alerts

I am trying to implement the new 'Command 2' push notification in Java and cannot have it push multiple alerts. First alert is pushed successfully. Please help if you can spot any issue on this code
Apple specs
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW1
for (DeviceApps deviceApps : deviceAppsList) {
outputStream.write(getByteArray(deviceApps, pushAlert));
}
private byte[] getByteArray(DeviceApps deviceApps, PushAlert pushAlert) {
ByteArrayOutputStream dataBao = new ByteArrayOutputStream();
// Write the TokenLength as a 16bits unsigned int, in big endian
dataBao.write((byte)1);
dataBao.write(intTo2ByteArray(32));
dataBao.write(deviceTokenAsBytes);
// Write the PayloadLength as a 16bits unsigned int, in big endian
dataBao.write((byte)2);
dataBao.write(intTo2ByteArray(payLoadAsBytes.length));
dataBao.write(payLoadAsBytes);
// 4 bytes. Notification identifier
dataBao.write((byte)3);
dataBao.write(intTo2ByteArray(4));
dataBao.write(intTo4ByteArray(random.nextInt()));
// 4 bytes Expiration date
dataBao.write((byte)4);
dataBao.write(intTo2ByteArray(4));
dataBao.write(intTo4ByteArray(pushAlert.getUtcExpireTime()));
LOG.error("UtcExpireTime="+ pushAlert.getUtcExpireTime());
// 1 bytes Priority
dataBao.write((byte)5);
dataBao.write(intTo2ByteArray(1));
dataBao.write((byte)10);
//Frame Info
bao = new ByteArrayOutputStream();
bao.write((byte)2);
byte [] data = dataBao.toByteArray();
bao.write(intTo4ByteArray(data.length));
LOG.error(" data.length "+data.length);
bao.write(data);
return bao.toByteArray();
}
Support Methods
private static final byte[] intTo4ByteArray(int value) {
return ByteBuffer.allocate(4).putInt(value).array();
}
private static final byte[] intTo2ByteArray(int value) {
int s1 = (value & 0xFF00) >> 8;
int s2 = value & 0xFF;
return new byte[] { (byte) s1, (byte) s2 };
}
It looks like you are writing a single notification to bao, so why do you expect it to push multiple alerts? If you want to push multiple alerts, you have to repeat that sequence of bytes that you write into bao multiple times.
The command 2 and the frame data length applies to each message. If you send multiple messages in one connection, then for each message: send command 2, the message's frame data length, and the 5 parts (token, payload, id, expiry, priority)
Since you are getting back a an error code from APNS, the connection should be dropped at that point and APNS will ignore everything after the error. When you receive an error back, the identifier is the identifier you are currently using a random number for.
There's no easy solution here -- you have to rearchitect what you have so that when you receive the error, you can figure out everything after that point and resend -- I'd recommend using a sequential number for the Identifier and then storing the packets in a queue that you purge periodically (you have to keep them around for say 30 seconds to guarantee that Apple Accepted them).

Arduino WiFi shield post with header problems

I'm trying to do a post from the arduino wifi shield to my java servlet. The servlet functions with url get, and jquery post, but I can't sort the headers out in my arduino code. Any help will be greatly appreciated!
The server returns 200, but I'm not getting the payload "content" as value. I'm not exactly sure what I'm doing wrong but I'm pretty sure it's in how my headers are setup. I've spent the last two days trying to get it.
#include <SPI.h>
#include <WiFi.h>
char ssid[] = "jesussavesforjust19.95"; // your network SSID (name)
char pass[] = "********"; // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0; // your network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;
IPAddress server(192,168,10,149); // numeric IP for Google (no DNS)
WiFiClient client;
void setup() {
Serial.begin(9600);
// attempt to connect to Wifi network:
while ( status != WL_CONNECTED) {
Serial.println("Attempting to connect to SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to wifi");
printWifiStatus();
sendData("0600890876");
}
void loop() {
// if there's incoming data from the net connection.
// send it out the serial port. This is for debugging
// purposes only:
if (client.available()) {
char c = client.read();
Serial.println(c);
}
//String dataString = "060088765";
// if you're not connected, and ten seconds have passed since
// your last connection, then connect again and send data:
if(!client.connected())
{
Serial.println();
Serial.println("disconnecting.");
client.stop();
//sendData(dataString);
for(;;)
;
}
}
// this method makes a HTTP connection to the server:
void sendData(String thisData) {
// if there's a successful connection:
Serial.println("send data");
if (client.connect(server, 8080)) {
String content = "value=0600887654";
Serial.println(content);
Serial.println("connected");
client.println("POST /hos HTTP/1.1");
client.println("Host:localhost");
client.println("Connection:Keep-Alive");
client.println("Cache-Control:max-age=0");
client.println("Content-Type: application/x-www-form-urlencoded\n");
client.println("Content-Length: ");
client.println(content.length());
client.println("\n\n");
client.println(content);
}
else {
// if you couldn't make a connection:
Serial.println("form connection failed");
Serial.println();
Serial.println("disconnecting.");
client.stop();
}
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.println("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.println("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.println("signal strength (RSSI):");
Serial.println(rssi);
Serial.println(" dBm");
}
Perhaps, some of your "Serial.println" and "client.println" commands should be "Serial.print" and "client.print" instead. For example:
client.print("Content-Length: ");
client.println(content.length());
would avoid adding a line break between the text and the number.
This is maybe more advice on an approach than an answer.
If I was doing something like this I would not start on the Arduino. The endless compile, download, run, look at print()'s would drive me crazy. I would fully prototype the client/server interaction in whatever you have at your fingertips, preferably something with a debugger. (Java, Python, PHP, VB, whatever you know that you can slap together)
Second, I would run Wireshark on the server so that I could see exactly what was being sent and responded.
Then I would port the same interaction over to the Arduino. Again inspect with Wireshark to confirm you are getting what you expected. If you send the same bytes, you should get the same response.
Even if you choose to implement straight on Arduino, consider having Wireshark to capture the actual network traffic.
With Wireshark, you might see that the Arduino println() is not sending the correct line end for the server.
Also, there is no guarantee that last println() is actually sent. The network stack implementation is free to buffer as it sees fit. You might need a flush(). A packet trace would show this.
With a packet capture you might find that time matters. In theory TCP is a stream and you should be able to send that POST data 1 character at a time in 1 packet and everything would work. But the Arduino might be so slow executing those println()'s by the server's standards that it times out. In such case you would see the server respond before the Arduino even finished sending.

Resources