node-beaglebone-usbboot
Version:
Transforms BeagleBone to mass storage device
200 lines • 10.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const protocols_1 = require("./protocols");
const util_1 = require("./protocols/util");
const BOOTPS = 67;
const BOOTPC = 68;
const IP_UDP = 17;
const IPV6_HOP_BY_HOP_OPTION = 0;
const IPV6_ICMP = 0x3a;
const TFTP_PORT = 69;
const NETCONSOLE_UDP_PORT = 6666;
const MDNS_UDP_PORT = 5353;
const ETH_TYPE_ARP = 0x0806;
const ETH_TYPE_IPV4 = 0x0800;
const ETH_TYPE_IPV6 = 0x86dd;
// Size of all protocol headers
const RNDIS_SIZE = 44;
const ETHER_SIZE = 14;
const IPV4_SIZE = 20;
const IPV6_SIZE = 40;
const UDP_SIZE = 8;
const MAXBUF = 500;
const BOOTP_SIZE = 300;
const SERVER_IP = [0xc0, 0xa8, 0x01, 0x09]; // 192.168.1.9
const BB_IP = [0xc0, 0xa8, 0x01, 0x03]; // 192.168.1.3
const FULL_SIZE = 386;
const SERVER_NAME = [66, 69, 65, 71, 76, 69, 66, 79, 79, 84]; // ASCII ['B','E','A','G','L','E','B','O','O','T']
const ARP_SIZE = 28;
const TFTP_SIZE = 4;
class Message {
constructor() {
this.parser = new protocols_1.Parser();
this.encoder = new protocols_1.Encoder();
}
identify(buff) {
const parser = new protocols_1.Parser();
const ether = parser.parseEthHdr(buff.slice(RNDIS_SIZE));
if (ether.h_proto === ETH_TYPE_ARP) {
return 'ARP';
}
if (ether.h_proto === ETH_TYPE_IPV4) {
const ipv4 = parser.parseIpv4(buff.slice(RNDIS_SIZE + ETHER_SIZE));
if (ipv4.Protocol === 2) {
return 'IGMP';
}
if (ipv4.Protocol === IP_UDP) {
const udp = parser.parseUdp(buff.slice(RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE));
const sPort = udp.udpSrc;
const dPort = udp.udpDest;
if (sPort === BOOTPC && dPort === BOOTPS) {
return 'BOOTP';
} // Port 68: BOOTP Client, Port 67: BOOTP Server
if (dPort === TFTP_PORT) {
const opcode = buff[RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE + UDP_SIZE + 1];
if (opcode === 1) {
return 'TFTP';
} // Opcode = 1 for Read Request (RRQ)
if (opcode === 4) {
return 'TFTP_Data';
} // Opcode = 4 for Acknowledgement (ACK)
}
if (dPort === NETCONSOLE_UDP_PORT) {
return 'NC';
}
if (dPort === MDNS_UDP_PORT && sPort === MDNS_UDP_PORT) {
return 'mDNS';
}
}
}
if (ether.h_proto === ETH_TYPE_IPV6) {
const ipv6 = parser.parseIpv6(buff.slice(RNDIS_SIZE + ETHER_SIZE));
if (ipv6.NextHeader === IPV6_HOP_BY_HOP_OPTION) {
const ipv6Option = parser.parseIpv6Option(buff.slice(RNDIS_SIZE + ETHER_SIZE + IPV6_SIZE));
if (ipv6Option.NextHeader === IPV6_ICMP) {
return 'ICMPv6';
}
}
if (ipv6.NextHeader === IP_UDP) {
const udp = parser.parseUdp(buff.slice(RNDIS_SIZE + ETHER_SIZE + IPV6_SIZE));
if (udp.udpSrc === MDNS_UDP_PORT && udp.udpDest === MDNS_UDP_PORT) {
return 'mDNS';
}
}
}
return 'unidentified';
}
// Function to process BOOTP request
getBOOTPResponse(data, serverConfig) {
const etherBuf = Buffer.alloc(MAXBUF - RNDIS_SIZE);
const udpBuf = Buffer.alloc(UDP_SIZE);
const bootpBuf = Buffer.alloc(BOOTP_SIZE);
data.copy(udpBuf, 0, RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE, MAXBUF);
data.copy(bootpBuf, 0, RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE + UDP_SIZE, MAXBUF);
data.copy(etherBuf, 0, RNDIS_SIZE, MAXBUF);
serverConfig.ether = this.parser.parseEthHdr(etherBuf); // Gets decoded ether packet data
const udpUboot = this.parser.parseUdp(udpBuf); // parsed udp header
const bootp = this.parser.parseBOOTP(bootpBuf); // parsed bootp header
const rndis = this.encoder.makeRNDIS(FULL_SIZE - RNDIS_SIZE);
const eth2 = this.encoder.makeEther2(serverConfig.ether.h_source, serverConfig.ether.h_dest, ETH_TYPE_IPV4);
const ip = this.encoder.makeIPV4(SERVER_IP, BB_IP, IP_UDP, 0, IPV4_SIZE + UDP_SIZE + BOOTP_SIZE, 0);
const udp = this.encoder.makeUDP(BOOTP_SIZE, udpUboot.udpDest, udpUboot.udpSrc);
const bootreply = this.encoder.makeBOOTP(SERVER_NAME, serverConfig.bootpFile, bootp.xid, serverConfig.ether.h_source, BB_IP, SERVER_IP);
const bootPBuff = Buffer.concat([rndis, eth2, ip, udp, bootreply], FULL_SIZE);
const bootPServerConfig = serverConfig;
return { bootPBuff, bootPServerConfig };
}
// Function to process ARP request
getARResponse(data, serverConfig) {
const arpBuf = Buffer.alloc(ARP_SIZE);
data.copy(arpBuf, 0, RNDIS_SIZE + ETHER_SIZE, RNDIS_SIZE + ETHER_SIZE + ARP_SIZE);
serverConfig.receivedARP = this.parser.parseARP(arpBuf); // Parsed received ARP request
const arpResponse = this.encoder.makeARP(2, serverConfig.ether.h_dest, serverConfig.receivedARP.ip_dest, serverConfig.receivedARP.hw_source, serverConfig.receivedARP.ip_source);
const rndis = this.encoder.makeRNDIS(ETHER_SIZE + ARP_SIZE);
const eth2 = this.encoder.makeEther2(serverConfig.ether.h_source, serverConfig.ether.h_dest, ETH_TYPE_ARP);
const arpBuff = Buffer.concat([rndis, eth2, arpResponse], RNDIS_SIZE + ETHER_SIZE + ARP_SIZE);
const arpServerConfig = serverConfig;
return { arpBuff, arpServerConfig };
}
// Event to process TFTP request
getBootFile(data, serverConfig) {
const udpTFTPBuf = Buffer.alloc(UDP_SIZE);
data.copy(udpTFTPBuf, 0, RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE, RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE + UDP_SIZE);
serverConfig.tftp = {}; // Object containing TFTP parameters
serverConfig.tftp.i = 1; // Keeps count of File Blocks transferred
serverConfig.tftp.receivedUdp = this.parser.parseUdp(udpTFTPBuf); // Received UDP packet for SPL tftp
serverConfig.tftp.eth2 = this.encoder.makeEther2(serverConfig.ether.h_source, serverConfig.ether.h_dest, ETH_TYPE_IPV4); // Making ether header here, as it remains same for all tftp block transfers
const fileName = this.extractName(data);
const buff = util_1.safeReadFile(fileName);
if (buff !== undefined) {
serverConfig.tftp.blocks = Math.ceil((buff.length + 1) / 512); // Total number of blocks of file
serverConfig.tftp.start = 0;
serverConfig.tftp.fileData = buff;
serverConfig.tftp.fileError = false;
}
else {
serverConfig.tftp.fileError = true;
}
return serverConfig;
}
// Function to process File data for TFTP
getTFTPData(serverConfig) {
let blockSize = serverConfig.tftp.fileData.length - serverConfig.tftp.start;
if (blockSize > 512) {
blockSize = 512;
}
const blockData = Buffer.alloc(blockSize);
serverConfig.tftp.fileData.copy(blockData, 0, serverConfig.tftp.start, serverConfig.tftp.start + blockSize); // Copying data to block
serverConfig.tftp.start += blockSize; // Keep counts of bytes transferred upto
const rndis = this.encoder.makeRNDIS(ETHER_SIZE + IPV4_SIZE + UDP_SIZE + TFTP_SIZE + blockSize);
const ip = this.encoder.makeIPV4(serverConfig.receivedARP.ip_dest, serverConfig.receivedARP.ip_source, IP_UDP, 0, IPV4_SIZE + UDP_SIZE + TFTP_SIZE + blockSize, 0);
const udp = this.encoder.makeUDP(TFTP_SIZE + blockSize, serverConfig.tftp.receivedUdp.udpDest, serverConfig.tftp.receivedUdp.udpSrc);
const tftp = this.encoder.makeTFTP(3, serverConfig.tftp.i);
serverConfig.tftp.i++;
const tftpBuff = Buffer.concat([rndis, serverConfig.tftp.eth2, ip, udp, tftp, blockData], RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE + UDP_SIZE + TFTP_SIZE + blockSize);
const tftpServerConfig = serverConfig;
return { tftpBuff, tftpServerConfig };
}
// Function to handle TFTP error
getTFTPError(serverConfig) {
const errorMsg = 'File not found';
const rndis = this.encoder.makeRNDIS(ETHER_SIZE + IPV4_SIZE + UDP_SIZE + TFTP_SIZE + errorMsg.length + 1);
const ip = this.encoder.makeIPV4(serverConfig.receivedARP.ip_dest, serverConfig.receivedARP.ip_source, IP_UDP, 0, IPV4_SIZE + UDP_SIZE + TFTP_SIZE + errorMsg.length + 1, 0);
const udp = this.encoder.makeUDP(TFTP_SIZE + errorMsg.length + 1, serverConfig.tftp.receivedUdp.udpDest, serverConfig.tftp.receivedUdp.udpSrc);
const tftp = this.encoder.makeTFTPError(5, 1, errorMsg);
return Buffer.concat([rndis, serverConfig.tftp.eth2, ip, udp, tftp], RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE + UDP_SIZE + TFTP_SIZE + errorMsg.length + 1);
}
getRNDISInit() {
return this.encoder.makeRNDISInit();
}
getRNDISSet() {
return this.encoder.makeRNDISSet();
}
// Function to extract FileName from TFTP packet
extractName(data) {
const fv = RNDIS_SIZE + ETHER_SIZE + IPV4_SIZE + UDP_SIZE + 2;
let nameCount = 0;
let name = '';
while (data[fv + nameCount] !== 0) {
name += String.fromCharCode(data[fv + nameCount]);
nameCount++;
}
return name;
}
getFileBuffer(filename) {
return __awaiter(this, void 0, void 0, function* () {
const buffer = yield util_1.safeReadFile(filename);
return buffer;
});
}
}
exports.Message = Message;
//# sourceMappingURL=index.js.map