1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
37
  
38
  
39
  
40
  
41
  
42
  
43
  
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
104
  
105
  
106
  
107
  
108
  
109
  
110
  
/* 
 * By Francesco Chemolli 
 * This is a Roxen module. Copyright © 2000 - 2009, Roxen IS. 
 */ 
 
constant cvs_version="$Id$"; 
 
#include <module.h> 
inherit "throttlelib"; 
string filter_type="(by address)"; 
string rules_doc= 
#"Throttling rules. One rule per line, whose format is:<br /> 
<tt>ip_with_mask modifier [fix]</tt><br /> 
where ip_with_mask can be an ip address, or  
ip_address/bits, or ip_address:netmask<p> 
The search will be stopped at the first match."; 
 
#ifdef THROTTLING_DEBUG 
#undef THROTTLING_DEBUG 
#define THROTTLING_DEBUG(X) werror("Throttling by address: "+X+"\n") 
#else 
#define THROTTLING_DEBUG(X) 
#endif 
 
constant module_type = MODULE_FILTER; 
constant module_name = "Throttling: throttle by address"; 
constant module_doc  =  
#"This module will alter a request's bandwidth by client address."; 
constant module_unique=1; 
 
class IP_with_mask  
{ 
  int net; 
  int mask; 
  private int ip_to_int(string ip) 
  { 
    int res; 
    foreach(((ip/".") + ({ "0", "0", "0" }))[..3], string num) { 
      res = res*256 + (int)num; 
    } 
    return(res); 
  } 
  void create(string _ip, string|int _mask) 
  { 
    net = ip_to_int(_ip); 
    if (intp(_mask)) { 
      if (_mask > 32) { 
        report_error(sprintf("Bad netmask: %s/%d\n" 
                             "Using %s/32\n", _ip, _mask, _ip)); 
        _mask = 32; 
      } 
      mask = ~0<<(32-_mask); 
    } else { 
      mask = ip_to_int(_mask); 
    } 
    if (net & ~mask) { 
      report_error(sprintf("Bad netmask: %s for network %s\n" 
                           "Ignoring node-specific bits\n", _ip, _mask)); 
      net &= mask; 
    } 
  } 
  int `()(string ip) 
  { 
    return((ip_to_int(ip) & mask) == net); 
  } 
} 
 
mapping(string:object(IP_with_mask)) rules_cache=([]); 
//I'm not using the global cache because these are going to have a long 
//lifespan anyways 
 
object(IP_with_mask) add_to_cache(string rule) { 
  array(mixed) a; 
  if (sizeof(a=rule/"/")==2) { // ip / bits 
    a[1]=(int)a[1]; 
    return IP_with_mask(@a); 
  } 
  if (sizeof(a=rule/":")==2) { // ip : mask 
    return IP_with_mask(@a); 
  } 
  if (sscanf(rule,"%*d.%*d.%*d.%*d")==4) { //exact IP 
    return IP_with_mask(rule,32); 
  } 
  throw( ({ "Can't parse rule: "+rule , backtrace() }) ); 
} 
 
string|void update_rules(string new_rules) { 
   rules_cache=([]); 
   return ::update_rules(new_rules); 
} 
 
//FIXME: non e` la regola giusta! 
array find_rule (mapping res, object id,  
                 array(string) rulenames, mapping rules) { 
  string ra=id->remoteaddr; 
  THROTTLING_DEBUG("remote is "+ra); 
  foreach(rulenames,string rule) { 
    object(IP_with_mask) cr; 
    if (!rules_cache[rule]) cr=add_to_cache(rule); 
    THROTTLING_DEBUG("examining: "+rule); 
    if (cr(ra)) { 
      THROTTLING_DEBUG("!!matched!!"); 
      return(rules[rule]); 
      break; 
    } 
  } 
  return 0; 
}