Skip to content
This repository was archived by the owner on Jul 3, 2020. It is now read-only.

Commit 8048564

Browse files
committed
ip4: limit max number of fragment queues and add timeouts
1 parent e33a8f8 commit 8048564

File tree

5 files changed

+111
-0
lines changed

5 files changed

+111
-0
lines changed

js/core/net/interfaces.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ exports.getByName = function(intfName) {
3333

3434
return null;
3535
};
36+
37+
exports.forEach = function(fn) {
38+
intfs.forEach(fn);
39+
};

js/core/net/ip4-fragments.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
var ip4header = require('./ip4-header');
1818
var ip4receive = require('./ip4-receive');
19+
var timeNow = require('../../utils').timeNow;
20+
var FRAGMENT_QUEUE_MAX_AGE_MS = 30000;
21+
var FRAGMENT_QUEUE_MAX_COUNT = 100;
1922

2023
function fragmentHash(srcIP, destIP, protocolId, packetId) {
2124
return srcIP.toInteger() + '-' + destIP.toInteger() + '-' + (packetId + (protocolId << 16));
@@ -38,10 +41,16 @@ exports.addFragment = function(intf, u8, headerOffset, fragmentOffset, isMoreFra
3841
var firstFragment = false;
3942
var fragmentQueue = intf.fragments.get(hash);
4043
if (!fragmentQueue) {
44+
if (intf.fragments.size >= FRAGMENT_QUEUE_MAX_COUNT) {
45+
// too many fragment queues
46+
return;
47+
}
48+
4149
firstFragment = true;
4250
fragmentQueue = {
4351
receivedLength: 0,
4452
totalLength: 0,
53+
createdAt: timeNow(),
4554
fragments: []
4655
};
4756
}
@@ -162,3 +171,20 @@ exports.addFragment = function(intf, u8, headerOffset, fragmentOffset, isMoreFra
162171
return;
163172
}
164173
};
174+
175+
/**
176+
* Timer tick
177+
*
178+
* @param {Interface} intf Network interface
179+
*/
180+
exports.tick = function(intf) {
181+
var time = timeNow();
182+
183+
for (var pair of intf.fragments) {
184+
var hash = pair[0];
185+
var fragmentQueue = pair[1];
186+
if (fragmentQueue.createdAt + FRAGMENT_QUEUE_MAX_AGE_MS <= time) {
187+
dropFragmentQueue(intf, hash);
188+
}
189+
}
190+
};

js/core/net/ip4.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ var IP4Address = require('./ip4-address');
1717
var ip4header = require('./ip4-header');
1818
var ip4fragments = require('./ip4-fragments');
1919
var ip4receive = require('./ip4-receive');
20+
var timers = require('../timers');
21+
var interfaces = require('./interfaces');
22+
23+
timers.scheduleTask5s(function() {
24+
interfaces.forEach(ip4fragments.tick);
25+
});
2026

2127
function handleReceive(intf, u8, headerOffset) {
2228
var headerLength = ip4header.getHeaderLength(u8, headerOffset);

js/core/timers.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2015 runtime.js project authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
var tasks5s = [];
18+
19+
setInterval(function() {
20+
if (tasks5s.length === 0) {
21+
return;
22+
}
23+
24+
for (var i = 0, l = tasks5s.length; i < l; ++i) {
25+
tasks5s[i]();
26+
}
27+
}, 5000);
28+
29+
/**
30+
* Schedule task to run every 5 seconds
31+
*
32+
* @param {function} fn Function to run
33+
*/
34+
exports.scheduleTask5s = function(fn) {
35+
tasks5s.push(fn);
36+
};

js/test/unit/net/ip4.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
var test = require('tape');
1818
var runtime = require('../../..');
19+
var ip4fragments = require('../../../core/net/ip4-fragments');
1920
var interfaceMock = require('../lib/interface-mock');
2021
var packetBuilder = require('../lib/packet-builder');
2122

@@ -200,3 +201,41 @@ test('receive ip4 fragmented too big', function(t) {
200201
ipFragmentsTest(t, 'max-size + 1', 65535 - 8 + 1, slices, [0, 1], true);
201202
t.end();
202203
});
204+
205+
test('too many fragment queues and timeouts', function(t) {
206+
t.timeoutAfter(1000);
207+
var intf = interfaceMock();
208+
var originalNow = performance.now;
209+
210+
performance.now = function() {
211+
return 100;
212+
};
213+
214+
for (var i = 0; i < 150; ++i) {
215+
var fragments = packetBuilder.createFragmentedIP4({
216+
srcPort: 999,
217+
destPort: 65432,
218+
srcIP: '33.44.55.' + String(i)
219+
}, 64 + 8 /* 8 bytes udp header */, [{ offset: 0, len: 8 }]);
220+
intf.receive(fragments[0]);
221+
}
222+
223+
t.equal(intf.fragments.size, 100);
224+
225+
performance.now = function() {
226+
return 20100;
227+
};
228+
229+
ip4fragments.tick(intf);
230+
t.equal(intf.fragments.size, 100);
231+
232+
performance.now = function() {
233+
return 30100;
234+
};
235+
236+
ip4fragments.tick(intf);
237+
t.equal(intf.fragments.size, 0);
238+
239+
performance.now = originalNow;
240+
t.end();
241+
});

0 commit comments

Comments
 (0)