netkitty
Version:
Network tools kit
152 lines (140 loc) • 6.01 kB
text/typescript
import {ProtocolJSONSchema} from '../../schema/ProtocolJSONSchema'
import {BaseHeader} from '../abstracts/BaseHeader'
import {BufferToUInt16, BufferToUInt8} from '../../helper/BufferToNumber'
import {UInt16ToBuffer, UInt8ToBuffer} from '../../helper/NumberToBuffer'
import {StringContentEncodingEnum} from '../lib/StringContentEncodingEnum'
import {BufferToHex} from '../../helper/BufferToHex'
export class ICMP extends BaseHeader {
/**
* Calculate ICMPv4 checksum
* @protected
*/
protected calculateIcmpChecksum(): number {
const icmpHeader: Buffer = Buffer.concat([
UInt8ToBuffer(this.instance.type.getValue(0)),
UInt8ToBuffer(this.instance.code.getValue(0)),
UInt16ToBuffer(this.instance.checksum.getValue(0)),
UInt16ToBuffer(this.instance.ident.getValue(0)),
UInt16ToBuffer(this.instance.seq.getValue(0)),
Buffer.from(this.instance.message.getValue(''), 'hex')
])
const paddedBuffer: Buffer = icmpHeader.length % 2 === 1 ?
Buffer.concat([
icmpHeader,
UInt8ToBuffer(0)
]) : icmpHeader
// 4. 计算 checksum
let checksum = 0
for (let i = 0; i < paddedBuffer.length; i += 2) {
const word = (paddedBuffer[i] << 8) | (paddedBuffer[i + 1] || 0)
checksum += word
// 处理溢出
if (checksum > 0xFFFF) {
checksum = (checksum & 0xFFFF) + 1
}
}
// 取反得到最终 checksum
return (~checksum) & 0xFFFF
}
public SCHEMA: ProtocolJSONSchema = {
type: 'object',
properties: {
type: {
type: 'integer',
label: 'Type',
minimum: 0,
maximum: 255,
decode: (): void => {
this.instance.type.setValue(BufferToUInt8(this.readBytes(0, 1)))
},
encode: (): void => {
const type: number = this.instance.type.getValue(0, (nodePath: string): void => this.recordError(nodePath, 'Not Found'))
this.instance.type.setValue(type)
this.writeBytes(0, UInt8ToBuffer(type))
}
},
code: {
type: 'integer',
label: 'Code',
minimum: 0,
maximum: 255,
decode: (): void => {
this.instance.code.setValue(BufferToUInt8(this.readBytes(1, 1)))
},
encode: (): void => {
const code: number = this.instance.code.getValue(0, (nodePath: string): void => this.recordError(nodePath, 'Not Found'))
this.instance.code.setValue(code)
this.writeBytes(1, UInt8ToBuffer(code))
}
},
checksum: {
type: 'integer',
label: 'Checksum',
minimum: 0,
maximum: 65535,
decode: (): void => {
this.instance.checksum.setValue(BufferToUInt16(this.readBytes(2, 2)))
},
encode: (): void => {
let checksum: number = this.instance.checksum.getValue(0)
this.instance.checksum.setValue(checksum)
this.writeBytes(2, UInt16ToBuffer(checksum))
if (!checksum) {
checksum = this.calculateIcmpChecksum()
this.instance.checksum.setValue(checksum)
this.writeBytes(2, UInt16ToBuffer(checksum))
}
}
},
ident: {
type: 'number',
label: 'Identifier (BE)',
minimum: 0,
maximum: 65535,
decode: (): void => {
this.instance.ident.setValue(BufferToUInt16(this.readBytes(4, 2)))
},
encode: (): void => {
const ident: number = this.instance.ident.getValue(0, (nodePath: string): void => this.recordError(nodePath, 'Not Found'))
this.instance.ident.setValue(ident)
this.writeBytes(4, UInt16ToBuffer(ident))
}
},
seq: {
type: 'number',
label: 'Sequence Number (BE)',
minimum: 0,
maximum: 65535,
decode: (): void => {
this.instance.seq.setValue(BufferToUInt16(this.readBytes(6, 2)))
},
encode: (): void => {
const seq: number = this.instance.seq.getValue(0, (nodePath: string): void => this.recordError(nodePath, 'Not Found'))
this.instance.seq.setValue(seq)
this.writeBytes(6, UInt16ToBuffer(seq))
}
},
message: {
type: 'string',
label: 'Message Body',
contentEncoding: StringContentEncodingEnum.HEX,
decode: (): void => {
const messageDataLength: number = this.packet.length - this.startPos - 8
this.instance.message.setValue(BufferToHex(this.readBytes(8, messageDataLength)))
},
encode: (): void => {
const messageHex: string = this.instance.message.getValue('')
this.instance.message.setValue(messageHex)
this.writeBytes(8, Buffer.from(messageHex, 'hex'))
}
}
}
}
public id: string = 'icmp'
public name: string = 'Internet Control Message Protocol'
public nickname: string = 'ICMP'
public match(): boolean {
if (!this.prevCodecModule) return false
return this.prevCodecModule.instance.protocol.getValue() === 0x01
}
}