Simple Rate Limiting on OpenSIPs using Redis

Election time is upon us, and lots of our customers are getting hit with unwanted dialer traffic (some people refer to this as robocalls).  To combat this, here is a simple albeit far from fool-proof way to limit the amount of calls being sent from particular users.

The advantages of using Redis for this are as follows:

  • It is a very light-weight solution
  • It's configured with a time to live (TTL) so that blocks will fall off over time
  • This solution is highly configurable
  • It's very easy to troubleshoot

The following is the base configuration that belongs in your opensips.cfg.  It rejects all calls from a unique From URI after that From URI exceeds 50 calls per minute. Simple modifications will allow you to adjust based upon your business rules.  For example, limiting by Request URI would easy with a few simple changes this.

First we load the redis module and connect to the Redis server.

loadmodule "cachedb_redis.so"
modparam("cachedb_redis", "cachedb_url", "redis://127.0.0.1:6379/")

Create the rate limiter route. $fu, ttl and max values can easily be changed to something more appropriate for your setup.

route[from_user_rate_limiter] {
  $var(minute) = $time(%Y-%m-%dT%H:%M);
  $var(key) = "invites:from_user:" + $fu + ":count";

  if(cache_counter_fetch("redis", "$var(key)", $var(result))) {
    if($var(result) >= 50) {
      return(-1);
    } else {
      cache_add("redis", "$var(key)", 1, 60);
      return(1);
    }
  } else {
    cache_add("redis", "$var(key)", 1, 60);
    return(1);
}

Finally call the route, check the return value, then take action. In this case, send a 480 reply.

route(from_user_rate_limiter);

if($retcode == -1) {
  xlog("L_WARN","WARN: Callid $ci - $fu is above the rate limit\n");
  sl_send_reply("480","Temporarily Unavailable");
  exit;
}