Skip to content

Commit 18f4fa8

Browse files
committed
feat(new tool): Option 43 DHCP Generator
Option 43 DHCP Generator Fix CorentinTh#907
1 parent d3b32cc commit 18f4fa8

File tree

5 files changed

+355
-1
lines changed

5 files changed

+355
-1
lines changed

src/tools/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { tool as asciiTextDrawer } from './ascii-text-drawer';
66

77
import { tool as textToUnicode } from './text-to-unicode';
88
import { tool as safelinkDecoder } from './safelink-decoder';
9+
import { tool as option43Generator } from './option43-generator';
910
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
1011
import { tool as numeronymGenerator } from './numeronym-generator';
1112
import { tool as macAddressGenerator } from './mac-address-generator';
@@ -152,7 +153,15 @@ export const toolsByCategory: ToolCategory[] = [
152153
},
153154
{
154155
name: 'Network',
155-
components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
156+
components: [
157+
ipv4SubnetCalculator,
158+
ipv4AddressConverter,
159+
ipv4RangeExpander,
160+
macAddressLookup,
161+
macAddressGenerator,
162+
ipv6UlaGenerator,
163+
option43Generator,
164+
],
156165
},
157166
{
158167
name: 'Math',

src/tools/option43-generator/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { RouterOutlined } from '@vicons/material';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'Option43 generator',
6+
path: '/option43-generator',
7+
description: 'Generate Option43 Wifi DHCP configuration',
8+
keywords: ['option43', 'wifi', 'dhcp', 'generator'],
9+
component: () => import('./option43-generator.vue'),
10+
icon: RouterOutlined,
11+
createdAt: new Date('2024-03-09'),
12+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// import { } from './option43-generator.service';
2+
//
3+
// describe('option43-generator', () => {
4+
//
5+
// })
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
// from option43.org
2+
3+
function IPToHexDigit(ip_addr: string) { // Ruckus
4+
const arr1 = [];
5+
// ip_addr = ip_addr.split('.').join('');
6+
for (let n = 0, l = ip_addr.length; n < l; n++) {
7+
const hex = Number(ip_addr.charCodeAt(n)).toString(16);
8+
arr1.push(hex);
9+
}
10+
return arr1.join('');
11+
}
12+
13+
function IPToHexNumber(ip_addr: string) {
14+
const arr1 = [];
15+
const ips = ip_addr.split('.');
16+
for (let n = 0, l = ips.length; n < l; n++) {
17+
const hex = (`0${Number(ips[n]).toString(16)}`).slice(-2);
18+
arr1.push(hex);
19+
}
20+
return arr1.join('');
21+
}
22+
23+
function IPCharCounter(ip_addr: string, ret: string) {
24+
if (ret === 'hex') {
25+
return (`0${ip_addr.length.toString(16)}`).slice(-2);
26+
}
27+
else {
28+
return ip_addr.length;
29+
}
30+
}
31+
32+
function splitIPs(ip_addr: string) {
33+
const validIPs = [];
34+
const rows = ip_addr.split('\n');
35+
for (let n = 0, l = rows.length; n < l; n++) {
36+
if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(rows[n])) {
37+
validIPs.push(rows[n]);
38+
}
39+
}
40+
return validIPs;
41+
}
42+
43+
function IPNumberCounter(ip_addr: string[]) {
44+
return ip_addr.length;
45+
}
46+
47+
function renderSettings(
48+
dhcp_vendor: string,
49+
option43_type: string,
50+
option43_subtype: string,
51+
option43_value: string,
52+
option60_type: string | undefined,
53+
option60_value: string | undefined,
54+
vendor_link: string | undefined,
55+
diff_number: number | undefined) {
56+
let output;
57+
switch (dhcp_vendor) {
58+
case 'cisco_01':
59+
// option code [instance number] {ascii string | hex string | ip-address} // no quotation marks in option 43!
60+
output = '<p>Cisco CLI commands:</p><div class="cli"><p>option ';
61+
if (typeof diff_number !== 'undefined') {
62+
output = output + diff_number;
63+
}
64+
else { output = `${output}43`; }
65+
output = `${output} ${option43_type}`;
66+
output = `${output} ${option43_subtype}${option43_value}`;
67+
if (typeof option60_value !== 'undefined') {
68+
output = `${output}</p><p>option 60 ascii "${option60_value}"`;
69+
}
70+
output = `${output}</p></div><!--<p>More information: ${vendor_link}</p>-->`;
71+
return output;
72+
case 'juniper_01':
73+
// https://www.juniper.net/documentation/en_US/junos/topics/topic-map/dhcp-serever-options.html#id-configure-user-defined-dhcp-options
74+
75+
output = '<p>Juniper EX CLI commands:</p><div class="cli"><p>set system services dhcp option ';
76+
if (typeof diff_number !== 'undefined') {
77+
output = output + diff_number;
78+
}
79+
else { output = `${output}43`; }
80+
if (option43_type === 'ascii') {
81+
option43_type = 'string';
82+
}
83+
if (option60_type === 'ascii') {
84+
option60_type = 'string';
85+
}
86+
output = `${output} ${option43_type}`;
87+
output = `${output} ${option43_subtype}${option43_value}`;
88+
if (typeof option60_value !== 'undefined') {
89+
output = `${output}</p><p>set system services dhcp option 60 ascii "${option60_value}"`;
90+
}
91+
output = `${output}</p></div>`;
92+
return output;
93+
case 'juniper_02':
94+
// https://www.juniper.net/documentation/en_US/junos/topics/topic-map/dhcp-serever-options.html#id-configure-user-defined-dhcp-options
95+
96+
output = '<p>Juniper SRX CLI commands:</p><div class="cli"><p>set access address-assignment pool <i>AP_DHCP_POOL</i> family inet dhcp-attributes option ';
97+
if (typeof diff_number !== 'undefined') {
98+
output = output + diff_number;
99+
}
100+
else { output = `${output}43`; }
101+
if (option43_type === 'ascii') {
102+
option43_type = 'string';
103+
}
104+
if (option43_type === 'hex') {
105+
option43_type = 'byte-stream';
106+
}
107+
output = `${output} ${option43_type}`;
108+
if (option43_type === 'byte-stream') {
109+
output = `${output} "0x${(option43_subtype + option43_value).match(/.{1,2}/g)?.join(' 0x')}"`;
110+
}
111+
else {
112+
output = `${output} ${option43_subtype}${option43_value}`;
113+
}
114+
if (option60_type === 'ascii') {
115+
option60_type = 'string';
116+
}
117+
if (typeof option60_value !== 'undefined') {
118+
output = `${output}</p><p>set access address-assignment pool <i>AP_DHCP_POOL</i> family inet dhcp-attributes option 60 ascii "${option60_value}"`;
119+
}
120+
output = `${output}</p></div>`;
121+
return output;
122+
default:
123+
output = '<p>Raw values:</p><p><b>Option ';
124+
if (typeof diff_number !== 'undefined') {
125+
output = output + diff_number;
126+
}
127+
else {
128+
output = `${output}43`;
129+
}
130+
output = `${output}</b><br />Type: "`;
131+
if (option43_type === 'ascii') {
132+
option43_type = 'String/ASCII';
133+
}
134+
if (option43_type === 'hex') {
135+
option43_type = 'Hexadecimal';
136+
}
137+
if (option43_type === 'ip') {
138+
option43_type = 'IP-Address';
139+
}
140+
if (option60_type === 'ascii') {
141+
option60_type = 'String/ASCII';
142+
}
143+
output = output + option43_type;
144+
output = `${output}"<br />Value: ${option43_subtype}${option43_value}`;
145+
if (typeof option60_value !== 'undefined') {
146+
output = `${output}</p><p><b>Option 60</b><br /> Type: "${option60_type}"<br />Value: "${option60_value}"`;
147+
}
148+
output = `${output}</p></div>`;
149+
return output;
150+
}
151+
}
152+
153+
export function getOption43Infos(ip_addr: string, wifi_vendor: string, dhcp_vendor: string) {
154+
const ip_addr_array = splitIPs(ip_addr);
155+
const ip_addr_hexDigit = IPToHexDigit (ip_addr_array.join(',')); // Ruckus, comma separation
156+
const ip_addr_hexNumber = IPToHexNumber (ip_addr_array.join('.')); // valid for Cisco, no separation
157+
const ip_addr_hexNumber_first = IPToHexNumber (ip_addr_array[0]);
158+
159+
const num_ips = IPNumberCounter (ip_addr_array);
160+
const num_ip_bytes = (`0${(num_ips * 4).toString(16)}`).slice(-2);
161+
162+
let option43_type = ''; // hex, ascii, ip
163+
let option43_subtype = ''; // vendor prefix
164+
let option43_value;
165+
let diff_number;
166+
let option60_type; // hex, ascii, ip
167+
let option60_value;
168+
let vendor_link;
169+
170+
switch (wifi_vendor) {
171+
case 'cisco_01':
172+
option43_type = 'hex';
173+
option43_subtype = 'f1';
174+
option43_value = num_ip_bytes + ip_addr_hexNumber;
175+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
176+
case 'ruckus_01':
177+
option43_type = 'hex';
178+
option43_subtype = '06';
179+
option43_value = IPCharCounter (ip_addr_array.join(','), 'hex') + ip_addr_hexDigit;
180+
option60_type = 'ascii';
181+
option60_value = 'Ruckus CPE';
182+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
183+
case 'ruckus_02':
184+
option43_type = 'hex';
185+
option43_subtype = '03';
186+
option43_value = IPCharCounter (ip_addr_array.join(','), 'hex') + ip_addr_hexDigit;
187+
option60_type = 'ascii';
188+
option60_value = 'Ruckus CPE';
189+
vendor_link = 'https://docs.commscope.com/bundle/zd-10.2-userguide/page/GUID-D5CF7FE0-D73F-4B4B-95C8-08CAB5B235D5.html';
190+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
191+
case 'aruba_01':
192+
option43_type = 'ip';
193+
option43_value = ip_addr;
194+
option60_type = 'ascii';
195+
option60_value = 'ArubaAP';
196+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
197+
case 'fortinet_01':
198+
option43_type = 'ip';
199+
option43_value = ip_addr_array.join(' ');
200+
// diff_number = 138;
201+
// option60_type = "ascii";
202+
// option60_value = "ArubaAP";
203+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
204+
case 'fortinet_02':
205+
option43_type = 'ip';
206+
option43_value = ip_addr_array.join(' ');
207+
diff_number = 138;
208+
// option60_type = "ascii";
209+
// option60_value = "ArubaAP";
210+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
211+
case 'ubiquiti_01':
212+
option43_type = 'hex';
213+
option43_subtype = '01';
214+
option43_value = `04${ip_addr_hexNumber_first}`;
215+
// option60_type = "ascii";
216+
// option60_value = "Ruckus CPE";
217+
// vendor_link = "https://docs.commscope.com/bundle/zd-10.2-userguide/page/GUID-D5CF7FE0-D73F-4B4B-95C8-08CAB5B235D5.html";
218+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
219+
case 'cambium_01':
220+
option43_type = 'ascii';
221+
// option43_subtype = "01";
222+
option43_value = `"https://${ip_addr[0]}"`;
223+
// option60_type = "ascii";
224+
// option60_value = "Ruckus CPE";
225+
// vendor_link = "https://docs.commscope.com/bundle/zd-10.2-userguide/page/GUID-D5CF7FE0-D73F-4B4B-95C8-08CAB5B235D5.html";
226+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
227+
case 'linux_01':
228+
return `Linux:<br />Option 43 (IP-address): ${ip_addr}<br /> You also <b>need</b>:<br />Option 60 (String): "ArubaAP".`;
229+
case 'netgear_01':
230+
option43_type = 'hex';
231+
option43_subtype = '0204';
232+
option43_value = ip_addr_hexNumber_first;
233+
return renderSettings(dhcp_vendor, option43_type, option43_subtype, option43_value, option60_type, option60_value, vendor_link, diff_number);
234+
default:
235+
return 'Not implemented';
236+
}
237+
};
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<script setup lang="ts">
2+
import { useStorage } from '@vueuse/core';
3+
import { getOption43Infos } from './option43-generator.service';
4+
5+
const dhcpVendorOptions = [
6+
{ value: 'genuine', label: 'Native' },
7+
{ value: 'cisco_01', label: 'Cisco IOS device' },
8+
{ value: 'juniper_01', label: 'Juniper EX device' },
9+
{ value: 'juniper_02', label: 'Juniper SRX device' },
10+
{ value: 'linux_01', label: 'Linux DHCPD' },
11+
{ value: 'ruckus_01', label: 'Ruckus SmartCellGateway' },
12+
{ value: 'lancom_01', label: 'Lancom' },
13+
{ value: 'fortinet_01', label: 'Fortinet' },
14+
];
15+
const wifiVendorOptions = [
16+
{ value: 'cisco_01', label: 'Cisco Aironet' },
17+
{ value: 'aruba_01', label: 'Aruba' },
18+
{ value: 'ruckus_01', label: 'Ruckus SmartZone' },
19+
{ value: 'ruckus_02', label: 'Ruckus ZoneDirector' },
20+
{ value: 'ruckus_01', label: 'Ruckus SmartCellGateway' },
21+
{ value: 'ubiquiti_01', label: 'Ubiquiti' },
22+
{ value: 'fortinet_01', label: 'Fortinet (old)' },
23+
{ value: 'fortinet_02', label: 'Fortinet (new/CAPWAP)' },
24+
{ value: 'netgear_01', label: 'Netgear' },
25+
{ value: 'cambium_01', label: 'Cambium cnMaestro' },
26+
];
27+
28+
const dhcpVendor = useStorage('option43-generator:dhcp', 'genuine');
29+
const wifiVendor = useStorage('option43-generator:wifi', 'cisco_01');
30+
const ipAdresses = ref('192.168.0.15');
31+
32+
const option43Infos = computed(() => getOption43Infos(ipAdresses.value, wifiVendor.value, dhcpVendor.value));
33+
</script>
34+
35+
<template>
36+
<div style="margin: 0 auto; max-width: 600px">
37+
<c-card>
38+
<c-select
39+
v-model:value="wifiVendor"
40+
label="Wifi Vendor:"
41+
label-position="left"
42+
label-width="120px"
43+
label-align="right"
44+
mb-2
45+
:options="wifiVendorOptions"
46+
w-full
47+
placeholder="Select a Wifi Vendor"
48+
/>
49+
50+
<c-select
51+
v-model:value="dhcpVendor"
52+
label="DHCP Vendor:"
53+
label-position="left"
54+
label-width="120px"
55+
label-align="right"
56+
mb-2
57+
:options="dhcpVendorOptions"
58+
w-full
59+
placeholder="Select a DHCP Vendor"
60+
/>
61+
62+
<c-input-text
63+
v-model:value="ipAdresses"
64+
label="IP Address(es) (one per line):"
65+
label-position="left"
66+
label-width="120px"
67+
label-align="right"
68+
multiline mb-2
69+
placeholder="Enter your IP Addresses (one per line)"
70+
/>
71+
</c-card>
72+
73+
<c-card title="Option 43 Result">
74+
<div v-html="option43Infos" />
75+
</c-card>
76+
</div>
77+
</template>
78+
79+
<style lang="less">
80+
.highlight {
81+
color: orange;
82+
font-variant: small-caps;
83+
}
84+
.cli {
85+
background-color: black;
86+
color: #adfc03;
87+
font-family: monospace;
88+
padding: 10px;
89+
font-size: 13px;
90+
}
91+
</style>

0 commit comments

Comments
 (0)