Skip to content

Commit

Permalink
Perform extra checks on CoAP message size
Browse files Browse the repository at this point in the history
This fixes the logic for checking the maximum CoAP message size. The
check is actually performed in the coap-packet repository in a default
parameter on the `generate()` function, however the default value is not
appropriate for all (if any) cases.

The maximum size that a CoAP message can be is the IP MTU, minus the IP
header and  minus the UDP header. The value is not constant across all
IP network stacks, so the CoAP specification recommends a maximum of 1152
bytes for cases where it is not known. The only way to know for sure is
MTU path discovery, which is way outside of the scope of the project.

This commit creates a parameter that allows the max packet size to be
adjusted as a server parameter for cases where (for example) the server
is running on a 6LoWPAN/Thread network and needs a lower maximum message
size.

Note that the logic for enforcing the size is just to throw an error and
crash the server. However, since the maximum payload size is enforced a
situation like that should never occur.
  • Loading branch information
edrose committed Dec 17, 2023
1 parent ec1c126 commit 0a11715
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 10 deletions.
7 changes: 7 additions & 0 deletions lib/parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ const NON_LIFETIME = 145
*/
const COAP_PORT = 5683

/**
* Maximum total size of the CoAP application layer message, as
* recommended by the CoAP specification
*/
const MAX_MESSAGE_SIZE = 1152

/**
* Default max payload size recommended in the CoAP specification
* For more info see RFC 7252 Section 4.6
Expand Down Expand Up @@ -178,6 +184,7 @@ const p: Parameters = {
nonLifetime: NON_LIFETIME,
coapPort: COAP_PORT,
maxPayloadSize: MAX_PAYLOAD_SIZE,
maxMessageSize: MAX_MESSAGE_SIZE,
sendAcksForNonConfirmablePackets,
piggybackReplyMs,
pruneTimerPeriod
Expand Down
20 changes: 11 additions & 9 deletions lib/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,13 @@ class CoAPServer extends EventEmitter {

// We use an LRU cache for the responses to avoid
// DDOS problems.
// max packet size is 1280
// 32 MB / 1280 = 26214
// The max lifetime is roughly 200s per packet.
// Which gave us 131 packets/second guarantee
let maxSize = 32768 * 1024
// total cache size is 32MiB
// max message size is 1152 bytes
// 32 MiB / 1152 = 29127 messages total

// The max lifetime is roughly 200s per message.
// Which gave us 145 messages/second guarantee
let maxSize = 32768 * 1024 // Maximum cache size is 32 MiB

if (typeof this._options.cacheSize === 'number' && this._options.cacheSize >= 0) {
maxSize = this._options.cacheSize
Expand Down Expand Up @@ -211,7 +213,7 @@ class CoAPServer extends EventEmitter {
payload,
messageId: packet != null ? packet.messageId : undefined,
token: packet != null ? packet.token : undefined
})
}, parameters.maxMessageSize)

if (this._sock instanceof Socket) {
this._sock.send(message, 0, message.length, rsinfo.port)
Expand All @@ -222,7 +224,7 @@ class CoAPServer extends EventEmitter {
const url = new URL(proxyUri)
const host = url.hostname
const port = parseInt(url.port)
const message = generate(removeProxyOptions(packet))
const message = generate(removeProxyOptions(packet), parameters.maxMessageSize)

if (this._sock instanceof Socket) {
this._sock.send(message, port, host, callback)
Expand All @@ -232,7 +234,7 @@ class CoAPServer extends EventEmitter {
_sendReverseProxied (packet: ParsedPacket, rsinfo: AddressInfo, callback?: (error: Error | null, bytes: number) => void): void {
const host = rsinfo.address
const port = rsinfo.port
const message = generate(packet)
const message = generate(packet, parameters.maxMessageSize)

if (this._sock instanceof Socket) {
this._sock.send(message, port, host, callback)
Expand Down Expand Up @@ -450,7 +452,7 @@ class CoAPServer extends EventEmitter {
const sender = new RetrySend(sock, rsinfo.port, rsinfo.address)

try {
buf = generate(packet)
buf = generate(packet, parameters.maxMessageSize)
} catch (err) {
response.emit('error', err)
return
Expand Down
2 changes: 2 additions & 0 deletions models/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface ParametersUpdate {
maxLatency?: number
piggybackReplyMs?: number
maxPayloadSize?: number
maxMessageSize?: number
sendAcksForNonConfirmablePackets?: boolean
pruneTimerPeriod?: number
}
Expand All @@ -70,6 +71,7 @@ export interface Parameters {
nonLifetime: number
coapPort: number
maxPayloadSize: number
maxMessageSize: number
sendAcksForNonConfirmablePackets: boolean
pruneTimerPeriod: number
maxTransmitSpan: number
Expand Down
2 changes: 1 addition & 1 deletion test/blockwise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('blockwise2', function () {
})
})

it('should use blockwise in response when payload bigger than max packet', function (done) {
it('should use blockwise in response when payload bigger than max payload', function (done) {
const payload = Buffer.alloc(1275) // 1275 produces a CoAP message (after headers) > 1280
request({
port
Expand Down

0 comments on commit 0a11715

Please sign in to comment.