Skip to content

Commit

Permalink
rbl check for alias creation
Browse files Browse the repository at this point in the history
I just have to be careful not to use a DUN list I guess. Aside of that,
I really want the RBL check for creation as in theory, a botnet could
generate thousands of aliases without ever hitting the rate limit.

Speaking of rate limit: This code here fixes the little async-screwup I
made in the rate limit code earlier
  • Loading branch information
pilif committed Jun 25, 2010
1 parent afd017d commit 7251750
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 44 deletions.
1 change: 1 addition & 0 deletions config.ini.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
port=8080 ; port to listen on for HTTP
listen=127.0.0.1 ; interface to bind webserver to (empty for all)
rate_limit=30000 ; time users have to wait before generating another alias
rbls=examplea.com,exampleb.com ; rbl domains to check for HTTP (alias generation)

[smtp]
port=2525 ; port to listen on for SMTP
Expand Down
6 changes: 5 additions & 1 deletion lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fs = require('fs');

var config_file = __dirname + '/../config.ini';

exports.http = {port: 8080, listen: null, rate_limit: 30000 };
exports.http = {port: 8080, listen: null, rate_limit: 30000, rbls: [] };
exports.smtp = {
port: 2525,
listen: null,
Expand All @@ -28,6 +28,10 @@ if (cf.isFile()){
if (c.http.port) exports.http.port = parseInt(c.http.port, 10);
if (c.http.rate_limit) exports.http.rate_limit = parseInt(c.http.rate_limit, 10);
if (c.http.listen) exports.http.listen = c.http.listen;
if (c.http.rbls){
exports.http.rbls = c.http.rbls.split(',');
}

}
if (c.general){
if (c.http.listen) exports.general.pidFile = c.general.pidFile;
Expand Down
110 changes: 67 additions & 43 deletions lib/tempalias_http.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,53 +55,77 @@ fs.realpath('lib/../public', function(err, public_root){
res.end(body);
};

// too bad SETNX counts as a write operation even when it doesn't write.
// that's why I can't just use redis' EXPIRE command
var lock_key = 'lock:'+req.socket.remoteAddress;
var t = (new Date()).getTime();
redis.setnx(lock_key, t+30000, function(lr){
if (!lr){
redis.get(lock_key, function(exp){
if (parseInt(exp, 10) < (t)){
redis.del(lock_key);
}else{
err(403, {error: 'rate-limited', description: 'please wait a moment before generating the next alias'});
}
});
}
});

process.addListener('uncaughtException', function (e) {
var msg = (e && e.message) ? e.message : 'unknown';
err(500, {error: 'server-error', description: msg});
});

var genAlias = function(data){
var alias = p.getNew();
try{
alias.setInfo(data);
}catch(e){
err(400, {
error: "invalid-data",
description: e.message
});
}
try{
p.save(alias, function(id){
try{
alias.currentDate = new Date();
var f = alias.valid_from ? alias.valid_from.getDate() : new Date();
if (alias.valid_until && !alias.valid_from){
alias.days = Math.ceil((alias.valid_until.getTime()-f.getTime())/(1000*60*60*24));
var generate = function(){
var alias = p.getNew();
try{
alias.setInfo(data);
}catch(e){
err(400, {
error: "invalid-data",
description: e.message
});
}
try{
p.save(alias, function(id){
try{
alias.currentDate = new Date();
var f = alias.valid_from ? alias.valid_from.getDate() : new Date();
if (alias.valid_until && !alias.valid_from){
alias.days = Math.ceil((alias.valid_until.getTime()-f.getTime())/(1000*60*60*24));
}
sendAlias(alias);
}catch(e){
err(500, {error: "server-exception", description: e.message});
}
});
}catch(e){
err(500, {error: "server-exception", description: e.message});
}
};

var rbl_check = function(){
if (config.http.rbls){
sys.debug('rbls set');
var addr = req.socket.remoteAddress;
require('rbl').check(addr, config.http.rbls, function(found){
if (found){
err(403, {error: 'rbl-check-failed', description: 'refused to generate alias for your IP-address'});
}else{
generate();
}
sendAlias(alias);
}catch(e){
err(500, {error: "server-exception", description: e.message});
});
}else{
generate();
}
};

var rate_limit_check = function(){
// too bad SETNX counts as a write operation even when it doesn't write.
// that's why I can't just use redis' EXPIRE command
var lock_key = 'lock:'+req.socket.remoteAddress;
var t = (new Date()).getTime();
redis.setnx(lock_key, t+config.http.rate_limit, function(lr){
if (!lr){
redis.get(lock_key, function(exp){
if (parseInt(exp, 10) < (t)){
sys.debug('lock key found but expired');
redis.set(lock_key, t+config.http.rate_limit, function(){
sys.debug('lock key updated');
rbl_check();
});
}else{
err(403, {error: 'rate-limited', description: 'please wait a moment before generating the next alias'});
}
});
}else{
sys.debug('lock key not found. Was set to '+lr);
rbl_check();
}
});
}catch(e){
err(500, {error: "server-exception", description: e.message});
}
};

rate_limit_check();
};

if (!url.query.callback){
Expand Down

0 comments on commit 7251750

Please sign in to comment.