Skip to content

Commit 7880a0e

Browse files
committed
DHCP client, options
1 parent 238800d commit 7880a0e

File tree

2 files changed

+201
-22
lines changed

2 files changed

+201
-22
lines changed

Protest/Front/dhcpdiscover.js

Lines changed: 187 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,124 @@
11
class DhcpDiscover extends Window {
2+
3+
static DEFAULT_OPTIONS = [0x01, 0x03, 0x04, 0x06, 0x0f, 0x1f, 0x21, 0x2a, 0x2b, 0x2c, 0x2e, 0x2f, 0x77, 0x79];
4+
5+
static OPTION_NAME = {
6+
1: "Subnet mask",
7+
2: "Time offset",
8+
3: "Router",
9+
4: "Time server",
10+
5: "Name server",
11+
6: "Domain server",
12+
7: "Log server",
13+
8: "Quotes server",
14+
9: "LPR server",
15+
10: "Impress server",
16+
11: "RLP server",
17+
12: "Hostname",
18+
13: "Boot file size",
19+
14: "Merit dump file",
20+
15: "Domain name",
21+
16: "Swap server",
22+
17: "Root Path",
23+
18: "Extension file",
24+
19: "Forward on/off",
25+
20: "SrcRte on/off",
26+
21: "Policy filter",
27+
22: "Max DG assembly",
28+
23: "Default IP TTL",
29+
24: "MTU timeout",
30+
25: "MTU plateau",
31+
26: "MTU interface",
32+
27: "MTU subnet",
33+
28: "Broadcast address",
34+
29: "Mask discovery",
35+
30: "Mask supplier",
36+
31: "Router discovery",
37+
32: "Router request",
38+
33: "Static route",
39+
34: "Trailers",
40+
35: "ARP timeout",
41+
36: "Ethernet",
42+
37: "Default TCP TTL",
43+
38: "Keepalive time",
44+
39: "Keepalive data",
45+
40: "NIS domain",
46+
41: "NIS servers",
47+
42: "NTP servers",
48+
43: "Vendor specific",
49+
44: "NetBIOS servers",
50+
45: "NetBIOS over TCP/IP servers",
51+
46: "NetBIOS node type",
52+
47: "NetBIOS scope ID",
53+
48: "X Window font",
54+
49: "X Window manager",
55+
50: "Address request",
56+
51: "Address time",
57+
52: "Overload",
58+
53: "DHCP message type",
59+
54: "DHCP server ID ",
60+
55: "Parameter list",
61+
56: "DHCP message",
62+
57: "DHCP max message size",
63+
58: "Renewal time",
64+
59: "Rebinding time",
65+
60: "Class ID",
66+
61: "Client ID",
67+
62: "NetWare/IP domain",
68+
63: "NetWare/IP option",
69+
64: "NIS+ domain name",
70+
65: "NIS+ servers",
71+
66: "Boot server",
72+
67: "Boot file",
73+
68: "Home agent IP",
74+
69: "SMTP servers",
75+
70: "POP3 servers",
76+
71: "NNTP servers",
77+
72: "WWW servers",
78+
73: "Finger servers",
79+
74: "IRC servers",
80+
75: "StreetTalk servers",
81+
76: "STDA servers",
82+
77: "User class",
83+
78: "Directory agent",
84+
79: "Service scope",
85+
80: "Rapid commit",
86+
81: "Client FQD",
87+
82: "Relay agent info",
88+
83: "iSNS",
89+
85: "NDS servers",
90+
86: "NDS tree name",
91+
87: "NDS context",
92+
88: "BCMCS domain name list",
93+
89: "BCMCS IPv4 address",
94+
90: "Authentication",
95+
91: "client last transaction time",
96+
92: "associated ip",
97+
93: "Client system",
98+
94: "Client NDI",
99+
95: "LDAP",
100+
97: "UUID/GUID",
101+
98: "User Auth",
102+
99: "GEOCONF CIVIC",
103+
100: "PCode",
104+
101: "TCode",
105+
108: "IPv6 only preferred",
106+
109: "OPTION_DHCP4O6_S46_SADDR",
107+
112: "Netinfo address",
108+
113: "Netinfo tag",
109+
114: "DHCP captive portal",
110+
116: "Auto config",
111+
117: "Name service search",
112+
118: "Subnet selection",
113+
119: "Domain search",
114+
120: "SIP servers DHCP",
115+
121: "Classless static route",
116+
122: "CCC",
117+
123: "GeoConf",
118+
124: "V-I vendor class",
119+
125: "V-I vendor specific info",
120+
};
121+
2122
constructor(args) {
3123
super();
4124
this.SetTitle("DHCP client");
@@ -8,7 +128,8 @@ class DhcpDiscover extends Window {
8128
timeout: 5000,
9129
hostname: "",
10130
mac: "",
11-
accept: false
131+
accept: false,
132+
options: DhcpDiscover.DEFAULT_OPTIONS
12133
};
13134

14135
this.hexRecord = [];
@@ -37,7 +158,6 @@ class DhcpDiscover extends Window {
37158
timeoutLabel.style.textAlign = "right";
38159
timeoutLabel.style.gridRow = "1";
39160
timeoutLabel.style.gridColumn = "2";
40-
grid.appendChild(timeoutLabel);
41161

42162
this.timeoutInput = document.createElement("input");
43163
this.timeoutInput.type = "number";
@@ -46,63 +166,65 @@ class DhcpDiscover extends Window {
46166
this.timeoutInput.value = this.args.timeout;
47167
this.timeoutInput.style.gridRow = "1";
48168
this.timeoutInput.style.gridColumn = "3";
49-
grid.appendChild(this.timeoutInput);
50-
169+
grid.append(timeoutLabel, this.timeoutInput);
51170

52171
const hostLabel = document.createElement("div");
53172
hostLabel.textContent = "Spoof hostname:";
54173
hostLabel.style.textAlign = "right";
55174
hostLabel.style.gridRow = "2";
56175
hostLabel.style.gridColumn = "2";
57-
grid.appendChild(hostLabel);
58176

59177
this.hostnameInput = document.createElement("input");
60178
this.hostnameInput.type = "text";
61179
this.hostnameInput.placeholder = "none";
62180
this.hostnameInput.value = this.args.hostname;
63181
this.hostnameInput.style.gridRow = "2";
64182
this.hostnameInput.style.gridColumn = "3";
65-
grid.appendChild(this.hostnameInput);
66-
183+
grid.append(hostLabel, this.hostnameInput);
67184

68185
const spoofMacLabel = document.createElement("div");
69186
spoofMacLabel.textContent = "Spoof MAC address:";
70187
spoofMacLabel.style.textAlign = "right";
71188
spoofMacLabel.style.gridRow = "3";
72189
spoofMacLabel.style.gridColumn = "2";
73-
grid.appendChild(spoofMacLabel);
74190

75191
this.macInput = document.createElement("input");
76192
this.macInput.type = "text";
77193
this.macInput.placeholder = "system default";
78194
this.macInput.value = this.args.mac;
79195
this.macInput.style.gridRow = "3";
80196
this.macInput.style.gridColumn = "3";
81-
grid.appendChild(this.macInput);
197+
grid.append(spoofMacLabel, this.macInput);
82198

83199
const acceptLabel = document.createElement("div");
84200
acceptLabel.textContent = "Accept the offer:";
85201
acceptLabel.style.textAlign = "right";
86202
acceptLabel.style.gridRow = "4";
87203
acceptLabel.style.gridColumn = "2";
88-
grid.appendChild(acceptLabel);
89-
204+
90205
const acceptBox = document.createElement("div");
91206
acceptBox.style.gridRow = "4";
92207
acceptBox.style.gridColumn = "3";
93-
grid.appendChild(acceptBox);
208+
grid.append(acceptLabel, acceptBox);
94209

95210
this.acceptToggle = this.CreateToggle(".", this.args.accept, acceptBox);
96211
this.acceptToggle.label.style.paddingLeft = "8px";
97212

213+
this.optionsButton = document.createElement("input");
214+
this.optionsButton.type = "button";
215+
this.optionsButton.value = "Options";
216+
this.optionsButton.style.width = "96px";
217+
this.optionsButton.style.margin = "0 16px";
218+
this.optionsButton.style.gridArea = "1 / 4";
219+
grid.appendChild(this.optionsButton);
220+
98221
this.discoverButton = document.createElement("input");
99222
this.discoverButton.type = "button";
100223
this.discoverButton.value = "Discover";
101224
this.discoverButton.style.display = "block-line";
102225
this.discoverButton.style.width = "96px";
103226
this.discoverButton.style.height = "48px";
104227
this.discoverButton.style.margin = "16px";
105-
this.discoverButton.style.borderRadius = "4px";
106228
this.discoverButton.style.gridArea = "2 / 4 / span 2 / span 1";
107229
grid.appendChild(this.discoverButton);
108230

@@ -114,7 +236,6 @@ class DhcpDiscover extends Window {
114236
this.content.appendChild(this.spinner);
115237
this.spinner.appendChild(document.createElement("div"));
116238

117-
118239
this.hexButton = document.createElement("input");
119240
this.hexButton.type = "button";
120241
this.hexButton.value = "";
@@ -133,7 +254,6 @@ class DhcpDiscover extends Window {
133254
this.hexButton.style.backgroundRepeat = "no-repeat";
134255
this.content.appendChild(this.hexButton);
135256

136-
137257
const titleBar = document.createElement("div");
138258
titleBar.style.height = "25px";
139259
titleBar.style.borderRadius = "4px 4px 0 0";
@@ -187,6 +307,8 @@ class DhcpDiscover extends Window {
187307
this.result.style.userSelect = "text";
188308
this.content.appendChild(this.result);
189309

310+
this.optionsButton.onclick = ()=> this.OptionsDialog();
311+
190312
this.timeoutInput.onchange = ()=> {
191313
this.args.timeout = this.timeoutInput.value;
192314
};
@@ -235,7 +357,7 @@ class DhcpDiscover extends Window {
235357

236358
this.ws = new WebSocket((KEEP.isSecure ? "wss://" : "ws://") + server + "/ws/dhcp");
237359

238-
this.ws.onopen = ()=> this.ws.send(`timeout=${this.timeoutInput.value}&mac=${mac}&hostname=${this.hostnameInput.value}&accept=${this.acceptToggle.checkbox.checked}`);
360+
this.ws.onopen = ()=> this.ws.send(`timeout=${this.timeoutInput.value}&mac=${mac}&hostname=${this.hostnameInput.value}&accept=${this.acceptToggle.checkbox.checked}&options=${this.args.options.join(";")}`);
239361

240362
this.ws.onmessage = event=> {
241363
const json = JSON.parse(event.data);
@@ -311,4 +433,53 @@ class DhcpDiscover extends Window {
311433
this.ConfirmBox("Server is unreachable", true);
312434
};
313435
}
436+
437+
OptionsDialog() {
438+
const dialog = this.DialogBox("400px");
439+
if (dialog === null) return;
440+
441+
dialog.innerBox.parentElement.style.maxWidth = "400px";
442+
443+
dialog.innerBox.style.margin = "20px";
444+
dialog.innerBox.style.overflowY = "auto";
445+
446+
const options = {};
447+
for (let i=1; i<255; i++) {
448+
const element = document.createElement("div");
449+
element.style.paddingBottom = "4px";
450+
dialog.innerBox.appendChild(element);
451+
452+
const checked = this.args.options.includes(i);
453+
const name = DhcpDiscover.OPTION_NAME[i];
454+
options[i] = checked;
455+
456+
const toggle = this.CreateToggle(`${i} ${(name ? `: ${name}` : "")}`, checked, element);
457+
toggle.label.style.width = "calc(100% - 48px)";
458+
459+
toggle.checkbox.onchange = ()=> {
460+
options[i] = toggle.checkbox.checked;
461+
};
462+
}
463+
464+
const resetButton = document.createElement("input");
465+
resetButton.type = "button";
466+
resetButton.value = "Reset";
467+
resetButton.style.marginLeft = "20px";
468+
dialog.buttonBox.appendChild(resetButton);
469+
470+
dialog.okButton.onclick = ()=> {
471+
const filtered = [];
472+
for (const key in options) {
473+
if (options[key]) filtered.push(parseInt(key));
474+
}
475+
this.args.options = filtered;
476+
dialog.Close();
477+
};
478+
479+
resetButton.onclick = ()=> {
480+
this.args.options = DhcpDiscover.DEFAULT_OPTIONS;
481+
dialog.Close();
482+
};
483+
484+
}
314485
}

Protest/Protocols/Dhcp.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Threading;
77
using System.Threading.Tasks;
88
using Protest.Http;
9+
using System.Collections.Generic;
910

1011
namespace Protest.Protocols;
1112

@@ -39,6 +40,7 @@ public static async void WebSocketHandler(HttpListenerContext ctx) {
3940
int timeout = 5000;
4041
string mac = String.Empty;
4142
string hostname = String.Empty;
43+
byte[] options = null;
4244
bool accept = false;
4345

4446
string[] attributes = Encoding.Default.GetString(buff, 0, receiveResult.Count).Trim().Split('&');
@@ -55,6 +57,12 @@ public static async void WebSocketHandler(HttpListenerContext ctx) {
5557
else if (attributes[i].StartsWith("accept=")) {
5658
accept = Uri.UnescapeDataString(attributes[i][7..].ToString()) == "true";
5759
}
60+
else if (attributes[i].StartsWith("options=")) {
61+
options = attributes[i][8..]
62+
.Split(';')
63+
.Select(o => byte.TryParse(o, out byte v) ? v : (byte)0)
64+
.ToArray();
65+
}
5866
}
5967

6068
if (mac.Length == 0) {
@@ -65,7 +73,7 @@ public static async void WebSocketHandler(HttpListenerContext ctx) {
6573
}
6674

6775
try {
68-
Dhcp4wayHandshake(ws, mac, hostname, timeout, accept);
76+
Dhcp4wayHandshake(ws, mac, hostname, options, timeout, accept);
6977
}
7078
catch (Exception ex) {
7179
string error = $"{{\"error\":\"{Data.EscapeJsonText(ex.Message)}\"}}";
@@ -77,7 +85,7 @@ public static async void WebSocketHandler(HttpListenerContext ctx) {
7785
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
7886
}
7987

80-
public static void Dhcp4wayHandshake(WebSocket ws, string mac, string hostname, int timeout, bool accept = false) {
88+
public static void Dhcp4wayHandshake(WebSocket ws, string mac, string hostname, byte[] options, int timeout, bool accept = false) {
8189
IPEndPoint remote = new IPEndPoint(IPAddress.Broadcast, 67);
8290
IPEndPoint local = new IPEndPoint(IPAddress.Any, 68);
8391

@@ -100,7 +108,7 @@ public static void Dhcp4wayHandshake(WebSocket ws, string mac, string hostname,
100108
}
101109

102110
long timestamp = DateTime.Now.Ticks;
103-
byte[] discover = Discover(timestamp, mac, hostname, transactionId, Array.Empty<byte>());
111+
byte[] discover = Discover(timestamp, mac, hostname, transactionId, options);
104112

105113
SendMessage(ws, discover, discover.Length, 1, id, id, mac, NULL_IP, NULL_IP);
106114

@@ -124,7 +132,7 @@ public static void Dhcp4wayHandshake(WebSocket ws, string mac, string hostname,
124132
SendMessage(ws, reply, length, type, id, replyId, mac, server, ip);
125133

126134
if (type == 0x02 && accept) { //offer
127-
byte[] request = Request(timestamp, transactionId, mac, hostname, ip, server, Array.Empty<byte>());
135+
byte[] request = Request(timestamp, transactionId, mac, hostname, ip, server, options);
128136
socket.SendTo(request, remote);
129137
SendMessage(ws, request, request.Length, 3, id, id, mac, server, ip);
130138
}
@@ -326,7 +334,7 @@ private static byte[] Discover(long timestamp, string mac, string hostname, byte
326334

327335
//index: 252
328336

329-
if (options.Length == 0) {
337+
if (options is null) {
330338
buffer[index++] = 0x37; //opt: request list
331339
buffer[index++] = 0x0e; //length
332340
buffer[index++] = 0x01; //subnet mask
@@ -490,7 +498,7 @@ private static byte[] Request(long timestamp, byte[] transactionId, string mac,
490498

491499
//index: 264
492500

493-
if (options.Length == 0) {
501+
if (options is null) {
494502
buffer[index++] = 0x37; //opt: request list
495503
buffer[index++] = 0x0e; //length
496504
buffer[index++] = 0x01; //subnet mask

0 commit comments

Comments
 (0)