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
  
111
  
112
  
113
  
114
  
115
  
116
  
117
  
118
  
119
  
120
  
121
  
122
  
123
  
124
  
125
  
126
  
127
  
128
  
129
  
130
  
131
  
132
  
133
  
134
  
135
  
136
  
137
  
138
  
139
  
140
  
#pike __REAL_VERSION__ 
#pragma strict_types 
 
//!   Lightweight IPv4 and IPv6 address type that stores the netmask 
//!   and allows simple arithmetic and comparison operators. 
 
#define IPV4MAX       0xffffffff 
 
constant is_inet = 1; 
 
//! IP address converted to an integer. 
//! IPv4 addresses will be 32-bit or less. 
int address; 
 
//! Defines the netmask.  For both IPv4 and IPv6 addresses, 
//! @[masklen] will be 128 in case of full addresses. 
int masklen; 
 
array(int) _encode() { 
  return ({address, masklen}); 
} 
 
void _decode(array(int) x) { 
  address = x[0]; 
  masklen = x[1]; 
} 
 
protected int __hash() { 
  return address; 
} 
 
//! @param ip 
//!   A string defining an IPv4 or IPv6 address 
//!   with an optional @expr{masklen@} attached. 
//!   If the address is in IPv6 notation, the range 
//!   of the @expr{masklen@} is expected to be 
//!   between @expr{0@} and @expr{128@}. 
//!   If the address is in IPv4 notation, the range 
//!   of the @expr{masklen@} is expected to be 
//!   between @expr{0@} and @expr{32@}. 
variant protected void create(string ip) { 
  masklen = -1; 
  sscanf(ip, "%s/%d", ip, masklen); 
  address = NetUtils.string_to_ip(ip); 
  if (masklen < 0) 
    masklen = 128; 
  else if (!has_value(ip, ":")) 
    masklen += 12 * 8; 
} 
 
//! @param ip 
//!   An IPv4 or IPv6 ip address. 
//! @param masklen 
//!   Defines the netmask, always in the range between @expr{0@} 
//!   and @expr{128@}; i.e. for IPv4 addresses you should 
//!   add @expr{12 * 8@} to the actual IPv4-masklen. 
variant protected void create(int ip, void|int masklen) { 
  address = ip; 
  this::masklen = zero_type(masklen) ? 16*8 : masklen; 
} 
variant protected void create() { 
} 
 
protected mixed `+(mixed that) { 
  if (!intp(that)) 
    error("Cannot add %O\n", that); 
  this_program n = this_program(); 
  n->masklen = masklen; 
  n->address = address + [int]that; 
  return n; 
} 
 
protected mixed `-(mixed that) { 
  if (intp(that)) 
    return this + -[int]that; 
  else if (objectp(that) && ([object]that)->is_inet) 
    return this->address - [int]([object]that)->address; 
  error("Cannot add %O\n", that); 
} 
 
protected mixed `~() { 
  this_program n = this_program(); 
  n->masklen = masklen; 
  n->address = ~address; 
  return n; 
} 
 
protected mixed `|(mixed that) { 
  this_program n = this_program(); 
  n->masklen = max(masklen, [int]([object]that)->masklen); 
  n->address = address | [int]([object]that)->address; 
  return n; 
} 
 
protected mixed `&(mixed that) { 
  this_program n = this_program(); 
  n->masklen = min(masklen, [int]([object]that)->masklen); 
  n->address = address & [int]([object]that)->address; 
  return n; 
} 
 
protected int(0..1) `<(mixed that) { 
  return objectp(that) ? address < [int]([object]that)->address 
   : intp(that) && address < [int]that; 
} 
 
protected int(0..1) `>(mixed that) { 
  return objectp(that) ? address > [int]([object]that)->address 
   : intp(that) && address > [int]that; 
} 
 
protected int(0..1) `==(mixed that) { 
  return objectp(that) 
   ? address == [int]([object]that)->address 
      && masklen == [int]([object]that)->masklen 
   : address == [int]that; 
} 
 
protected mixed cast(string to) { 
  switch (to) { 
    case "string": 
      return NetUtils.ip_to_string(address) 
       + (masklen == 128 ? "" : 
                    sprintf("/%d", masklen - (address <= IPV4MAX && 12*8))); 
    case "int": 
      return address; 
    default: 
      return UNDEFINED; 
  } 
} 
 
protected string _sprintf(int fmt, mapping(string:mixed) params) { 
  switch (fmt) { 
    case 'O': return sprintf("Inet(%s)", (string)this); 
    case 's': return (string)this; 
  } 
  return sprintf(sprintf("%%*%c", fmt), params, 0); 
}