Skip to content

Commit

Permalink
reduced code duplication in WispNetworkAdapter
Browse files Browse the repository at this point in the history
- added missing callback WispNetworkAdapter.on_tcp_connection(packet, tuple),
  moved all relevant code from WispNetworkAdapter.send(data) to new method,
  replaced with call to handle_fake_tcp() (now identical to FetchNetworkAdapter)
- removed redundant first argument of adapter.on_tcp_connection(adapter, ...)
- added TCP_STATE_SYN_RECEIVED -> TCP_STATE_ESTABLISHED state transition back in (just to be sure)

The larger goal is to replace all code in WispNetworkAdapter.send(data) with a call to handle_fake_networking(), just like in FetchNetworkAdapter. The only difference left is two alternate fake DNS implementations.
  • Loading branch information
chschnell committed Nov 24, 2024
1 parent 38e01d8 commit a73e383
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 113 deletions.
22 changes: 13 additions & 9 deletions src/browser/fake_network.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,20 +235,13 @@ function make_packet(out, spec)

function handle_fake_tcp(packet, adapter)
{
let reply = {};
reply.eth = { ethertype: ETHERTYPE_IPV4, src: adapter.router_mac, dest: packet.eth.src };
reply.ipv4 = {
proto: IPV4_PROTO_TCP,
src: packet.ipv4.dest,
dest: packet.ipv4.src
};
const tuple = `${packet.ipv4.src.join(".")}:${packet.tcp.sport}:${packet.ipv4.dest.join(".")}:${packet.tcp.dport}`;

if(packet.tcp.syn) {
if(adapter.tcp_conn[tuple]) {
dbg_log("SYN to already opened port", LOG_FETCH);
}
if(adapter.on_tcp_connection(adapter, packet, tuple)) {
if(adapter.on_tcp_connection(packet, tuple)) {
return;
}
}
Expand All @@ -257,6 +250,13 @@ function handle_fake_tcp(packet, adapter)
dbg_log(`I dont know about ${tuple}, so resetting`, LOG_FETCH);
let bop = packet.tcp.ackn;
if(packet.tcp.fin || packet.tcp.syn) bop += 1;
let reply = {};
reply.eth = { ethertype: ETHERTYPE_IPV4, src: adapter.router_mac, dest: packet.eth.src };
reply.ipv4 = {
proto: IPV4_PROTO_TCP,
src: packet.ipv4.dest,
dest: packet.ipv4.src
};
reply.tcp = {
sport: packet.tcp.dport,
dport: packet.tcp.sport,
Expand Down Expand Up @@ -1068,7 +1068,11 @@ TCPConnection.prototype.process = function(packet) {
}

if(packet.tcp.ack) {
if(this.state === TCP_STATE_FIN_WAIT_1) {
if(this.state === TCP_STATE_SYN_RECEIVED) {
// dbg_log(`TCP[${this.tuple}]: received ACK in state "${this.state}", next "${TCP_STATE_ESTABLISHED}"`, LOG_FETCH);
this.state = TCP_STATE_ESTABLISHED;
}
else if(this.state === TCP_STATE_FIN_WAIT_1) {
if(!packet.tcp.fin) { // handle FIN+ACK in FIN_WAIT_1 separately further down below
// dbg_log(`TCP[${this.tuple}]: received ACK in state "${this.state}", next "${TCP_STATE_FIN_WAIT_2}"`, LOG_FETCH);
this.state = TCP_STATE_FIN_WAIT_2;
Expand Down
4 changes: 2 additions & 2 deletions src/browser/fetch_network.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ FetchNetworkAdapter.prototype.destroy = function()
{
};

FetchNetworkAdapter.prototype.on_tcp_connection = function(adapter, packet, tuple)
FetchNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
{
if(packet.tcp.dport === 80) {
let conn = new TCPConnection();
Expand All @@ -47,7 +47,7 @@ FetchNetworkAdapter.prototype.on_tcp_connection = function(adapter, packet, tupl
conn.on_data = on_data_http;
conn.tuple = tuple;
conn.accept(packet);
adapter.tcp_conn[tuple] = conn;
this.tcp_conn[tuple] = conn;
return true;
}
return false;
Expand Down
168 changes: 66 additions & 102 deletions src/browser/wisp_network.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ WispNetworkAdapter.prototype.send_wisp_frame = function(frame_obj) {
const hostname_buffer = new TextEncoder().encode(frame_obj.hostname);
full_packet = new Uint8Array(5 + 1 + 2 + hostname_buffer.length);
view = new DataView(full_packet.buffer);
view.setUint8(0, 0x01); // TYPE
view.setUint8(0, 0x01); // TYPE
view.setUint32(1, frame_obj.stream_id, true); // Stream ID
view.setUint8(5, 0x01); // TCP
view.setUint16(6, frame_obj.port, true); // PORT
view.setUint8(5, 0x01); // TCP
view.setUint16(6, frame_obj.port, true); // PORT
full_packet.set(hostname_buffer, 8); // hostname

// Setting callbacks
Expand All @@ -147,16 +147,16 @@ WispNetworkAdapter.prototype.send_wisp_frame = function(frame_obj) {
case "DATA":
full_packet = new Uint8Array(5 + frame_obj.data.length);
view = new DataView(full_packet.buffer);
view.setUint8(0, 0x02); // TYPE
view.setUint8(0, 0x02); // TYPE
view.setUint32(1, frame_obj.stream_id, true); // Stream ID
full_packet.set(frame_obj.data, 5); // Actual data
break;
case "CLOSE":
full_packet = new Uint8Array(5 + 1);
view = new DataView(full_packet.buffer);
view.setUint8(0, 0x04); // TYPE
view.setUint8(0, 0x04); // TYPE
view.setUint32(1, frame_obj.stream_id, true); // Stream ID
view.setUint8(5, frame_obj.reason); // Packet size
view.setUint8(5, frame_obj.reason); // Packet size
break;
default:
dbg_log("Client tried to send unknown packet: " + frame_obj.type, LOG_NET);
Expand All @@ -176,117 +176,81 @@ WispNetworkAdapter.prototype.destroy = function()
};

/**
* @param {Uint8Array} data
* @param {Uint8Array} packet
* @param {String} tuple
*/
WispNetworkAdapter.prototype.send = function(data)
WispNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
{
let packet = {};
parse_eth(data, packet);

if(packet.ipv4) {
if(packet.tcp) {
let reply = {};
reply.eth = { ethertype: ETHERTYPE_IPV4, src: this.router_mac, dest: packet.eth.src };
reply.ipv4 = {
proto: IPV4_PROTO_TCP,
src: packet.ipv4.dest,
dest: packet.ipv4.src
};

let tuple = [
packet.ipv4.src.join("."),
packet.tcp.sport,
packet.ipv4.dest.join("."),
packet.tcp.dport
].join(":");

if(packet.tcp.syn) {
if(this.tcp_conn[tuple]) {
dbg_log("SYN to already opened port", LOG_FETCH);
}
const tcp_conn = new TCPConnection();
let conn = new TCPConnection();
conn.state = TCP_STATE_SYN_RECEIVED;
conn.net = this;
conn.tuple = tuple;
conn.stream_id = this.last_stream++;
this.tcp_conn[tuple] = conn;

tcp_conn.state = TCP_STATE_SYN_RECEIVED;
tcp_conn.net = this;
tcp_conn.tuple = tuple;
tcp_conn.stream_id = this.last_stream++;
this.tcp_conn[tuple] = tcp_conn;

tcp_conn.on_data = (data) => {
if(data.length !== 0) {
this.send_wisp_frame({
type: "DATA",
stream_id: tcp_conn.stream_id,
data: data
});
}
};
conn.on_data = (data) => {
if(data.length !== 0) {
this.send_wisp_frame({
type: "DATA",
stream_id: conn.stream_id,
data: data
});
}
};

tcp_conn.on_shutdown = () => {
this.send_wisp_frame({
type: "CLOSE",
stream_id: tcp_conn.stream_id,
reason: 0x02 // 0x02: Voluntary stream closure
});
};
conn.on_close = () => {
this.send_wisp_frame({
type: "CLOSE",
stream_id: conn.stream_id,
reason: 0x02 // 0x02: Voluntary stream closure
});
};

tcp_conn.on_close = () => {
this.send_wisp_frame({
type: "CLOSE",
stream_id: tcp_conn.stream_id,
reason: 0x02 // 0x02: Voluntary stream closure
});
};
// WISP doesn't implement shutdown, use close as workaround
conn.on_shutdown = conn.on_close;

this.send_wisp_frame({
type: "CONNECT",
stream_id: tcp_conn.stream_id,
hostname: packet.ipv4.dest.join("."),
port: packet.tcp.dport,
data_callback: (data) => {
tcp_conn.write(data);
},
close_callback: (data) => {
tcp_conn.close();
}
});
this.send_wisp_frame({
type: "CONNECT",
stream_id: conn.stream_id,
hostname: packet.ipv4.dest.join("."),
port: packet.tcp.dport,
data_callback: (data) => {
conn.write(data);
},
close_callback: (data) => {
conn.close();
}
});

tcp_conn.accept(packet);
return;
}
conn.accept(packet);
return true;
}

if(!this.tcp_conn[tuple]) {
dbg_log(`I dont know about ${tuple}, so restting`, LOG_FETCH);
let bop = packet.tcp.ackn;
if(packet.tcp.fin || packet.tcp.syn) bop += 1;
reply.tcp = {
sport: packet.tcp.dport,
dport: packet.tcp.sport,
seq: bop,
ackn: packet.tcp.seq + (packet.tcp.syn ? 1: 0),
winsize: packet.tcp.winsize,
rst: true,
ack: packet.tcp.syn
};
this.receive(make_packet(this.eth_encoder_buf, reply));
return;
}
/**
* @param {Uint8Array} data
*/
WispNetworkAdapter.prototype.send = function(data)
{
let packet = {};
parse_eth(data, packet);

this.tcp_conn[tuple].process(packet);
if(packet.ipv4) {
if(packet.tcp) {
handle_fake_tcp(packet, this);
}
else if(packet.udp) {
// TODO: remove when this wisp client supports udp
if(packet.dns) {
(async () => {
let reply = {};
reply.eth = { ethertype: ETHERTYPE_IPV4, src: this.router_mac, dest: packet.eth.src };
reply.ipv4 = {
proto: IPV4_PROTO_UDP,
src: this.router_ip,
dest: packet.ipv4.src,
const reply = {
eth: { ethertype: ETHERTYPE_IPV4, src: this.router_mac, dest: packet.eth.src },
ipv4: { proto: IPV4_PROTO_UDP, src: this.router_ip, dest: packet.ipv4.src },
udp: { sport: 53, dport: packet.udp.sport }
};
reply.udp = { sport: 53, dport: packet.udp.sport };
const result = await ((await fetch(`https://${this.doh_server}/dns-query`, {method: "POST", headers: [["content-type", "application/dns-message"]], body: packet.udp.data})).arrayBuffer());
const result = await (await fetch(`https://${this.doh_server}/dns-query`, {
method: "POST",
headers: [["content-type", "application/dns-message"]],
body: packet.udp.data})).arrayBuffer();
reply.udp.data = new Uint8Array(result);
this.receive(make_packet(this.eth_encoder_buf, reply));
})();
Expand Down

0 comments on commit a73e383

Please sign in to comment.