Skip to content

Commit c6538e1

Browse files
committed
Add an insecure_disable_tls_host_verification command line option
When set, this disables the host verification of all HTTP requests. Available for both the fetch and serve mode. Also introduced an App.Config, for future command line options which need to be passed more deeply into the code.
1 parent 3a1a582 commit c6538e1

File tree

7 files changed

+81
-30
lines changed

7 files changed

+81
-30
lines changed

src/app.zig

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@ pub const App = struct {
1717
app_dir_path: ?[]const u8,
1818

1919
pub const RunMode = enum {
20-
serve,
20+
help,
2121
fetch,
22+
serve,
23+
version,
24+
};
25+
26+
pub const Config = struct {
27+
tls_verify_host: bool = true,
28+
run_mode: RunMode,
2229
};
2330

24-
pub fn init(allocator: Allocator, run_mode: RunMode) !*App {
31+
pub fn init(allocator: Allocator, config: Config) !*App {
2532
const app = try allocator.create(App);
2633
errdefer allocator.destroy(app);
2734

@@ -38,9 +45,11 @@ pub const App = struct {
3845
.allocator = allocator,
3946
.telemetry = undefined,
4047
.app_dir_path = app_dir_path,
41-
.http_client = try HttpClient.init(allocator, 5),
48+
.http_client = try HttpClient.init(allocator, 5, .{
49+
.tls_verify_host = config.tls_verify_host,
50+
}),
4251
};
43-
app.telemetry = Telemetry.init(app, run_mode);
52+
app.telemetry = Telemetry.init(app, config.run_mode);
4453

4554
return app;
4655
}

src/cdp/testing.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ const TestContext = struct {
281281

282282
pub fn context() TestContext {
283283
return .{
284-
.app = App.init(std.testing.allocator, .serve) catch unreachable,
284+
.app = App.init(std.testing.allocator, .{ .run_mode = .serve }) catch unreachable,
285285
.arena = std.heap.ArenaAllocator.init(std.testing.allocator),
286286
};
287287
}

src/http/client.zig

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,13 @@ pub const Client = struct {
4545
allocator: Allocator,
4646
state_pool: StatePool,
4747
root_ca: tls.config.CertBundle,
48+
tls_verify_host: bool = true,
4849

49-
// we only allow passing in a root_ca for testing
50-
pub fn init(allocator: Allocator, max_concurrent: usize) !Client {
50+
const Opts = struct {
51+
tls_verify_host: bool = true,
52+
};
53+
54+
pub fn init(allocator: Allocator, max_concurrent: usize, opts: Opts) !Client {
5155
var root_ca = try tls.config.CertBundle.fromSystem(allocator);
5256
errdefer root_ca.deinit(allocator);
5357

@@ -58,6 +62,7 @@ pub const Client = struct {
5862
.root_ca = root_ca,
5963
.allocator = allocator,
6064
.state_pool = state_pool,
65+
.tls_verify_host = opts.tls_verify_host,
6166
};
6267
}
6368

@@ -123,7 +128,7 @@ pub const Request = struct {
123128
_has_host_header: bool,
124129

125130
// Whether or not we should verify that the host matches the certificate CN
126-
_tls_verify_host: bool = true,
131+
_tls_verify_host: bool,
127132

128133
pub const Method = enum {
129134
GET,
@@ -167,6 +172,7 @@ pub const Request = struct {
167172
._client = client,
168173
._redirect_count = 0,
169174
._has_host_header = false,
175+
._tls_verify_host = client.tls_verify_host,
170176
};
171177
}
172178

@@ -205,11 +211,13 @@ pub const Request = struct {
205211

206212
// TODO timeout
207213
const SendSyncOpts = struct {
208-
tls_verify_host: bool = true,
214+
tls_verify_host: ?bool = null,
209215
};
210216
// Makes an synchronous request
211217
pub fn sendSync(self: *Request, opts: SendSyncOpts) anyerror!Response {
212-
self._tls_verify_host = opts.tls_verify_host;
218+
if (opts.tls_verify_host) |override| {
219+
self._tls_verify_host = override;
220+
}
213221
try self.prepareInitialSend();
214222
return self.doSendSync();
215223
}
@@ -230,11 +238,13 @@ pub const Request = struct {
230238
}
231239

232240
const SendAsyncOpts = struct {
233-
tls_verify_host: bool = true,
241+
tls_verify_host: ?bool = null,
234242
};
235243
// Makes an asynchronous request
236244
pub fn sendAsync(self: *Request, loop: anytype, handler: anytype, opts: SendAsyncOpts) !void {
237-
self._tls_verify_host = opts.tls_verify_host;
245+
if (opts.tls_verify_host) |override| {
246+
self._tls_verify_host = override;
247+
}
238248
try self.prepareInitialSend();
239249
return self.doSendAsync(loop, handler);
240250
}
@@ -2176,5 +2186,5 @@ fn testReader(state: *State, res: *TestResponse, data: []const u8) !void {
21762186
}
21772187

21782188
fn testClient() !Client {
2179-
return try Client.init(testing.allocator, 1);
2189+
return try Client.init(testing.allocator, 1, .{});
21802190
}

src/main.zig

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const Allocator = std.mem.Allocator;
2222

2323
const jsruntime = @import("jsruntime");
2424

25+
const App = @import("app.zig").App;
2526
const Browser = @import("browser/browser.zig").Browser;
2627
const server = @import("server.zig");
2728

@@ -69,9 +70,12 @@ pub fn main() !void {
6970
log.err("address (host:port) {any}\n", .{err});
7071
return args.printUsageAndExit(false);
7172
};
72-
73-
var app = try @import("app.zig").App.init(alloc, .serve);
73+
var app = try App.init(alloc, .{
74+
.run_mode = args.mode,
75+
.tls_verify_host = opts.tls_verify_host,
76+
});
7477
defer app.deinit();
78+
7579
app.telemetry.record(.{ .run = {} });
7680

7781
const timeout = std.time.ns_per_s * @as(u64, opts.timeout);
@@ -83,7 +87,10 @@ pub fn main() !void {
8387
.fetch => |opts| {
8488
log.debug("Fetch mode: url {s}, dump {any}", .{ opts.url, opts.dump });
8589

86-
var app = try @import("app.zig").App.init(alloc, .fetch);
90+
var app = try App.init(alloc, .{
91+
.run_mode = args.mode,
92+
.tls_verify_host = opts.tls_verify_host,
93+
});
8794
defer app.deinit();
8895
app.telemetry.record(.{ .run = {} });
8996

@@ -125,14 +132,7 @@ const Command = struct {
125132
mode: Mode,
126133
exec_name: []const u8,
127134

128-
const ModeType = enum {
129-
help,
130-
fetch,
131-
serve,
132-
version,
133-
};
134-
135-
const Mode = union(ModeType) {
135+
const Mode = union(App.RunMode) {
136136
help: bool, // false when being printed because of an error
137137
fetch: Fetch,
138138
serve: Serve,
@@ -143,11 +143,13 @@ const Command = struct {
143143
host: []const u8,
144144
port: u16,
145145
timeout: u16,
146+
tls_verify_host: bool,
146147
};
147148

148149
const Fetch = struct {
149150
url: []const u8,
150151
dump: bool = false,
152+
tls_verify_host: bool,
151153
};
152154

153155
fn printUsageAndExit(self: *const Command, success: bool) void {
@@ -164,6 +166,12 @@ const Command = struct {
164166
\\--dump Dumps document to stdout.
165167
\\ Defaults to false.
166168
\\
169+
\\--insecure_disable_tls_host_verification
170+
\\ Disables host verification on all HTTP requests.
171+
\\ This is an advanced option which should only be
172+
\\ set if you understand and accept the risk of
173+
\\ disabling host verification.
174+
\\
167175
\\serve command
168176
\\Starts a websocket CDP server
169177
\\Example: {s} serve --host 127.0.0.1 --port 9222
@@ -178,11 +186,18 @@ const Command = struct {
178186
\\--timeout Inactivity timeout in seconds before disconnecting clients
179187
\\ Defaults to 3 (seconds)
180188
\\
189+
\\--insecure_disable_tls_host_verification
190+
\\ Disables host verification on all HTTP requests.
191+
\\ This is an advanced option which should only be
192+
\\ set if you understand and accept the risk of
193+
\\ disabling host verification.
194+
\\
181195
\\version command
182196
\\Displays the version of {s}
183197
\\
184198
\\help command
185199
\\Displays this message
200+
\\
186201
;
187202
std.debug.print(usage, .{ self.exec_name, self.exec_name, self.exec_name, self.exec_name });
188203
if (success) {
@@ -204,7 +219,7 @@ fn parseArgs(allocator: Allocator) !Command {
204219
};
205220

206221
const mode_string = args.next() orelse "";
207-
const mode = std.meta.stringToEnum(Command.ModeType, mode_string) orelse blk: {
222+
const mode = std.meta.stringToEnum(App.RunMode, mode_string) orelse blk: {
208223
const inferred_mode = inferMode(mode_string) orelse return cmd;
209224
// "command" wasn't a command but an option. We can't reset args, but
210225
// we can create a new one. Not great, but this fallback is temporary
@@ -227,7 +242,7 @@ fn parseArgs(allocator: Allocator) !Command {
227242
return cmd;
228243
}
229244

230-
fn inferMode(opt: []const u8) ?Command.ModeType {
245+
fn inferMode(opt: []const u8) ?App.RunMode {
231246
if (opt.len == 0) {
232247
return .serve;
233248
}
@@ -260,6 +275,7 @@ fn parseServeArgs(
260275
var host: []const u8 = "127.0.0.1";
261276
var port: u16 = 9222;
262277
var timeout: u16 = 3;
278+
var tls_verify_host = true;
263279

264280
while (args.next()) |opt| {
265281
if (std.mem.eql(u8, "--host", opt)) {
@@ -297,6 +313,11 @@ fn parseServeArgs(
297313
continue;
298314
}
299315

316+
if (std.mem.eql(u8, "--insecure_tls_verify_host", opt)) {
317+
tls_verify_host = false;
318+
continue;
319+
}
320+
300321
log.err("Unknown option to serve command: '{s}'", .{opt});
301322
return error.UnkownOption;
302323
}
@@ -305,6 +326,7 @@ fn parseServeArgs(
305326
.host = host,
306327
.port = port,
307328
.timeout = timeout,
329+
.tls_verify_host = tls_verify_host,
308330
};
309331
}
310332

@@ -314,13 +336,19 @@ fn parseFetchArgs(
314336
) !Command.Fetch {
315337
var dump: bool = false;
316338
var url: ?[]const u8 = null;
339+
var tls_verify_host = true;
317340

318341
while (args.next()) |opt| {
319342
if (std.mem.eql(u8, "--dump", opt)) {
320343
dump = true;
321344
continue;
322345
}
323346

347+
if (std.mem.eql(u8, "--insecure_disable_tls_host_verification", opt)) {
348+
tls_verify_host = false;
349+
continue;
350+
}
351+
324352
if (std.mem.startsWith(u8, opt, "--")) {
325353
log.err("Unknown option to serve command: '{s}'", .{opt});
326354
return error.UnkownOption;
@@ -338,7 +366,11 @@ fn parseFetchArgs(
338366
return error.MissingURL;
339367
}
340368

341-
return .{ .url = url.?, .dump = dump };
369+
return .{
370+
.url = url.?,
371+
.dump = dump,
372+
.tls_verify_host = tls_verify_host,
373+
};
342374
}
343375

344376
var verbose: bool = builtin.mode == .Debug; // In debug mode, force verbose.

src/main_tests.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn testExecFn(
8888
std.debug.print("documentHTMLClose error: {s}\n", .{@errorName(err)});
8989
};
9090

91-
var http_client = try @import("http/client.zig").Client.init(alloc, 5);
91+
var http_client = try @import("http/client.zig").Client.init(alloc, 5, .{});
9292
defer http_client.deinit();
9393

9494
try js_env.setUserContext(.{

src/main_unit_tests.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ fn serveHTTPS(address: std.net.Address) !void {
213213

214214
fn serveCDP(address: std.net.Address) !void {
215215
const App = @import("app.zig").App;
216-
var app = try App.init(gpa.allocator(), .serve);
216+
var app = try App.init(gpa.allocator(), .{.run_mode = .serve});
217217
defer app.deinit();
218218

219219
const server = @import("server.zig");

src/testing.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {
157157

158158
// dummy opts incase we want to add something, and not have to break all the callers
159159
pub fn app(_: anytype) *App {
160-
return App.init(allocator, .serve) catch unreachable;
160+
return App.init(allocator, .{.run_mode = .serve}) catch unreachable;
161161
}
162162

163163
pub const Random = struct {

0 commit comments

Comments
 (0)