1 package FS::addr_range;
4 use base qw( FS::Record );
5 use vars qw( %status_desc
9 use FS::Record qw( qsearch qsearchs );
12 # metadata about status strings:
13 # how to describe them
16 'unavailable' => 'unavailable',
19 # whether addresses in this range are available for use
27 FS::addr_range - Object methods for addr_range records
33 $record = new FS::addr_range \%hash;
34 $record = new FS::addr_range { 'column' => 'value' };
36 $error = $record->insert;
38 $error = $new_record->replace($old_record);
40 $error = $record->delete;
42 $error = $record->check;
46 An FS::addr_range object represents a contiguous range of IP
47 addresses assigned to a certain purpose. Unlike L<FS::addr_block>,
48 this isn't a routing block; the range doesn't have to be aligned on
49 a subnet boundary, and doesn't have a gateway or broadcast address.
54 =item rangenum - primary key
56 =item start - starting address of the range, as a dotted quad
58 =item length - number of addresses in the range, including start
60 =item status - what to do with the addresses in this range; currently can
61 only be "unavailable", which makes the addresses unavailable for assignment
62 to any kind of service.
72 Creates a new range. To add the example to the database, see L<"insert">.
74 Note that this stores the hash reference, not a distinct copy of the hash it
75 points to. You can ask the object for a copy with the I<hash> method.
79 sub table { 'addr_range'; }
83 Adds this record to the database. If there is an error, returns the error,
84 otherwise returns false.
88 # the insert method can be inherited from FS::Record
92 Delete this record from the database.
96 # the delete method can be inherited from FS::Record
98 =item replace OLD_RECORD
100 Replaces the OLD_RECORD with this one in the database. If there is an error,
101 returns the error, otherwise returns false.
105 # the replace method can be inherited from FS::Record
109 Checks all fields to make sure this is a valid example. If there is
110 an error, returns the error, otherwise returns false. Called by the insert
115 # the check method should currently be supplied - FS::Record contains some
116 # data checking routines
122 $self->ut_numbern('rangenum')
123 || $self->ut_ip('start')
124 || $self->ut_number('length')
125 || $self->ut_textn('status')
127 return $error if $error;
134 Get/set the end IP address in the range. This isn't actually part of the
135 record but it's convenient.
141 # if there's no start address, just return nothing
142 my $start = NetAddr::IP->new($self->start, 0) or return '';
146 my $end = NetAddr::IP->new($new, 0)
147 or die "bad end address $new";
148 if ( $end < $start ) {
149 $self->set('start', $end);
150 ($end, $start) = ($start, $end);
152 # fails if $end - $start > 2^31
154 # (fixed in NetAddr::IP 4.050 but we can't rely on that, apparently)
155 $self->set('length', $end - $start + 1);
158 my $end = $start + $self->get('length') - 1;
162 =item contains IPADDR
164 Checks whether IPADDR (a dotted-quad IPv4 address) is within the range.
171 $addr = NetAddr::IP->new($addr, 0);
172 return 0 unless $addr;
174 my $start = NetAddr::IP->new($self->start, 0);
176 return ($addr >= $start and $addr < ( $start + $self->length) )
182 Returns a readable string showing the address range.
188 my $start = NetAddr::IP->new($self->start, 0);
189 my $end = $start + $self->length - 1;
191 if ( $self->length == 1 ) {
192 # then just the address
194 } else { # we have to get tricksy
195 my @end_octets = split('\.', $end->addr);
196 $start = ($start->numeric)[0] + 0;
197 $end = ($end->numeric)[0] + 0;
198 # which octets are different between start and end?
199 my $delta = $end ^ $start;
200 foreach (0xffffff, 0xffff, 0xff) {
201 if ( $delta <= $_ ) {
202 # then they are identical in the first 8/16/24 bits
206 return $self->start . '-' . join('.', @end_octets);
212 Returns a semi-friendly description of the block status.
216 Returns true if addresses in this range can be used by services, etc.
222 $status_desc{ $self->status };
227 $status_allow_use{ $self->status };
234 =sub any_contains IPADDR
236 Returns all address ranges that contain IPADDR.
243 return grep { $_->contains($addr) } qsearch('addr_range', {});
246 =head1 DEVELOPER NOTE
248 L<NetAddr::IP> objects have netmasks. They also have overloaded operators
249 for addition and subtraction, but those have range limitations when comparing
250 addresses. (An IPv4 address is effectively a uint32; the difference
251 between two IPv4 addresses is the same range, but signed.) In later versions
252 of the library the C<bigint> method can be used as a workaround, but
253 otherwise it's not safe to subtract two addresses that might differ in the
254 first bit of the first octet.
260 L<FS::svc_IP_Mixin>, L<FS::Record>, schema.html from the base documentation.