Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ expect-tests: build/v86-debug.wasm build/libwabt.cjs
make -C tests/expect/tests
./tests/expect/run.js

devices-test: build/v86-debug.wasm
devices-test: build/v86-debug.wasm build/mitm.mjs
./tests/devices/virtio_9p.js
./tests/devices/virtio_console.js
./tests/devices/fetch_network.js
Expand Down Expand Up @@ -380,6 +380,10 @@ build/capstone-x86.min.js:
mkdir -p build
wget -nv -P build https://github.com/AlexAltea/capstone.js/releases/download/v3.0.5-rc1/capstone-x86.min.js

build/mitm.mjs:
mkdir -p build
wget -nv -P build https://github.com/basicer/mitm.js/releases/download/latest/mitm.mjs

build/libwabt.cjs:
mkdir -p build
wget -nv -P build https://github.com/WebAssembly/wabt/archive/1.0.6.zip
Expand Down
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<meta name="description" content="Run KolibriOS, Linux or Windows 98 in your browser">

<script src="build/v86_all.js?98e7110c2"></script>
<script src="build/mitm.js"></script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this for preloading?

<link rel="stylesheet" href="v86.css">

<div>
Expand Down
39 changes: 28 additions & 11 deletions src/browser/fake_network.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,31 @@ function handle_fake_tcp(packet, adapter)
{
const tuple = `${packet.ipv4.src.join(".")}:${packet.tcp.sport}:${packet.ipv4.dest.join(".")}:${packet.tcp.dport}`;

if(packet.tcp.syn) {
if(packet.tcp.syn && !packet.tcp.ack) {
if(adapter.tcp_conn[tuple]) {
dbg_log("SYN to already opened port", LOG_FETCH);
delete adapter.tcp_conn[tuple];
}
if(adapter.on_tcp_connection(packet, tuple)) {
return;

let conn = new TCPConnection();
conn.state = TCP_STATE_SYN_RECEIVED;
conn.net = adapter;
conn.tuple = tuple;
conn.last = packet;

conn.hsrc = packet.eth.dest;
conn.psrc = packet.ipv4.dest;
conn.sport = packet.tcp.dport;
conn.hdest = packet.eth.src;
conn.dport = packet.tcp.sport;
conn.pdest = packet.ipv4.src;

adapter.bus.pair.send("tcp-connection", conn);

if(adapter.on_tcp_connection) {
adapter.on_tcp_connection(conn, packet);
}
if(adapter.tcp_conn[tuple]) return;
}

if(!adapter.tcp_conn[tuple]) {
Expand Down Expand Up @@ -1083,7 +1101,9 @@ TCPConnection.prototype.connect = function() {
this.ack = 1;
this.start_seq = 0;
this.winsize = 64240;
this.state = TCP_STATE_SYN_SENT;
if(this.state !== TCP_STATE_SYN_PROBE) {
this.state = TCP_STATE_SYN_SENT;
}

let reply = this.ipv4_reply();
reply.ipv4.id = 2345;
Expand All @@ -1099,16 +1119,12 @@ TCPConnection.prototype.connect = function() {
};


TCPConnection.prototype.accept = function(packet) {
TCPConnection.prototype.accept = function(packet=undefined) {
packet = packet || this.last;
this.net.tcp_conn[this.tuple] = this;
this.seq = 1338;
this.ack = packet.tcp.seq + 1;
this.start_seq = packet.tcp.seq;
this.hsrc = this.net.router_mac;
this.psrc = packet.ipv4.dest;
this.sport = packet.tcp.dport;
this.hdest = packet.eth.src;
this.dport = packet.tcp.sport;
this.pdest = packet.ipv4.src;
this.winsize = packet.tcp.winsize;

let reply = this.ipv4_reply();
Expand All @@ -1127,6 +1143,7 @@ TCPConnection.prototype.accept = function(packet) {
};

TCPConnection.prototype.process = function(packet) {
this.last = packet;
if(this.state === TCP_STATE_CLOSED) {
// dbg_log(`TCP[${this.tuple}]: WARNING: connection already closed, packet dropped`, LOG_FETCH);
const reply = this.packet_reply(packet, {rst: true});
Expand Down
77 changes: 59 additions & 18 deletions src/browser/fetch_network.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LOG_FETCH } from "../const.js";
import { h } from "../lib.js";
import { dbg_log } from "../log.js";

import {
Expand Down Expand Up @@ -36,6 +35,14 @@ export function FetchNetworkAdapter(bus, config)
this.eth_encoder_buf = create_eth_encoder_buf();
this.fetch = (...args) => fetch(...args);

eval(`import("../../build/mitm.mjs")`).then(factory => factory.default()).then(obj => {
this.tls = new obj["MITM"]();
this.tls["generateECCPrivateKey"]();
}).catch(e => {
console.log(e);
dbg_log("No TLS library detected.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing LOG_FETCH

});

// Ex: 'https://corsproxy.io/?'
this.cors_proxy = config.cors_proxy;

Expand All @@ -46,27 +53,22 @@ export function FetchNetworkAdapter(bus, config)
{
this.send(data);
}, this);
this.bus.register("tcp-connection", (conn) => {
if(conn.sport === 80) {
conn.on("data", on_data_http);
conn.accept();
}
if(conn.sport === 443 && this.tls) {
conn.on("data", on_data_tls.bind(conn, {net: this}));
conn.accept();
}
}, this);
}

FetchNetworkAdapter.prototype.destroy = function()
{
};

FetchNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
{
if(packet.tcp.dport === 80) {
let conn = new TCPConnection();
conn.state = TCP_STATE_SYN_RECEIVED;
conn.net = this;
conn.on("data", on_data_http);
conn.tuple = tuple;
conn.accept(packet);
this.tcp_conn[tuple] = conn;
return true;
}
return false;
};

FetchNetworkAdapter.prototype.connect = function(port)
{
return fake_tcp_connect(port, this);
Expand Down Expand Up @@ -104,6 +106,9 @@ async function on_data_http(data)
// fix "Mixed Content" errors
target.protocol = "https:";
}
else if(this.tls) {
target.protocol = "https:";
}

let req_headers = new Headers();
for(let i = 1; i < headers.length; ++i) {
Expand Down Expand Up @@ -144,7 +149,7 @@ async function on_data_http(data)
const fetch_url = this.net.cors_proxy ? this.net.cors_proxy + encodeURIComponent(target.href) : target.href;
const encoder = new TextEncoder();
let response_started = false;
this.net.fetch(fetch_url, opts).then((resp) => {
let handler = (resp) => {
let resp_headers = new Headers(resp.headers);
resp_headers.delete("content-encoding");
resp_headers.delete("keep-alive");
Expand Down Expand Up @@ -177,7 +182,13 @@ async function on_data_http(data)
this.close();
});
}
})
};

if(this.net.tls && /^https?:[/][/]mitm[.]it[/](ca|cert)[/.]pem/.test(target.href)) {
return handler(new Response(this.net.tls["getCACertificate"]()));
}

this.net.fetch(fetch_url, opts).then(handler)
.catch((e) => {
console.warn("Fetch Failed: " + fetch_url + "\n" + e);
if(!response_started) {
Expand All @@ -188,6 +199,36 @@ async function on_data_http(data)
}
}


async function on_data_tls(ctx, data)
{
let packet = this;
if(!ctx.tls) {
ctx.tls = packet.net.tls["ssl"]();
ctx.write = d => {
let r = ctx.tls["dataIn"](d);
};
ctx.writev = v => {
for(const data of v) {
let r = ctx.tls["dataIn"](data);
}
};
ctx.close = () => {
ctx.tls["close"]();
setTimeout(()=> packet.close(), 100);
};

ctx.tls["setPacketOutCallback"](d => {
let r = packet.write(d);
});

ctx.tls["setDataOutCallback"](d => {
on_data_http.call(ctx, d);
});
}
ctx.tls["packetIn"](data);
}

FetchNetworkAdapter.prototype.fetch = async function(url, options)
{
if(this.cors_proxy) url = this.cors_proxy + encodeURIComponent(url);
Expand Down
4 changes: 3 additions & 1 deletion src/browser/starter.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,11 @@ V86.prototype.continue_init = async function(emulator, options)
if(relay_url)
{
// TODO: remove bus, use direct calls instead
if(relay_url === "fetch")
if(relay_url.startsWith("fetch"))
{
this.network_adapter = new FetchNetworkAdapter(this.bus, options.net_device);
let parts = relay_url.split(";");
if(parts[1]) this.network_adapter.cors_proxy = parts[1];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
else if(relay_url === "inbrowser")
{
Expand Down
13 changes: 4 additions & 9 deletions src/browser/wisp_network.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,17 +185,12 @@ WispNetworkAdapter.prototype.destroy = function()
};

/**
* @param {TCPConnection} conn
* @param {Uint8Array} packet
* @param {String} tuple
*/
WispNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
WispNetworkAdapter.prototype.on_tcp_connection = function(conn, packet)
{
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;

conn.on("data", data => {
if(data.length !== 0) {
Expand All @@ -222,7 +217,7 @@ WispNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
type: "CONNECT",
stream_id: conn.stream_id,
hostname: packet.ipv4.dest.join("."),
port: packet.tcp.dport,
port: conn.sport,
data_callback: (data) => {
conn.write(data);
},
Expand All @@ -231,7 +226,7 @@ WispNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
}
});

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

Expand Down
6 changes: 2 additions & 4 deletions src/virtio_console.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,9 @@ export function VirtioConsole(cpu, bus)
{
dbg_assert(false, "VirtioConsole Notified for wrong queue: " + queue_id +
" (expected queue_id of 2)");
return;

}
const queue = this.virtio.queues[queue_id];
// Full buffer looks like an empty buffer so prevent it from filling
while(queue.count_requests() > queue.size - 2) queue.pop_request();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move this into its own commit and write a commit message that explains what gets fixed/changed here?


},
(queue_id) =>
{
Expand Down
17 changes: 15 additions & 2 deletions tests/devices/fetch_network.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,27 @@ if(isMainThread)
start: () =>
{
emulator.serial0_send("wget --header='testheader' -T 10 -O - test.domain\n");
emulator.serial0_send("echo -e done\\\\theader without colon\n");
emulator.serial0_send("echo -e done\\\\theader without separator\n");
},
end_trigger: "done\theader without colon",
end_trigger: "done\theader without separator",
end: (capture) =>
{
assert(/400 Bad Request/.test(capture), "got error 400");
},
},
{
name: "Fetch MITM cert",
start: () =>
{
emulator.serial0_send("curl http://mitm.it/cert.pem\n");
emulator.serial0_send("echo -e done\\\\tmitm cert\n");
},
end_trigger: "done\tmitm cert",
end: (capture) =>
{
assert(/BEGIN CERTIFICATE/.test(capture), "BEGIN CERTIFICATE");
},
},
];


Expand Down