1 |
95b003ff
|
Origo
|
#!/usr/bin/perl
|
2 |
|
|
|
3 |
|
|
# All rights reserved and Copyright (c) 2020 Origo Systems ApS.
|
4 |
|
|
# This file is provided with no warranty, and is subject to the terms and conditions defined in the license file LICENSE.md.
|
5 |
|
|
# The license file is part of this source code package and its content is also available at:
|
6 |
|
|
# https://www.origo.io/info/stabiledocs/licensing/stabile-open-source-license
|
7 |
|
|
|
8 |
|
|
package Stabile::Networks;
|
9 |
|
|
|
10 |
|
|
use Error qw(:try);
|
11 |
|
|
use Data::Dumper;
|
12 |
|
|
use Time::Local;
|
13 |
|
|
use Time::HiRes qw( time );
|
14 |
|
|
use Data::UUID;
|
15 |
|
|
use Net::Netmask;
|
16 |
|
|
use Net::Ping;
|
17 |
|
|
use File::Basename;
|
18 |
|
|
use List::Util qw(shuffle);
|
19 |
|
|
use lib dirname (__FILE__);
|
20 |
|
|
use Stabile;
|
21 |
|
|
|
22 |
2a63870a
|
Christian Orellana
|
($datanic, $extnic) = $main::getNics->();
|
23 |
95b003ff
|
Origo
|
$extsubnet = $Stabile::config->get('EXTERNAL_SUBNET_SIZE');
|
24 |
|
|
$proxynic = $Stabile::config->get('PROXY_NIC') || $extnic;
|
25 |
|
|
$proxyip = $Stabile::config->get('PROXY_IP');
|
26 |
|
|
$proxygw = $Stabile::config->get('PROXY_GW') || $proxyip;
|
27 |
|
|
$proxysubnet = $Stabile::config->get('PROXY_SUBNET_SIZE');
|
28 |
|
|
my $engineid = $Stabile::config->get('ENGINEID') || "";
|
29 |
|
|
$dodns = $Stabile::config->get('DO_DNS') || "";
|
30 |
71b897d3
|
hq
|
$enginelinked = $Stabile::config->get('ENGINE_LINKED') || "";
|
31 |
95b003ff
|
Origo
|
|
32 |
|
|
my $tenders = $Stabile::config->get('STORAGE_POOLS_ADDRESS_PATHS');
|
33 |
|
|
@tenderlist = split(/,\s*/, $tenders);
|
34 |
|
|
my $tenderpaths = $Stabile::config->get('STORAGE_POOLS_LOCAL_PATHS') || "/mnt/stabile/images";
|
35 |
|
|
@tenderpathslist = split(/,\s*/, $tenderpaths);
|
36 |
|
|
my $tendernames = $Stabile::config->get('STORAGE_POOLS_NAMES') || "Standard storage";
|
37 |
|
|
@tendernameslist = split(/,\s*/, $tendernames);
|
38 |
|
|
$storagepools = $Stabile::config->get('STORAGE_POOLS_DEFAULTS') || "0";
|
39 |
|
|
|
40 |
|
|
$uiuuid;
|
41 |
|
|
$uistatus;
|
42 |
|
|
$help = 0; # If this is set, functions output help
|
43 |
|
|
|
44 |
|
|
#our %options=();
|
45 |
|
|
# -a action -h help -u uuid -m match pattern -f full list, i.e. all users
|
46 |
|
|
# -v verbose, include HTTP headers -s impersonate subaccount -t target [uuid or image]
|
47 |
|
|
# -g args to gearman task
|
48 |
|
|
#Getopt::Std::getopts("a:hfu:g:m:vs:t:", \%options);
|
49 |
|
|
|
50 |
|
|
try {
|
51 |
|
|
Init(); # Perform various initalization tasks
|
52 |
|
|
process() if ($package);
|
53 |
|
|
|
54 |
|
|
} catch Error with {
|
55 |
|
|
my $ex = shift;
|
56 |
|
|
print header('text/html', '500 Internal Server Error') unless ($console);
|
57 |
|
|
if ($ex->{-text}) {
|
58 |
|
|
print "Got error: ", $ex->{-text}, " on line ", $ex->{-line}, "\n";
|
59 |
|
|
} else {
|
60 |
|
|
print "Status=ERROR\n";
|
61 |
|
|
}
|
62 |
|
|
} finally {
|
63 |
|
|
};
|
64 |
|
|
|
65 |
|
|
1;
|
66 |
|
|
|
67 |
|
|
sub getObj {
|
68 |
|
|
my %h = %{@_[0]};
|
69 |
|
|
$console = 1 if $h{"console"};
|
70 |
|
|
$api = 1 if $h{"api"};
|
71 |
|
|
my $uuid = $h{"uuid"};
|
72 |
eb31fb38
|
hq
|
my $obj;
|
73 |
|
|
$action = $action || $h{'action'};
|
74 |
|
|
if (
|
75 |
|
|
$action =~ /^dns/
|
76 |
|
|
) {
|
77 |
|
|
$obj = \%h;
|
78 |
|
|
return $obj;
|
79 |
|
|
}
|
80 |
95b003ff
|
Origo
|
$uuid = $curuuid if ($uuid eq 'this');
|
81 |
d3d1a2d4
|
Origo
|
if ($uuid =~ /(\d+\.\d+\.\d+\.\d+)/) { # ip addresses are unique across networks so we allow this
|
82 |
|
|
foreach my $val (values %register) {
|
83 |
|
|
if ($val->{'internalip'} eq $uuid || $val->{'externalip'} eq $uuid) {
|
84 |
|
|
$uuid = $val->{'uuid'};
|
85 |
|
|
last;
|
86 |
|
|
}
|
87 |
|
|
}
|
88 |
|
|
}
|
89 |
95b003ff
|
Origo
|
my $dbobj = $register{$uuid} || {};
|
90 |
|
|
my $status = $dbobj->{'status'} || $h{"status"}; # Trust db status if it exists
|
91 |
c899e439
|
Origo
|
if ((!$uuid && $uuid ne '0') && (!$status || $status eq 'new') && ($action eq 'save')) {
|
92 |
95b003ff
|
Origo
|
my $ug = new Data::UUID;
|
93 |
|
|
$uuid = $ug->create_str();
|
94 |
|
|
$status = 'new';
|
95 |
|
|
};
|
96 |
|
|
return 0 unless ($uuid && length $uuid == 36);
|
97 |
|
|
|
98 |
|
|
$uiuuid = $uuid;
|
99 |
|
|
$uistatus = $dbobj->{'status'};
|
100 |
|
|
|
101 |
|
|
my $id = $h{"id"};
|
102 |
|
|
my $dbid = 0+$dbobj->{'id'};
|
103 |
|
|
if ($status eq 'new' || !$dbid) {
|
104 |
|
|
$id = getNextId($id) ;
|
105 |
|
|
} else {
|
106 |
|
|
$id = $dbid;
|
107 |
|
|
}
|
108 |
|
|
|
109 |
|
|
if ($id > 4095 || $id < 0 || ($id==0 && $uuid!=0) || ($id==1 && $uuid!=1)) {
|
110 |
|
|
$postreply .= "Status=ERROR Invalid new network id $id\n";
|
111 |
|
|
return;
|
112 |
|
|
}
|
113 |
|
|
my $name = $h{"name"} || $dbobj->{'name'};
|
114 |
|
|
my $internalip = $h{"internalip"} || $dbobj->{'internalip'};
|
115 |
|
|
if (!($internalip =~ /\d+\.\d+\.\d+\.\d+/)) {$internalip = ""};
|
116 |
|
|
my $externalip = $h{"externalip"} || $dbobj->{'externalip'};
|
117 |
|
|
my $ports = $h{"ports"} || $dbobj->{'ports'};
|
118 |
|
|
my $type = $h{"type"} || $dbobj->{'type'};
|
119 |
d3d1a2d4
|
Origo
|
my $systems = $h{"systems"} || $dbobj->{'systems'};
|
120 |
|
|
my $force = $h{"force"};
|
121 |
95b003ff
|
Origo
|
my $reguser = $dbobj->{'user'};
|
122 |
|
|
# Sanity checks
|
123 |
|
|
if (
|
124 |
|
|
($name && length $name > 255)
|
125 |
|
|
|| ($ports && length $ports > 255)
|
126 |
|
|
|| ($type && !($type =~ /gateway|ipmapping|internalip|externalip/))
|
127 |
|
|
) {
|
128 |
|
|
$postreply .= "Stroke=ERROR Bad network data: $name\n";
|
129 |
|
|
return;
|
130 |
|
|
}
|
131 |
|
|
# Security check
|
132 |
d24d9a01
|
hq
|
if (($user ne $reguser && index($privileges,"a")==-1 && $action ne 'save' ) ||
|
133 |
95b003ff
|
Origo
|
($reguser && $status eq "new"))
|
134 |
|
|
{
|
135 |
d24d9a01
|
hq
|
$postreply .= "Stroke=ERROR Bad user: $user, $action\n";
|
136 |
95b003ff
|
Origo
|
return;
|
137 |
|
|
}
|
138 |
|
|
|
139 |
|
|
if (!$type ||($type ne 'gateway' && $type ne 'internalip' && $type ne 'ipmapping' && $type ne 'externalip')) {
|
140 |
|
|
$type = "gateway";
|
141 |
|
|
if ($internalip && $internalip ne "--" && $externalip && $externalip ne "--") {$type = "ipmapping";}
|
142 |
|
|
elsif (($internalip && $internalip ne "--") || $status eq 'new') {$type = "internalip";}
|
143 |
|
|
elsif (($externalip && $externalip ne "--") || $status eq 'new') {$type = "externalip";}
|
144 |
d3d1a2d4
|
Origo
|
}
|
145 |
95b003ff
|
Origo
|
|
146 |
|
|
my $obj = {
|
147 |
|
|
uuid => $uuid,
|
148 |
|
|
id => $id,
|
149 |
|
|
name => $name,
|
150 |
|
|
status => $status,
|
151 |
|
|
type => $type,
|
152 |
|
|
internalip => $internalip,
|
153 |
|
|
externalip => $externalip,
|
154 |
|
|
ports => $ports,
|
155 |
d3d1a2d4
|
Origo
|
systems => $systems,
|
156 |
|
|
force => $force,
|
157 |
95b003ff
|
Origo
|
action => $h{"action"}
|
158 |
|
|
};
|
159 |
|
|
return $obj;
|
160 |
|
|
}
|
161 |
|
|
|
162 |
|
|
sub Init {
|
163 |
|
|
|
164 |
|
|
# Tie database tables to hashes
|
165 |
|
|
unless ( tie(%register,'Tie::DBI', Hash::Merge::merge({table=>'networks'}, $Stabile::dbopts)) ) {return "Unable to access network register"};
|
166 |
|
|
unless ( tie(%domreg,'Tie::DBI', Hash::Merge::merge({table=>'domains'}, $Stabile::dbopts)) ) {return "Unable to access domain register"};
|
167 |
|
|
|
168 |
|
|
# simplify globals initialized in Stabile.pm
|
169 |
|
|
$tktuser = $tktuser || $Stabile::tktuser;
|
170 |
|
|
$user = $user || $Stabile::user;
|
171 |
|
|
|
172 |
|
|
# Create aliases of functions
|
173 |
|
|
*header = \&CGI::header;
|
174 |
|
|
|
175 |
|
|
*Natall = \&Deactivateall;
|
176 |
|
|
*Stopall = \&Deactivateall;
|
177 |
|
|
*Restoreall = \&Activateall;
|
178 |
|
|
|
179 |
|
|
*do_save = \&Save;
|
180 |
|
|
*do_tablelist = \&do_list;
|
181 |
|
|
*do_jsonlist = \&do_list;
|
182 |
|
|
*do_listnetworks = \&do_list;
|
183 |
|
|
*do_this = \&do_list;
|
184 |
|
|
*do_help = \&action;
|
185 |
|
|
*do_remove = \&action;
|
186 |
|
|
|
187 |
|
|
*do_restoreall = \&privileged_action;
|
188 |
|
|
*do_activateall = \&privileged_action;
|
189 |
|
|
*do_deactivateall = \&privileged_action;
|
190 |
|
|
*do_natall = \&privileged_action;
|
191 |
|
|
*do_stopall = \&privileged_action;
|
192 |
|
|
*do_stop = \&privileged_action;
|
193 |
|
|
*do_activate = \&privileged_action;
|
194 |
|
|
*do_deactivate = \&privileged_action;
|
195 |
|
|
|
196 |
|
|
*do_gear_activate = \&do_gear_action;
|
197 |
|
|
*do_gear_deactivate = \&do_gear_action;
|
198 |
|
|
*do_gear_stop = \&do_gear_action;
|
199 |
|
|
*do_gear_activateall = \&do_gear_action;
|
200 |
|
|
*do_gear_restoreall = \&do_gear_action;
|
201 |
|
|
*do_gear_deactivateall = \&do_gear_action;
|
202 |
|
|
*do_gear_stopall = \&do_gear_action;
|
203 |
|
|
*do_gear_natall = \&do_gear_action;
|
204 |
|
|
|
205 |
|
|
$rx; # Global rx count in bytes
|
206 |
|
|
$tx; # Global tx count in bytes
|
207 |
|
|
$etcpath = "/etc/stabile/networks";
|
208 |
|
|
|
209 |
|
|
}
|
210 |
|
|
|
211 |
|
|
sub do_list {
|
212 |
d3d1a2d4
|
Origo
|
my ($uuid, $action, $obj) = @_;
|
213 |
95b003ff
|
Origo
|
if ($help) {
|
214 |
|
|
return <<END
|
215 |
d3d1a2d4
|
Origo
|
GET:uuid:
|
216 |
95b003ff
|
Origo
|
List networks current user has access to.
|
217 |
|
|
END
|
218 |
|
|
}
|
219 |
|
|
|
220 |
|
|
my $res;
|
221 |
|
|
my $filter;
|
222 |
|
|
my $statusfilter;
|
223 |
|
|
my $uuidfilter;
|
224 |
d3d1a2d4
|
Origo
|
$uuid = $obj->{'uuid'} if ($obj->{'uuid'});
|
225 |
95b003ff
|
Origo
|
|
226 |
|
|
if ($curuuid && ($isadmin || $register{$curuuid}->{'user'} eq $user) && $uripath =~ /networks(\.cgi)?\/(\?|)(this)/) {
|
227 |
|
|
$uuidfilter = $curuuid;
|
228 |
|
|
} elsif ($uripath =~ /networks(\.cgi)?\/(\?|)(name|status)/) {
|
229 |
|
|
$filter = $3 if ($uripath =~ /networks(\.cgi)?\/.*name(:|=)(.+)/);
|
230 |
|
|
$statusfilter = $3 if ($uripath =~ /networks(\.cgi)?\/.*status(:|=)(\w+)/);
|
231 |
|
|
} elsif ($uripath =~ /networks(\.cgi)?\/(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})/) {
|
232 |
d3d1a2d4
|
Origo
|
$uuidfilter = $2;
|
233 |
|
|
} elsif ($uuid) {
|
234 |
|
|
$uuidfilter = $uuid;
|
235 |
95b003ff
|
Origo
|
}
|
236 |
|
|
$uuidfilter = $options{u} unless $uuidfilter;
|
237 |
|
|
$filter = $1 if ($filter =~ /(.*)\*/);
|
238 |
|
|
$statusfilter = '' if ($statusfilter eq '*');
|
239 |
|
|
|
240 |
|
|
my $curnetwork = URI::Escape::uri_unescape($params{'network'});
|
241 |
|
|
my $curnetwork1 = URI::Escape::uri_unescape($params{'network1'});
|
242 |
|
|
|
243 |
|
|
my $sysuuid;
|
244 |
|
|
if ($params{'system'}) {
|
245 |
|
|
$sysuuid = $params{'system'};
|
246 |
|
|
$sysuuid = $cursysuuid || $curdomuuid if ($params{'system'} eq 'this');
|
247 |
|
|
}
|
248 |
|
|
|
249 |
|
|
$res .= header('application/json') unless ($console || $action eq 'tablelist');
|
250 |
|
|
my @curregvalues;
|
251 |
|
|
|
252 |
54401133
|
hq
|
# updateBilling();
|
253 |
95b003ff
|
Origo
|
my @regkeys;
|
254 |
|
|
if ($fulllist) {
|
255 |
|
|
@regkeys = keys %register;
|
256 |
|
|
} elsif ($uuidfilter && $isadmin) {
|
257 |
|
|
@regkeys = (tied %register)->select_where("uuid = '$uuidfilter'");
|
258 |
|
|
} else {
|
259 |
|
|
@regkeys = (tied %register)->select_where("user = '$user' OR user = 'common'");
|
260 |
|
|
}
|
261 |
|
|
|
262 |
|
|
foreach my $k (@regkeys) {
|
263 |
|
|
my $valref = $register{$k};
|
264 |
|
|
my $uuid = $valref->{'uuid'};
|
265 |
|
|
my $dbuser = $valref->{'user'};
|
266 |
|
|
my $type = $valref->{'type'};
|
267 |
|
|
my $id = $valref->{'id'};
|
268 |
|
|
# Only list networks belonging to current user
|
269 |
|
|
if ($dbuser eq "common" || $user eq $dbuser || $fulllist || ($uuidfilter && $isadmin)) {
|
270 |
|
|
my $dom = $domreg{$valref->{'domains'}};
|
271 |
|
|
next unless (!$sysuuid || $dom->{'system'} eq $sysuuid || $valref->{'domains'} eq $sysuuid);
|
272 |
|
|
validateStatus($valref);
|
273 |
|
|
|
274 |
|
|
my %val = %{$valref}; # Deference and assign to new ass array, effectively cloning object
|
275 |
|
|
$val{'id'} += 0;
|
276 |
|
|
$val{'rx'} = $rx;
|
277 |
|
|
$val{'tx'} = $tx;
|
278 |
04c16f26
|
hq
|
$val{'domainnames'} = decode('utf8', $val{'domainnames'});
|
279 |
95b003ff
|
Origo
|
if ($filter || $statusfilter || $uuidfilter) { # List filtered networks
|
280 |
|
|
my $fmatch;
|
281 |
|
|
my $smatch;
|
282 |
|
|
my $umatch;
|
283 |
|
|
$fmatch = 1 if (!$filter || $val{'name'}=~/$filter/i);
|
284 |
|
|
$smatch = 1 if (!$statusfilter || $statusfilter eq 'all'
|
285 |
|
|
|| $statusfilter eq $val{'status'}
|
286 |
|
|
);
|
287 |
|
|
$umatch = 1 if ($val{'uuid'} eq $uuidfilter);
|
288 |
|
|
if ($fmatch && $smatch && !$uuidfilter) {
|
289 |
|
|
push @curregvalues,\%val;
|
290 |
|
|
} elsif ($umatch) {
|
291 |
|
|
push @curregvalues,\%val;
|
292 |
|
|
last;
|
293 |
|
|
}
|
294 |
|
|
|
295 |
|
|
} elsif ($action eq "listnetworks") { # List available networks
|
296 |
c899e439
|
Origo
|
if (($id>0 || index($privileges,"a")!=-1) && ((!$valref->{'domains'} && !$valref->{'systems'}) || $type eq 'gateway' || ($curnetwork eq $uuid && !$curnetwork1) || $curnetwork1 eq $uuid)) {
|
297 |
95b003ff
|
Origo
|
push @curregvalues,\%val;
|
298 |
|
|
}
|
299 |
|
|
} else {
|
300 |
|
|
push @curregvalues,\%val if ($id>0 || index($privileges,"a")!=-1);
|
301 |
|
|
}
|
302 |
|
|
}
|
303 |
|
|
}
|
304 |
|
|
|
305 |
|
|
# Sort @curregvalues
|
306 |
|
|
my $sort = 'status';
|
307 |
|
|
$sort = $2 if ($uripath =~ /sort\((\+|\-)(\S+)\)/);
|
308 |
|
|
my $reverse;
|
309 |
|
|
$reverse = 1 if ($1 eq '-');
|
310 |
|
|
if ($reverse) { # sort reverse
|
311 |
|
|
if ($sort =~ /id/) {
|
312 |
|
|
@curregvalues = (sort {$b->{$sort} <=> $a->{$sort}} @curregvalues); # Sort as number
|
313 |
|
|
} else {
|
314 |
|
|
@curregvalues = (sort {$b->{$sort} cmp $a->{$sort}} @curregvalues); # Sort as string
|
315 |
|
|
}
|
316 |
|
|
} else {
|
317 |
|
|
if ($sort =~ /id/) {
|
318 |
|
|
@curregvalues = (sort {$a->{$sort} <=> $b->{$sort}} @curregvalues); # Sort as number
|
319 |
|
|
} else {
|
320 |
|
|
@curregvalues = (sort {$a->{$sort} cmp $b->{$sort}} @curregvalues); # Sort as string
|
321 |
|
|
}
|
322 |
|
|
}
|
323 |
|
|
|
324 |
|
|
my %val = ("uuid", "--", "name", "--");
|
325 |
|
|
if ($curnetwork1) {
|
326 |
|
|
push @curregvalues, \%val;
|
327 |
|
|
}
|
328 |
|
|
if ($action eq 'tablelist') {
|
329 |
|
|
$res .= header("text/plain") unless ($console);
|
330 |
|
|
my $t2 = Text::SimpleTable->new(36,20,10,5,10,14,14,7);
|
331 |
|
|
$t2->row('uuid', 'name', 'type', 'id', 'internalip', 'externalip', 'user', 'status');
|
332 |
|
|
$t2->hr;
|
333 |
|
|
my $pattern = $options{m};
|
334 |
|
|
foreach $rowref (@curregvalues){
|
335 |
|
|
if ($pattern) {
|
336 |
|
|
my $rowtext = $rowref->{'uuid'} . " " . $rowref->{'name'} . " " . $rowref->{'type'} . " " . $rowref->{'id'}
|
337 |
|
|
. " " . $rowref->{'internalip'} . " " . $rowref->{'externalip'} . " " . $rowref->{'user'} . " " . $rowref->{'status'};
|
338 |
|
|
$rowtext .= " " . $rowref->{'mac'} if ($isadmin);
|
339 |
|
|
next unless ($rowtext =~ /$pattern/i);
|
340 |
|
|
}
|
341 |
|
|
$t2->row($rowref->{'uuid'}, $rowref->{'name'}||'--', $rowref->{'type'}, $rowref->{'id'},
|
342 |
|
|
$rowref->{'internalip'}||'--', $rowref->{'externalip'}||'--', $rowref->{'user'}, $rowref->{'status'});
|
343 |
|
|
}
|
344 |
|
|
$res .= $t2->draw;
|
345 |
|
|
} elsif ($console && !$uuidfilter && $action ne 'jsonlist') {
|
346 |
|
|
$res .= Dumper(\@curregvalues);
|
347 |
|
|
} else {
|
348 |
|
|
my $json_text;
|
349 |
|
|
if ($uuidfilter) {
|
350 |
|
|
$json_text = to_json($curregvalues[0], {pretty => 1}) if (@curregvalues);
|
351 |
|
|
} else {
|
352 |
|
|
$json_text = to_json(\@curregvalues, {pretty => 1}) if (@curregvalues);
|
353 |
|
|
}
|
354 |
|
|
$json_text = "[]" unless $json_text;
|
355 |
|
|
$json_text =~ s/""/"--"/g;
|
356 |
|
|
$json_text =~ s/null/"--"/g;
|
357 |
|
|
$json_text =~ s/undef/"--"/g;
|
358 |
|
|
$json_text =~ s/\x/ /g;
|
359 |
|
|
$res .= qq|{"action": "$action", "identifier": "uuid", "label": "name", "items": | if ($action && $action ne 'jsonlist' && $action ne 'list' && !$uuidfilter);
|
360 |
|
|
$res .= $json_text;
|
361 |
|
|
$res .= qq|}| if ($action && $action ne 'jsonlist' && $action ne 'list' && !$uuidfilter);
|
362 |
|
|
# $res .= "JSON" if (action eq 'jsonlist');
|
363 |
|
|
}
|
364 |
|
|
return $res;
|
365 |
|
|
}
|
366 |
|
|
|
367 |
|
|
sub do_uuidlookup {
|
368 |
|
|
if ($help) {
|
369 |
|
|
return <<END
|
370 |
|
|
GET:uuid:
|
371 |
|
|
Simple action for looking up a uuid or part of a uuid and returning the complete uuid.
|
372 |
|
|
END
|
373 |
|
|
}
|
374 |
|
|
|
375 |
|
|
my $res;
|
376 |
|
|
$res .= header('text/plain') unless $console;
|
377 |
|
|
my $u = $options{u};
|
378 |
|
|
$u = $curuuid unless ($u || $u eq '0');
|
379 |
|
|
my $ruuid;
|
380 |
|
|
if ($u || $u eq '0') {
|
381 |
|
|
foreach my $uuid (keys %register) {
|
382 |
|
|
if (($register{$uuid}->{'user'} eq $user || $register{$uuid}->{'user'} eq 'common' || $fulllist)
|
383 |
|
|
&& ($uuid =~ /^$u/ || $register{$uuid}->{'name'} =~ /^$u/)) {
|
384 |
|
|
$ruuid = $uuid;
|
385 |
|
|
last;
|
386 |
|
|
}
|
387 |
|
|
}
|
388 |
|
|
if (!$ruuid && $isadmin) { # If no match and user is admin, do comprehensive lookup
|
389 |
|
|
foreach $uuid (keys %register) {
|
390 |
|
|
if ($uuid =~ /^$u/ || $register{$uuid}->{'name'} =~ /^$u/) {
|
391 |
|
|
$ruuid = $uuid;
|
392 |
|
|
last;
|
393 |
|
|
}
|
394 |
|
|
}
|
395 |
|
|
}
|
396 |
|
|
}
|
397 |
|
|
$res .= "$ruuid\n" if ($ruuid);
|
398 |
|
|
return $res;
|
399 |
|
|
}
|
400 |
|
|
|
401 |
|
|
sub do_uuidshow {
|
402 |
|
|
if ($help) {
|
403 |
|
|
return <<END
|
404 |
|
|
GET:uuid:
|
405 |
|
|
Simple action for showing a single network.
|
406 |
|
|
END
|
407 |
|
|
}
|
408 |
|
|
|
409 |
|
|
my $res;
|
410 |
|
|
$res .= header('application/json') unless $console;
|
411 |
|
|
my $u = $options{u};
|
412 |
|
|
$u = $curuuid unless ($u || $u eq '0');
|
413 |
|
|
if ($u || $u eq '0') {
|
414 |
|
|
foreach my $uuid (keys %register) {
|
415 |
|
|
if (($register{$uuid}->{'user'} eq $user || $register{$uuid}->{'user'} eq 'common' || index($privileges,"a")!=-1)
|
416 |
|
|
&& $uuid =~ /^$u/) {
|
417 |
|
|
my %hash = %{$register{$uuid}};
|
418 |
|
|
delete $hash{'action'};
|
419 |
|
|
delete $hash{'nextid'};
|
420 |
|
|
# my $dump = Dumper(\%hash);
|
421 |
|
|
my $dump = to_json(\%hash, {pretty=>1});
|
422 |
|
|
$dump =~ s/undef/"--"/g;
|
423 |
|
|
$res .= $dump;
|
424 |
|
|
last;
|
425 |
|
|
}
|
426 |
|
|
}
|
427 |
|
|
}
|
428 |
|
|
return $res;
|
429 |
|
|
}
|
430 |
|
|
|
431 |
|
|
sub do_updateui {
|
432 |
|
|
my ($uuid, $action) = @_;
|
433 |
|
|
if ($help) {
|
434 |
|
|
return <<END
|
435 |
|
|
GET:uuid:
|
436 |
|
|
Update the web UI for the given uuid (if user has web UI loaded).
|
437 |
|
|
END
|
438 |
|
|
}
|
439 |
|
|
|
440 |
|
|
my $res;
|
441 |
|
|
$res .= header('text/plain') unless $console;
|
442 |
|
|
if ($register{$uuid}) {
|
443 |
|
|
my $uistatus = $register{$uuid}->{'status'};
|
444 |
|
|
$main::updateUI->({tab=>"networks", user=>$user, uuid=>$uuid, status=>$uistatus});
|
445 |
|
|
$res .= "Status=OK Updated UI for $register{$uuid}->{'type'} $register{$uuid}->{'name'}: $uistatus";
|
446 |
|
|
} else {
|
447 |
|
|
$main::updateUI->({tab=>"networks", user=>$user});
|
448 |
|
|
$res .= "Status=OK Updated networks UI for $user";
|
449 |
|
|
}
|
450 |
|
|
return $res;
|
451 |
|
|
|
452 |
|
|
}
|
453 |
|
|
|
454 |
eb31fb38
|
hq
|
sub do_dnslist {
|
455 |
95b003ff
|
Origo
|
my ($uuid, $action) = @_;
|
456 |
|
|
if ($help) {
|
457 |
|
|
return <<END
|
458 |
eb31fb38
|
hq
|
GET:domain:
|
459 |
|
|
Lists entries in [domain] or if not specified, the default zone: $dnsdomain.
|
460 |
95b003ff
|
Origo
|
END
|
461 |
|
|
}
|
462 |
|
|
|
463 |
eb31fb38
|
hq
|
my $res = $main::dnsList->($engineid, $user, $params{'domain'});
|
464 |
95b003ff
|
Origo
|
return $res;
|
465 |
|
|
}
|
466 |
|
|
|
467 |
705b5366
|
hq
|
sub do_envdump {
|
468 |
|
|
my ($uuid, $action) = @_;
|
469 |
|
|
if ($help) {
|
470 |
|
|
return <<END
|
471 |
|
|
GET::
|
472 |
|
|
Dump environment variables
|
473 |
|
|
END
|
474 |
|
|
}
|
475 |
|
|
return to_json(\%ENV, {pretty=>1});
|
476 |
|
|
}
|
477 |
|
|
|
478 |
|
|
|
479 |
eb31fb38
|
hq
|
sub do_dnscreate {
|
480 |
48fcda6b
|
Origo
|
my ($uuid, $action) = @_;
|
481 |
|
|
if ($help) {
|
482 |
|
|
return <<END
|
483 |
eb31fb38
|
hq
|
GET:name, value, type:
|
484 |
|
|
Create a DNS record in the the subdomain belonging to the user's default DNS domain.
|
485 |
|
|
<b>name</b> is a domain name in the Engine's zone. <b>value</b> is either an IP address for A records or a domain name for other. <b>[type]</b> is A, CNAME, TXT or MX.
|
486 |
48fcda6b
|
Origo
|
END
|
487 |
|
|
}
|
488 |
|
|
|
489 |
eb31fb38
|
hq
|
my $res = $main::dnsCreate->($engineid, $params{'name'}, $params{'value'}, $params{'type'}, $user);
|
490 |
48fcda6b
|
Origo
|
return $res;
|
491 |
|
|
}
|
492 |
|
|
|
493 |
eb31fb38
|
hq
|
sub do_dnsupdate {
|
494 |
|
|
my ($uuid, $action, $obj) = @_;
|
495 |
e9af6c24
|
Origo
|
if ($help) {
|
496 |
|
|
return <<END
|
497 |
eb31fb38
|
hq
|
GET:name,value,type,oldname,oldvalue:
|
498 |
|
|
Updates CNAME records pointing to a A record with value 'value', to point to the new 'name' in the the default DNS domain.
|
499 |
e9af6c24
|
Origo
|
END
|
500 |
|
|
}
|
501 |
|
|
|
502 |
eb31fb38
|
hq
|
my $res = $main::dnsUpdate->($engineid, $obj->{'name'}, $obj->{'value'}, $obj->{'type'}, $obj->{'oldname'}, $obj->{'oldvalue'}, $user);
|
503 |
e9af6c24
|
Origo
|
return $res;
|
504 |
|
|
}
|
505 |
|
|
|
506 |
|
|
sub do_dnsclean {
|
507 |
|
|
my ($uuid, $action) = @_;
|
508 |
|
|
if ($help) {
|
509 |
|
|
return <<END
|
510 |
|
|
GET::
|
511 |
|
|
Remove this engines entries in $dnsdomain zone.
|
512 |
|
|
END
|
513 |
|
|
}
|
514 |
|
|
|
515 |
|
|
my $res;
|
516 |
|
|
$res .= header('text/plain') unless $console;
|
517 |
|
|
$res .= $main::dnsClean->($engineid, $user);
|
518 |
|
|
return $res;
|
519 |
|
|
}
|
520 |
|
|
|
521 |
95b003ff
|
Origo
|
sub do_dnscheck {
|
522 |
|
|
my ($uuid, $action) = @_;
|
523 |
|
|
if ($help) {
|
524 |
|
|
return <<END
|
525 |
|
|
GET:name:
|
526 |
|
|
Checks if a domain name (name[.subdomain]) is available, i.e. not registered,
|
527 |
|
|
where subdomain is the subdomain belonging to the the registering engine.
|
528 |
|
|
END
|
529 |
|
|
}
|
530 |
|
|
|
531 |
|
|
my $res;
|
532 |
|
|
$res .= header('text/plain') unless $console;
|
533 |
|
|
my $name = $params{'name'};
|
534 |
|
|
$name = $1 if ($name =~ /(.+)\.$dnsdomain$/);
|
535 |
48fcda6b
|
Origo
|
if (!$enginelinked) {
|
536 |
|
|
$res .= "Status=ERROR You cannot create DNS records - your engine is not linked.\n";
|
537 |
|
|
} elsif ($name =~ /^\S+$/ && !(`host $name.$dnsdomain authns1.cabocomm.dk` =~ /has address/)
|
538 |
95b003ff
|
Origo
|
&& $name ne 'www'
|
539 |
|
|
&& $name ne 'mail'
|
540 |
|
|
&& $name ne 'info'
|
541 |
|
|
&& $name ne 'admin'
|
542 |
|
|
&& $name ne 'work'
|
543 |
|
|
&& $name ne 'io'
|
544 |
|
|
&& $name ne 'cloud'
|
545 |
|
|
&& $name ne 'compute'
|
546 |
|
|
&& $name ne 'sso'
|
547 |
|
|
&& $name !~ /valve/
|
548 |
|
|
) {
|
549 |
|
|
$res .= "Status=OK $name.$dnsdomain is available\n";
|
550 |
|
|
} else {
|
551 |
|
|
$res .= "Status=ERROR $name.$dnsdomain is not available\n";
|
552 |
|
|
}
|
553 |
|
|
return $res;
|
554 |
|
|
}
|
555 |
|
|
|
556 |
|
|
sub do_dnsdelete {
|
557 |
|
|
my ($uuid, $action) = @_;
|
558 |
|
|
if ($help) {
|
559 |
|
|
return <<END
|
560 |
ca937547
|
hq
|
GET:name, value, type:
|
561 |
95b003ff
|
Origo
|
Delete a DNS record in the configured zone.
|
562 |
|
|
END
|
563 |
|
|
}
|
564 |
|
|
|
565 |
ca937547
|
hq
|
my $res = $main::dnsDelete->($engineid, $params{'name'}, $params{'value'}, $params{'type'}, $user);
|
566 |
95b003ff
|
Origo
|
return $res;
|
567 |
|
|
}
|
568 |
|
|
|
569 |
|
|
sub do_getappstoreurl {
|
570 |
|
|
my ($uuid, $action) = @_;
|
571 |
|
|
if ($help) {
|
572 |
|
|
return <<END
|
573 |
|
|
GET::
|
574 |
45cc3024
|
hq
|
Get URL to the app store belonging to engine or user (uverrides engine default).
|
575 |
95b003ff
|
Origo
|
END
|
576 |
|
|
}
|
577 |
|
|
|
578 |
|
|
my $res;
|
579 |
|
|
# $res .= header('application/json') unless $console;
|
580 |
|
|
# $res .= qq|{"url": "$appstoreurl"}\n|;
|
581 |
|
|
$res .= "$appstoreurl\n";
|
582 |
|
|
return $res;
|
583 |
|
|
}
|
584 |
|
|
|
585 |
eb31fb38
|
hq
|
sub do_listdnsdomains {
|
586 |
|
|
my ($uuid, $action) = @_;
|
587 |
|
|
if ($help) {
|
588 |
|
|
return <<END
|
589 |
|
|
GET::
|
590 |
|
|
Get the DNS domains current user has access to.
|
591 |
|
|
END
|
592 |
|
|
}
|
593 |
|
|
unless ( tie(%userreg,'Tie::DBI', Hash::Merge::merge({table=>'users', key=>'username', CLOBBER=>1}, $Stabile::dbopts)) ) {return 0};
|
594 |
|
|
my $billto = $userreg{$user}->{'billto'};
|
595 |
|
|
my $bdomains = ($userreg{$billto})?$userreg{$billto}->{'dnsdomains'}:'';
|
596 |
|
|
my $domains = ($enginelinked)?($userreg{$user}->{'dnsdomains'} || $bdomains || $dnsdomain) :'';
|
597 |
|
|
untie %userreg;
|
598 |
|
|
my @doms = split(/, ?/, $domains);
|
599 |
|
|
my $subdomain = ($enginelinked)?substr($engineid, 0, 8):'';
|
600 |
|
|
my $linked = ($enginelinked)?'true':'false';
|
601 |
|
|
my $res;
|
602 |
|
|
$res .= header('application/json') unless $console;
|
603 |
|
|
$res .= qq|{"domains": | . to_json(\@doms) . qq|, "subdomain": "$subdomain", "enginelinked": "$linked", "billto": "$billto", "user": "$user"}|;
|
604 |
|
|
return $res;
|
605 |
|
|
}
|
606 |
|
|
|
607 |
95b003ff
|
Origo
|
sub do_getdnsdomain {
|
608 |
|
|
my ($uuid, $action) = @_;
|
609 |
|
|
if ($help) {
|
610 |
|
|
return <<END
|
611 |
|
|
GET::
|
612 |
eb31fb38
|
hq
|
Get the default DNS domain and the subdomain this Engine registers entries in.
|
613 |
95b003ff
|
Origo
|
END
|
614 |
|
|
}
|
615 |
e9af6c24
|
Origo
|
my $domain = ($enginelinked)?$dnsdomain:'';
|
616 |
|
|
my $subdomain = ($enginelinked)?substr($engineid, 0, 8):'';
|
617 |
|
|
my $linked = ($enginelinked)?'true':'false';
|
618 |
95b003ff
|
Origo
|
my $res;
|
619 |
e9af6c24
|
Origo
|
$res .= header('application/json') unless $console;
|
620 |
|
|
$res .= qq|{"domain": "$domain", "subdomain": "$subdomain", "enginelinked": "$linked"}|;
|
621 |
95b003ff
|
Origo
|
return $res;
|
622 |
|
|
}
|
623 |
|
|
|
624 |
|
|
sub xmppsend {
|
625 |
|
|
my ($uuid, $action) = @_;
|
626 |
|
|
if ($help) {
|
627 |
|
|
return <<END
|
628 |
|
|
GET:to, msg:
|
629 |
|
|
Send out an xmpp alert.
|
630 |
|
|
END
|
631 |
|
|
}
|
632 |
|
|
if ($help) {
|
633 |
|
|
return <<END
|
634 |
|
|
Send out an xmpp alert
|
635 |
|
|
END
|
636 |
|
|
}
|
637 |
|
|
|
638 |
|
|
my $res;
|
639 |
|
|
$res .= header('text/plain') unless $console;
|
640 |
|
|
$res .= $main::xmppSend->($params{'to'}, $params{'msg'}, $engineid);
|
641 |
|
|
return $res;
|
642 |
|
|
}
|
643 |
|
|
|
644 |
|
|
# List available network types. Possibly limited by exhausted IP ranges.
|
645 |
|
|
sub do_listnetworktypes {
|
646 |
|
|
if ($help) {
|
647 |
|
|
return <<END
|
648 |
|
|
GET::
|
649 |
|
|
List available network types. Possibly limited by exhausted IP ranges.
|
650 |
|
|
END
|
651 |
|
|
}
|
652 |
|
|
|
653 |
|
|
my $res;
|
654 |
|
|
$res .= header('application/json') unless $console;
|
655 |
|
|
# Check if we have exhausted our IP ranges
|
656 |
|
|
my $intipavail = getNextInternalIP();
|
657 |
|
|
my $extipavail = getNextExternalIP();
|
658 |
|
|
my $arpipavail = getNextExternalIP('','',1);
|
659 |
|
|
my $json_text;
|
660 |
|
|
$json_text .= '{"type": "gateway", "name": "Gateway"}, ';
|
661 |
|
|
$json_text .= '{"type": "internalip", "name": "Internal IP"}, ' if ($intipavail);
|
662 |
|
|
unless (overQuotas()) {
|
663 |
|
|
$json_text .= '{"type": "ipmapping", "name": "IP mapping"}, ' if ($intipavail && $extipavail);
|
664 |
|
|
$json_text .= '{"type": "externalip", "name": "External IP"}, 'if ($arpipavail);
|
665 |
|
|
}
|
666 |
|
|
$json_text = substr($json_text,0,-2);
|
667 |
|
|
$res .= '{"identifier": "type", "label": "name", "items": [' . $json_text . ']}';
|
668 |
|
|
return $res;
|
669 |
|
|
}
|
670 |
|
|
|
671 |
|
|
# Simple action for removing all networks belonging to a user
|
672 |
|
|
sub do_removeusernetworks {
|
673 |
|
|
my ($uuid, $action) = @_;
|
674 |
|
|
|
675 |
|
|
if ($help) {
|
676 |
|
|
return <<END
|
677 |
|
|
GET::
|
678 |
|
|
Remove all networks belonging to a user.
|
679 |
|
|
END
|
680 |
|
|
}
|
681 |
|
|
|
682 |
|
|
my $res;
|
683 |
|
|
$res .= header('text/plain') unless $console;
|
684 |
|
|
if ($readonly) {
|
685 |
|
|
$postreply .= "Status=ERROR Not allowed\n";
|
686 |
|
|
} else {
|
687 |
|
|
Removeusernetworks($user);
|
688 |
|
|
}
|
689 |
|
|
$res .= $postreply || "Status=OK Nothing to remove\n";
|
690 |
|
|
return $res;
|
691 |
|
|
}
|
692 |
|
|
|
693 |
|
|
# Activate all networks. If restoreall (e.g. after reboot) is called, we only activate networks which have entries in /etc/stabile/network
|
694 |
|
|
sub Activateall {
|
695 |
|
|
my ($nouuid, $action) = @_;
|
696 |
|
|
if ($help) {
|
697 |
|
|
return <<END
|
698 |
|
|
GET::
|
699 |
|
|
Tries to activate all networks. If called as restoreall by an admin, will try to restore all user's networks to saved state, e.g. after a reboot.
|
700 |
|
|
END
|
701 |
|
|
}
|
702 |
|
|
my @regkeys;
|
703 |
|
|
if (($action eq "restoreall" || $fulllist) && index($privileges,"a")!=-1) { # Only an administrator is allowed to do this
|
704 |
|
|
@regkeys = keys %register;
|
705 |
|
|
} else {
|
706 |
|
|
@regkeys = (tied %register)->select_where("user='$user'");
|
707 |
|
|
}
|
708 |
|
|
my $i = 0;
|
709 |
|
|
if (!$isreadonly) {
|
710 |
|
|
foreach my $key (@regkeys) {
|
711 |
|
|
my $valref = $register{$key};
|
712 |
|
|
my $uuid = $valref->{'uuid'};
|
713 |
|
|
my $type = $valref->{'type'};
|
714 |
|
|
my $id = $valref->{'id'};
|
715 |
|
|
my $name = $valref->{'name'};
|
716 |
|
|
my $internalip = $valref->{'internalip'};
|
717 |
|
|
my $externalip = $valref->{'externalip'};
|
718 |
|
|
if ($id!=0 && $id!=1 && $id<4095) {
|
719 |
|
|
my $caction = "nat";
|
720 |
|
|
if (-e "$etcpath/dhcp-hosts-$id") {
|
721 |
|
|
if ($action eq "restoreall" && $isadmin) { # If restoring, only activate previously active networks
|
722 |
|
|
my $hosts;
|
723 |
|
|
$hosts = lc `/bin/cat $etcpath/dhcp-hosts-$id` if (-e "$etcpath/dhcp-hosts-$id");
|
724 |
|
|
$caction = "activate" if ($hosts =~ /($internalip|$externalip)/);
|
725 |
|
|
} elsif ($action eq "activateall") {
|
726 |
|
|
$caction = "activate";
|
727 |
|
|
}
|
728 |
48fcda6b
|
Origo
|
# TODO: investigate why this is necessary - if we don't do it, networks are not activated
|
729 |
|
|
$user = $valref->{'user'};
|
730 |
|
|
do_list($uuid, 'list');
|
731 |
|
|
|
732 |
95b003ff
|
Origo
|
my $res = Activate($uuid, $caction);
|
733 |
|
|
if ($res =~ /\w+=(\w+) / ) {
|
734 |
|
|
$register{$uuid}->{'status'} = $1 unless (uc $1 eq 'ERROR');
|
735 |
|
|
$i ++ unless (uc $1 eq 'ERROR');
|
736 |
|
|
} else {
|
737 |
|
|
$postreply .= "Status=ERROR Cannot $caction $type $name $uuid: $res\n";
|
738 |
|
|
}
|
739 |
|
|
}
|
740 |
|
|
} else {
|
741 |
|
|
$postreply .= "Status=ERROR Cannot $action $type $name\n" unless ($id==0 || $id==1);
|
742 |
|
|
}
|
743 |
|
|
}
|
744 |
|
|
} else {
|
745 |
|
|
$postreply .= "Status=ERROR Problem activating all networks\n";
|
746 |
|
|
}
|
747 |
|
|
if ($postreply =~/Status=ERROR /) {
|
748 |
|
|
$postreply = header('text/plain', '500 Internal Server Error') . $postreply unless $console;
|
749 |
|
|
}
|
750 |
|
|
$postreply .= "Status=OK activated $i networks\n";
|
751 |
|
|
$main::updateUI->({tab=>"networks", user=>$user});
|
752 |
|
|
updateBilling("$action $user");
|
753 |
|
|
return $postreply;
|
754 |
|
|
}
|
755 |
|
|
|
756 |
|
|
# Deactivate all networks
|
757 |
|
|
sub Deactivateall {
|
758 |
|
|
my ($nouuid, $action) = @_;
|
759 |
|
|
if ($help) {
|
760 |
|
|
return <<END
|
761 |
|
|
GET::
|
762 |
|
|
Tries to deactivate all networks. May also be called as natall or stopall.
|
763 |
|
|
END
|
764 |
|
|
}
|
765 |
|
|
|
766 |
|
|
my @regkeys;
|
767 |
|
|
if ($fulllist && index($privileges,"a")!=-1) { # Only an administrator is allowed to do this
|
768 |
|
|
@regkeys = keys %register;
|
769 |
|
|
} else {
|
770 |
|
|
@regkeys = (tied %register)->select_where("user='$user'");
|
771 |
|
|
}
|
772 |
|
|
if (!$isreadonly) {
|
773 |
|
|
my %ids;
|
774 |
|
|
foreach my $key (@regkeys) {
|
775 |
|
|
my $valref = $register{$key};
|
776 |
|
|
my $uuid = $valref->{'uuid'};
|
777 |
|
|
my $type = $valref->{'type'};
|
778 |
|
|
my $id = $valref->{'id'};
|
779 |
|
|
my $name = $valref->{'name'};
|
780 |
|
|
if ($id!=0 && $id!=1 && $id<4095) {
|
781 |
|
|
if (-e "$etcpath/dhcp-hosts-$id") {
|
782 |
|
|
my $caction = "deactivate";
|
783 |
|
|
my $result;
|
784 |
|
|
if ($action eq "stopall") {
|
785 |
|
|
$caction = "stop";
|
786 |
|
|
# Stop also deactivates all networks with same id, so only do this once for each id
|
787 |
|
|
if ($ids{$id}) {
|
788 |
|
|
$result = $valref->{'status'};
|
789 |
|
|
} else {
|
790 |
|
|
$result = Stop($id, $caction);
|
791 |
|
|
}
|
792 |
|
|
$ids{$id} = 1;
|
793 |
|
|
} else {
|
794 |
|
|
my $res = Deactivate($uuid, $caction);
|
795 |
|
|
if ($res =~ /\w+=(\w+) /) {
|
796 |
|
|
$register{$uuid}->{'status'} = $1;
|
797 |
|
|
} else {
|
798 |
|
|
$postreply .= "Status=ERROR Cannot $caction $type $name $uuid: $res\n";
|
799 |
|
|
}
|
800 |
|
|
}
|
801 |
|
|
if ($result =~ /\w+=(.\w+) /) {
|
802 |
|
|
$register{$uuid}->{'status'} = $uistatus = $1;
|
803 |
|
|
$uiuuid = $uuid;
|
804 |
|
|
$postreply .= "Status=OK $caction $type $name $uuid\n";
|
805 |
|
|
$main::syslogit->($user, "info", "$caction network $uuid ($id) ");
|
806 |
|
|
}
|
807 |
|
|
}
|
808 |
|
|
} else {
|
809 |
|
|
$postreply .= "Status=ERROR Cannot $action $type $name\n" unless ($id==0 || $id==1);
|
810 |
|
|
}
|
811 |
|
|
}
|
812 |
|
|
} else {
|
813 |
|
|
$postreply .= "Status=ERROR Problem deactivating all networks\n";
|
814 |
|
|
}
|
815 |
|
|
if ($postreply =~/Status=ERROR /) {
|
816 |
|
|
$res = header('text/plain', '500 Internal Server Error') unless $console;
|
817 |
|
|
} else {
|
818 |
|
|
$res = header('text/plain') unless $console;
|
819 |
|
|
}
|
820 |
|
|
$main::updateUI->({tab=>"networks", user=>$user});
|
821 |
|
|
updateBilling("$action $user");
|
822 |
|
|
return $postreply;
|
823 |
|
|
}
|
824 |
|
|
|
825 |
|
|
sub do_updatebilling {
|
826 |
|
|
my ($uuid, $action) = @_;
|
827 |
|
|
if ($help) {
|
828 |
|
|
return <<END
|
829 |
|
|
GET:uuid:
|
830 |
|
|
Update network billing for current user.
|
831 |
|
|
END
|
832 |
|
|
}
|
833 |
|
|
|
834 |
|
|
my $res;
|
835 |
|
|
$res .= header('text/plain') unless $console;
|
836 |
|
|
if ($isreadonly) {
|
837 |
|
|
$res .= "Status=ERROR Not updating network billing for $user\n";
|
838 |
|
|
} else {
|
839 |
|
|
updateBilling("updatebilling $user");
|
840 |
|
|
$res .= "Status=OK Updated network billing for $user\n";
|
841 |
|
|
}
|
842 |
|
|
return $res;
|
843 |
|
|
}
|
844 |
|
|
|
845 |
|
|
# Print list of available actions on objects
|
846 |
|
|
sub do_plainhelp {
|
847 |
|
|
my $res;
|
848 |
|
|
$res .= header('text/plain') unless $console;
|
849 |
|
|
$res .= <<END
|
850 |
|
|
* new [type="ipmapping|internalip|externalip|gateway", name="name"]: Creates a new network
|
851 |
|
|
* activate: Activates a network. If gateway is down it is brought up.
|
852 |
|
|
* stop: Stops the gateway, effectively stopping network communcation with the outside.
|
853 |
|
|
* deactivate: Deactivates a network. Removes the associated internal IP address from the DHCP service.
|
854 |
|
|
* delete: Deletes a network. Use with care. Network can not be in use.
|
855 |
|
|
|
856 |
|
|
END
|
857 |
|
|
;
|
858 |
|
|
}
|
859 |
|
|
|
860 |
|
|
sub addDHCPAddress {
|
861 |
|
|
my $id = shift;
|
862 |
|
|
my $uuid = shift;
|
863 |
|
|
my $dhcpip = shift;
|
864 |
|
|
my $gateway = shift;
|
865 |
|
|
my $mac = lc shift;
|
866 |
|
|
my $isexternal = !($dhcpip =~ /^10\./);
|
867 |
|
|
my $options;
|
868 |
|
|
my $interface = "br$id"; #,$extnic.$id
|
869 |
|
|
$options = "--strict-order --bind-interfaces --except-interface=lo --interface=$interface " .
|
870 |
|
|
($proxyip?"--dhcp-range=tag:external,$proxyip,static ":"") .
|
871 |
|
|
"--pid-file=/var/run/stabile-$id.pid --dhcp-hostsfile=$etcpath/dhcp-hosts-$id --dhcp-range=tag:internal,$gateway,static " .
|
872 |
|
|
"--dhcp-optsfile=$etcpath/dhcp-options-$id --port=0 --log-dhcp";
|
873 |
|
|
|
874 |
|
|
my $running;
|
875 |
|
|
my $error;
|
876 |
|
|
my $psid;
|
877 |
|
|
return "Status=ERROR Empty mac or ip when configuing dhcp for $name" unless ($mac && $dhcpip);
|
878 |
|
|
|
879 |
|
|
eval {
|
880 |
|
|
$psid = `/bin/cat /var/run/stabile-$id.pid` if (-e "/var/run/stabile-$id.pid");
|
881 |
|
|
chomp $psid;
|
882 |
|
|
$running = -e "/proc/$psid" if ($psid);
|
883 |
|
|
# `/bin/ps p $psid` =~ /$psid/
|
884 |
|
|
# `/bin/ps ax | /bin/grep stabile-$id.pid | /usr/bin/wc -l`; 1;} or do
|
885 |
|
|
1;
|
886 |
|
|
} or do {$error .= "Status=ERROR Problem configuring dhcp for $name $@\n";};
|
887 |
|
|
|
888 |
|
|
if (-e "$etcpath/dhcp-hosts-$id") {
|
889 |
|
|
open(TEMP1, "<$etcpath/dhcp-hosts-$id") || ($error .= "Status=ERROR Problem reading dhcp hosts\n");
|
890 |
|
|
open(TEMP2, ">$etcpath/dhcp-hosts-$id.new") || ($error .= "Status=ERROR Problem writing dhcp hosts $etcpath/dhcp-hosts-$id.new\n");
|
891 |
|
|
while (<TEMP1>) {
|
892 |
|
|
my $line = $_;
|
893 |
|
|
print TEMP2 $line unless (($mac && $line =~ /^$mac/i) || ($line & $line =~ /.+,$dhcpip/));
|
894 |
|
|
}
|
895 |
|
|
print TEMP2 "$mac," . (($isexternal)?"set:external,":"set:internal,") . "$dhcpip\n";
|
896 |
|
|
close(TEMP1);
|
897 |
|
|
close(TEMP2);
|
898 |
|
|
rename("$etcpath/dhcp-hosts-$id", "$etcpath/dhcp-hosts-$id.old") || ($error .= "Status=ERROR Problem writing dhcp hosts\n");
|
899 |
|
|
rename("$etcpath/dhcp-hosts-$id.new", "$etcpath/dhcp-hosts-$id") || ($error .= "Status=ERROR Problem writing dhcp hosts\n");
|
900 |
|
|
} else {
|
901 |
|
|
open(TEMP1, ">$etcpath/dhcp-hosts-$id") || ($error .= "Status=ERROR Problem writing dhcp options\n");
|
902 |
|
|
print TEMP1 "$mac,$dhcpip\n";
|
903 |
|
|
close (TEMP1);
|
904 |
|
|
}
|
905 |
|
|
|
906 |
|
|
# unless (-e "$etcpath/dhcp-options-$id") {
|
907 |
|
|
my $block = new Net::Netmask("$proxygw/$proxysubnet");
|
908 |
|
|
my $proxymask = $block->mask();
|
909 |
|
|
open(TEMP1, ">$etcpath/dhcp-options-$id") || ($error .= "Status=ERROR Problem writing dhcp options\n");
|
910 |
|
|
|
911 |
e837d785
|
hq
|
# Turns out the VM's gateway has to be $proxyip and not $proxygw in our proxyarp setup
|
912 |
95b003ff
|
Origo
|
print TEMP1 <<END;
|
913 |
e837d785
|
hq
|
tag:external,option:router,$proxyip
|
914 |
95b003ff
|
Origo
|
tag:external,option:netmask,$proxymask
|
915 |
|
|
tag:external,option:dns-server,$proxyip
|
916 |
|
|
tag:internal,option:router,$gateway
|
917 |
|
|
tag:internal,option:netmask,255.255.255.0
|
918 |
|
|
tag:internal,option:dns-server,$gateway
|
919 |
|
|
option:dns-server,1.1.1.1
|
920 |
|
|
END
|
921 |
|
|
|
922 |
|
|
close (TEMP1);
|
923 |
|
|
# }
|
924 |
|
|
|
925 |
|
|
if ($running) {
|
926 |
48fcda6b
|
Origo
|
$main::syslogit->($user, 'info', "HUPing dnsmasq 1: $id");
|
927 |
95b003ff
|
Origo
|
eval {`/usr/bin/pkill -HUP -f "stabile-$id.pid"`; 1;} or do {$error .= "Status=ERROR Problem configuring dhcp for $name $@\n";};
|
928 |
|
|
} else {
|
929 |
|
|
eval {`/usr/sbin/dnsmasq $options`;1;} or do {$error .= "Status=ERROR Problem configuring dhcp for $name $@\n";};
|
930 |
|
|
}
|
931 |
e5789be5
|
hq
|
# Allow access to DHCP service
|
932 |
|
|
`iptables -D INPUT -i br$id -p udp -m udp --dport 67 -j ACCEPT`;
|
933 |
|
|
`iptables -I INPUT -i br$id -p udp -m udp --dport 67 -j ACCEPT`;
|
934 |
|
|
# Allow access to DNS service
|
935 |
|
|
`iptables -D INPUT -i br$id -p udp -m udp --dport 53 -j ACCEPT`;
|
936 |
|
|
`iptables -I INPUT -i br$id -p udp -m udp --dport 53 -j ACCEPT`;
|
937 |
|
|
`iptables -D INPUT -i br$id -p tcp -m tcp --dport 53 -j ACCEPT`;
|
938 |
|
|
`iptables -I INPUT -i br$id -p tcp -m tcp --dport 53 -j ACCEPT`;
|
939 |
95b003ff
|
Origo
|
|
940 |
|
|
return $error?$error:"OK";
|
941 |
|
|
}
|
942 |
|
|
|
943 |
|
|
sub removeDHCPAddress {
|
944 |
|
|
my $id = shift;
|
945 |
|
|
my $uuid = shift;
|
946 |
|
|
my $dhcpip = shift;
|
947 |
|
|
my $mac;
|
948 |
|
|
$mac = lc $domreg{$uuid}->{'nicmac1'} if ($domreg{$uuid});
|
949 |
|
|
my $isexternal = ($dhcpip =~ /^10\./);
|
950 |
|
|
my $running;
|
951 |
|
|
my $error;
|
952 |
|
|
my $psid;
|
953 |
|
|
return "Status=ERROR Empty mac or ip when configuring dhcp for $name" unless ($mac || $dhcpip);
|
954 |
|
|
|
955 |
|
|
eval {
|
956 |
|
|
$psid = `/bin/cat /var/run/stabile-$id.pid` if (-e "/var/run/stabile-$id.pid");
|
957 |
|
|
chomp $psid;
|
958 |
|
|
$running = -e "/proc/$psid" if ($psid);
|
959 |
|
|
1;
|
960 |
d3d1a2d4
|
Origo
|
} or do {$error .= "Status=ERROR Problem deconfiguring dhcp for $name $@\n";};
|
961 |
95b003ff
|
Origo
|
|
962 |
|
|
my $keepup;
|
963 |
|
|
if (-e "$etcpath/dhcp-hosts-$id") {
|
964 |
|
|
open(TEMP1, "<$etcpath/dhcp-hosts-$id") || ($error .= "Status=ERROR Problem reading dhcp hosts\n");
|
965 |
|
|
open(TEMP2, ">$etcpath/dhcp-hosts-$id.new") || ($error .= "Status=ERROR Problem writing dhcp hosts\n");
|
966 |
|
|
while (<TEMP1>) {
|
967 |
|
|
my $line = $_; chomp $line;
|
968 |
|
|
if ($line && $line =~ /(.+),.+,($dhcpip)/) { # Release and remove this mac/ip from lease file
|
969 |
80e0b3f5
|
hq
|
$main::syslogit->($user, 'info', "Releasing dhcp lease: br$id $dhcpip $1");
|
970 |
|
|
`/usr/bin/dhcp_release br$id $dhcpip $1`;
|
971 |
95b003ff
|
Origo
|
} elsif ($mac && $line =~ /^$mac/i) {
|
972 |
|
|
# If we find a stale assigment to the mac we are removing, remove this also
|
973 |
80e0b3f5
|
hq
|
$main::syslogit->($user, 'info', "Releasing stale dhcp lease: br$id $dhcpip $mac");
|
974 |
|
|
`/usr/bin/dhcp_release br$id $dhcpip $mac`;
|
975 |
95b003ff
|
Origo
|
} else {
|
976 |
|
|
# Keep all other leases, and keep up the daemon if any leases found
|
977 |
|
|
print TEMP2 "$line\n";
|
978 |
|
|
$keepup = 1 if $line;
|
979 |
|
|
}
|
980 |
|
|
}
|
981 |
|
|
close(TEMP1);
|
982 |
|
|
close(TEMP2);
|
983 |
|
|
rename("$etcpath/dhcp-hosts-$id", "$etcpath/dhcp-hosts-$id.old") || ($error .= "Status=ERROR Problem writing dhcp hosts\n");
|
984 |
|
|
rename("$etcpath/dhcp-hosts-$id.new", "$etcpath/dhcp-hosts-$id") || ($error .= "Status=ERROR Problem writing dhcp hosts\n");
|
985 |
|
|
}
|
986 |
|
|
|
987 |
|
|
if ($keepup) {
|
988 |
|
|
if ($running) {
|
989 |
48fcda6b
|
Origo
|
$main::syslogit->($user, 'info', "HUPing dnsmasq 2: $id");
|
990 |
95b003ff
|
Origo
|
eval {`/usr/bin/pkill -HUP -f "stabile-$id.pid"`; 1;} or do {$error .= "Status=ERROR Problem configuring dhcp for $name $@\n";};
|
991 |
|
|
}
|
992 |
|
|
} else {
|
993 |
|
|
unlink "$etcpath/dhcp-options-$id" if (-e "$etcpath/dhcp-options-$id");
|
994 |
|
|
if ($running) {
|
995 |
e5789be5
|
hq
|
# Disallow access to DHCP service
|
996 |
|
|
`iptables -D INPUT -i br$id -p udp -m udp --dport 67 -j ACCEPT`;
|
997 |
|
|
# Disallow access to DNS service
|
998 |
|
|
`iptables -D INPUT -i br$id -p udp -m udp --dport 53 -j ACCEPT`;
|
999 |
|
|
`iptables -D INPUT -i br$id -p tcp -m tcp --dport 53 -j ACCEPT`;
|
1000 |
95b003ff
|
Origo
|
# Take down dhcp server
|
1001 |
|
|
$main::syslogit->($user, 'info', "Killing dnsmasq 3: $id");
|
1002 |
|
|
eval {`/usr/bin/pkill -f "stabile-$id.pid"`; 1;} or do {$error .= "Status=ERROR Problem configuring dhcp for $name $@\n";};
|
1003 |
|
|
}
|
1004 |
|
|
}
|
1005 |
|
|
|
1006 |
|
|
return $error?$error:"OK";
|
1007 |
|
|
}
|
1008 |
|
|
|
1009 |
|
|
# Helper function
|
1010 |
|
|
sub save {
|
1011 |
|
|
my ($id, $uuid, $name, $status, $type, $internalip, $externalip, $ports, $buildsystem, $username) = @_;
|
1012 |
|
|
my $obj = {
|
1013 |
|
|
id => $id,
|
1014 |
|
|
uuid => $uuid,
|
1015 |
|
|
name => $name,
|
1016 |
|
|
status => $status,
|
1017 |
|
|
type => $type,
|
1018 |
|
|
internalip => $internalip,
|
1019 |
|
|
externalip => $externalip,
|
1020 |
|
|
ports => $ports,
|
1021 |
|
|
buildsystem => $buildsystem,
|
1022 |
|
|
username => $username
|
1023 |
|
|
};
|
1024 |
|
|
return Save($uuid, 'save', $obj);
|
1025 |
|
|
}
|
1026 |
|
|
|
1027 |
|
|
sub Save {
|
1028 |
|
|
my ($uuid, $action, $obj) = @_;
|
1029 |
|
|
if ($help) {
|
1030 |
|
|
return <<END
|
1031 |
d3d1a2d4
|
Origo
|
POST:uuid, id, name, internalip, externalip, ports, type, systems, activate:
|
1032 |
95b003ff
|
Origo
|
To save a collection of networks you either PUT or POST a JSON array to the main endpoint with objects representing the networks with the changes you want.
|
1033 |
|
|
Depending on your privileges not all changes are permitted. If you save without specifying a uuid, a new network is created.
|
1034 |
d3d1a2d4
|
Origo
|
For now, [activate] only has effect when creating a new connection with a linked system/server.
|
1035 |
95b003ff
|
Origo
|
END
|
1036 |
|
|
}
|
1037 |
d3d1a2d4
|
Origo
|
$uuid = $obj->{'uuid'} if ($obj->{'uuid'});
|
1038 |
04c16f26
|
hq
|
my $regnet = $register{$uuid};
|
1039 |
95b003ff
|
Origo
|
my $id = $obj->{id};
|
1040 |
|
|
my $name = $obj->{name};
|
1041 |
|
|
my $status = $obj->{status};
|
1042 |
04c16f26
|
hq
|
my $type = $obj->{type} || $regnet->{type};
|
1043 |
95b003ff
|
Origo
|
my $internalip = $obj->{internalip};
|
1044 |
|
|
my $externalip = $obj->{externalip};
|
1045 |
|
|
my $ports = $obj->{ports};
|
1046 |
|
|
my $buildsystem = $obj->{buildsystem};
|
1047 |
|
|
my $username = $obj->{username};
|
1048 |
d3d1a2d4
|
Origo
|
my $systems = $obj->{systems}; # Optionally link this network to a system
|
1049 |
95b003ff
|
Origo
|
|
1050 |
|
|
$postreply = "" if ($buildsystem);
|
1051 |
|
|
$username = $user unless ($username);
|
1052 |
|
|
|
1053 |
|
|
$status = $regnet->{'status'} || $status; # Trust db status if it exists
|
1054 |
|
|
if ((!$uuid && $uuid ne '0') && $status eq 'new') {
|
1055 |
|
|
my $ug = new Data::UUID;
|
1056 |
|
|
$uuid = $ug->create_str();
|
1057 |
|
|
};
|
1058 |
|
|
if ($status eq 'new') {
|
1059 |
|
|
$name = 'New Connection' unless ($name);
|
1060 |
|
|
}
|
1061 |
|
|
unless ($uuid && length $uuid == 36) {
|
1062 |
|
|
$postreply .= "Status=Error Invalid uuid $uuid\n";
|
1063 |
|
|
return $postreply;
|
1064 |
|
|
}
|
1065 |
d3d1a2d4
|
Origo
|
my $systemnames = $regnet->{'systemnames'};
|
1066 |
95b003ff
|
Origo
|
|
1067 |
|
|
my $dbid = 0+$regnet->{'id'};
|
1068 |
|
|
if ($status eq 'new' || !$dbid) {
|
1069 |
|
|
$id = getNextId($id) ;
|
1070 |
|
|
} else {
|
1071 |
|
|
$id = $dbid;
|
1072 |
|
|
}
|
1073 |
|
|
if ($id > 4095 || $id < 0 || ($id==0 && $uuid!=0 && $isadmin) || ($id==1 && $uuid!=1 && $isadmin)) {
|
1074 |
|
|
$postreply .= "Status=ERROR Invalid network id $id\n";
|
1075 |
|
|
return $postreply;
|
1076 |
|
|
}
|
1077 |
|
|
$name = $name || $regnet->{'name'};
|
1078 |
|
|
$internalip = $internalip || $regnet->{'internalip'};
|
1079 |
|
|
if (!($internalip =~ /\d+\.\d+\.\d+\.\d+/)) {$internalip = ''};
|
1080 |
|
|
$externalip = $externalip || $regnet->{'externalip'};
|
1081 |
|
|
$ports = $ports || $regnet->{'ports'};
|
1082 |
|
|
my $reguser = $regnet->{'user'};
|
1083 |
|
|
# Sanity checks
|
1084 |
|
|
if (
|
1085 |
|
|
($name && length $name > 255)
|
1086 |
|
|
|| ($ports && length $ports > 255)
|
1087 |
|
|
|| ($type && !($type =~ /gateway|ipmapping|internalip|externalip/))
|
1088 |
|
|
) {
|
1089 |
|
|
$postreply .= "Stroke=ERROR Bad data: $name, $ports, $type\n";
|
1090 |
|
|
return $postreply;
|
1091 |
|
|
}
|
1092 |
|
|
# Security check
|
1093 |
|
|
if (($reguser && $username ne $reguser && !$isadmin ) ||
|
1094 |
|
|
($reguser && $status eq "new"))
|
1095 |
|
|
{
|
1096 |
|
|
$postreply .= "Status=Error Bad user: $username ($status)\n";
|
1097 |
|
|
return $postreply;
|
1098 |
|
|
}
|
1099 |
|
|
|
1100 |
|
|
my $hit = 0;
|
1101 |
|
|
# Check if user is allowed to use network
|
1102 |
|
|
my @regvalues = values %register;
|
1103 |
|
|
foreach my $val (@regvalues) {
|
1104 |
|
|
$dbid = $val->{"id"};
|
1105 |
|
|
$dbuser = $val->{"user"};
|
1106 |
|
|
if ($dbid == $id && $username ne $dbuser && $dbuser ne "common") {
|
1107 |
|
|
$hit = 1;
|
1108 |
|
|
last;
|
1109 |
|
|
}
|
1110 |
|
|
}
|
1111 |
|
|
if ($hit && !$isadmin) { # Network is nogo (unless you are an admin)
|
1112 |
|
|
$postreply .= "Status=ERROR Network id $id not available\n";
|
1113 |
|
|
return $postreply;
|
1114 |
|
|
} elsif (!$type) {
|
1115 |
|
|
$postreply .= "Status=ERROR Network must have a type\n";
|
1116 |
|
|
return $postreply;
|
1117 |
|
|
} elsif ($status eq 'down' || $status eq 'new' || $status eq 'nat') {
|
1118 |
|
|
# Check if network has been modified or is new
|
1119 |
|
|
if ($regnet->{'id'} ne $id ||
|
1120 |
|
|
$regnet->{'name'} ne $name ||
|
1121 |
|
|
$regnet->{'type'} ne $type ||
|
1122 |
|
|
$regnet->{'internalip'} ne $internalip ||
|
1123 |
|
|
$regnet->{'externalip'} ne $externalip ||
|
1124 |
d3d1a2d4
|
Origo
|
$regnet->{'systems'} ne $systems ||
|
1125 |
95b003ff
|
Origo
|
$regnet->{'ports'} ne $ports)
|
1126 |
|
|
{
|
1127 |
|
|
if ($type eq "externalip") {
|
1128 |
|
|
$internalip = "--";
|
1129 |
|
|
$externalip = getNextExternalIP($externalip, $uuid, 1);
|
1130 |
|
|
if (!$externalip) {
|
1131 |
|
|
$postreply .= "Status=ERROR Unable to allocate external proxy IP for $name\n";
|
1132 |
|
|
$externalip = "--";
|
1133 |
|
|
$internalip = getNextInternalIP($internalip, $uuid, $id);
|
1134 |
|
|
$type = "internalip";
|
1135 |
|
|
} else {
|
1136 |
|
|
$postreply .= "Status=OK Allocated external IP: $externalip\n" unless ($regnet->{'externalip'} eq $externalip);
|
1137 |
|
|
if ($dodns) {
|
1138 |
e9af6c24
|
Origo
|
$main::dnsCreate->($engineid, $externalip, $externalip, 'A', $user);
|
1139 |
95b003ff
|
Origo
|
}
|
1140 |
|
|
}
|
1141 |
|
|
|
1142 |
|
|
} elsif ($type eq "ipmapping") {
|
1143 |
|
|
$externalip = getNextExternalIP($externalip, $uuid);
|
1144 |
|
|
if (!$externalip) {
|
1145 |
|
|
$postreply .= "Status=ERROR Unable to allocate external IP for $name\n";
|
1146 |
|
|
$externalip = "--";
|
1147 |
|
|
$type = "internalip";
|
1148 |
|
|
} else {
|
1149 |
|
|
$postreply .= "Status=OK Allocated external IP: $externalip\n" unless ($regnet->{'externalip'} eq $externalip);
|
1150 |
|
|
if ($dodns) {
|
1151 |
eb31fb38
|
hq
|
$postreply .= "Status=OK Trying to register DNS ";
|
1152 |
|
|
$main::dnsCreate->($engineid, $externalip, $externalip, 'A', $user);
|
1153 |
95b003ff
|
Origo
|
}
|
1154 |
|
|
}
|
1155 |
|
|
$internalip = getNextInternalIP($internalip, $uuid, $id);
|
1156 |
|
|
if (!$internalip) {
|
1157 |
|
|
$postreply .= "Status=ERROR Unable to allocate internal IP for $name\n";
|
1158 |
|
|
$internalip = "--";
|
1159 |
|
|
$type = "gateway";
|
1160 |
|
|
} else {
|
1161 |
|
|
$postreply .= "Status=OK Allocated internal IP: $internalip for $name\n" unless ($regnet->{'internalip'} eq $internalip);
|
1162 |
|
|
}
|
1163 |
|
|
|
1164 |
|
|
} elsif ($type eq "internalip") {
|
1165 |
|
|
$externalip = "--";
|
1166 |
|
|
$ports = "--";
|
1167 |
|
|
my $ointip = $internalip;
|
1168 |
|
|
$internalip = getNextInternalIP($internalip, $uuid, $id);
|
1169 |
|
|
if (!$internalip) {
|
1170 |
|
|
$postreply .= "Status=ERROR Unable to allocate internal IP $internalip ($id, $uuid, $ointip) for $name\n";
|
1171 |
|
|
$internalip = "--";
|
1172 |
|
|
$type = "gateway";
|
1173 |
|
|
} else {
|
1174 |
d3d1a2d4
|
Origo
|
$postreply .= "Status=OK Allocated internal IP: $internalip for $name\n" unless ($regnet->{'internalip'} eq $internalip);
|
1175 |
95b003ff
|
Origo
|
}
|
1176 |
|
|
|
1177 |
|
|
} elsif ($type eq "gateway") {
|
1178 |
|
|
# $internalip = "--";
|
1179 |
|
|
# $externalip = "--";
|
1180 |
|
|
# $ports = "--";
|
1181 |
|
|
} else {
|
1182 |
|
|
$postreply .= "Status=ERROR Network must have a valid type\n";
|
1183 |
|
|
return $postreply;
|
1184 |
|
|
}
|
1185 |
|
|
# Validate ports
|
1186 |
|
|
my @portslist = split(/, ?| /, $ports);
|
1187 |
|
|
if ($ports ne "--") {
|
1188 |
|
|
foreach my $port (@portslist) {
|
1189 |
|
|
my $p = $port; # Make a copy of var
|
1190 |
|
|
if ($p =~ /(\d+\.\d+\.\d+\.\d+):(\d+)/) {
|
1191 |
|
|
$p = $2;
|
1192 |
|
|
};
|
1193 |
|
|
$p = 0 unless ($p =~ /\d+/);
|
1194 |
|
|
if ($p<1 || $p>65535) {
|
1195 |
|
|
$postreply .= "Status=ERROR Invalid port mapping for $name\n";
|
1196 |
|
|
$ports = "--";
|
1197 |
|
|
last;
|
1198 |
|
|
}
|
1199 |
|
|
}
|
1200 |
|
|
}
|
1201 |
|
|
if ($ports ne "--") {
|
1202 |
|
|
$ports = join(',', @portslist);
|
1203 |
|
|
}
|
1204 |
d3d1a2d4
|
Origo
|
if ($systems ne $regnet->{'systems'}) {
|
1205 |
|
|
my $regsystems = $regnet->{'systems'};
|
1206 |
|
|
unless (tie(%sysreg,'Tie::DBI', Hash::Merge::merge({table=>'systems'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access systems register"}|; return $res;};
|
1207 |
|
|
|
1208 |
|
|
# Remove existing link to system
|
1209 |
|
|
if ($sysreg{$regsystems}) {
|
1210 |
|
|
$sysreg{$regsystems}->{'networkuuids'} =~ s/$uuid,? ?//;
|
1211 |
|
|
$sysreg{$regsystems}->{'networknames'} = s/$regnet->{'name'},? ?//;
|
1212 |
|
|
} elsif ($domreg{$regsystems}) {
|
1213 |
|
|
$domreg{$regsystems}->{'networkuuids'} =~ s/$uuid,? ?//;
|
1214 |
|
|
$domreg{$regsystems}->{'networknames'} = s/$regnet->{'name'},? ?//;
|
1215 |
|
|
}
|
1216 |
|
|
if ($systems) {
|
1217 |
|
|
if ($sysreg{$systems}) { # Add new link to system
|
1218 |
|
|
$sysreg{$systems}->{'networkuuids'} .= (($sysreg{$systems}->{'networkuuids'}) ? ',' : '') . $uuid;
|
1219 |
|
|
$sysreg{$systems}->{'networknames'} .= (($sysreg{$systems}->{'networknames'}) ? ',' : '') . $name;
|
1220 |
|
|
$systemnames = $sysreg{$systems}->{'name'};
|
1221 |
|
|
} elsif ($domreg{$systems}) {
|
1222 |
|
|
$domreg{$systems}->{'networkuuids'} .= (($domreg{$systems}->{'networkuuids'}) ? ',' : '') . $uuid;
|
1223 |
|
|
$domreg{$systems}->{'networknames'} .= (($domreg{$systems}->{'networknames'}) ? ',' : '') . $name;
|
1224 |
|
|
$systemnames = $domreg{$systems}->{'name'};
|
1225 |
|
|
} else {
|
1226 |
|
|
$systems = '';
|
1227 |
|
|
}
|
1228 |
|
|
}
|
1229 |
|
|
tied(%sysreg)->commit;
|
1230 |
|
|
untie(%sysreg);
|
1231 |
|
|
}
|
1232 |
95b003ff
|
Origo
|
$register{$uuid} = {
|
1233 |
|
|
uuid=>$uuid,
|
1234 |
|
|
user=>$username,
|
1235 |
|
|
id=>$id,
|
1236 |
|
|
name=>$name,
|
1237 |
|
|
internalip=>$internalip,
|
1238 |
|
|
externalip=>$externalip,
|
1239 |
|
|
ports=>$ports,
|
1240 |
|
|
type=>$type,
|
1241 |
d3d1a2d4
|
Origo
|
systems=>$systems,
|
1242 |
|
|
systemnames=>$systemnames,
|
1243 |
95b003ff
|
Origo
|
action=>""
|
1244 |
|
|
};
|
1245 |
6fdc8676
|
hq
|
my $res = tied(%register)->commit;
|
1246 |
|
|
my $obj = $register{$uuid};
|
1247 |
95b003ff
|
Origo
|
$postreply .= "Status=OK Network $register{$uuid}->{'name'} saved: $uuid\n";
|
1248 |
|
|
$postreply .= "Status=OK uuid: $uuid\n" if ($console && $status eq 'new');
|
1249 |
|
|
if ($status eq 'new') {
|
1250 |
|
|
validateStatus($register{$uuid});
|
1251 |
d3d1a2d4
|
Origo
|
$postmsg = "Created connection $name";
|
1252 |
|
|
$uiupdatetype = "update";
|
1253 |
95b003ff
|
Origo
|
}
|
1254 |
|
|
updateBilling("allocate $externalip") if (($type eq "ipmapping" || $type eq "externalip") && $externalip && $externalip ne "--");
|
1255 |
|
|
|
1256 |
|
|
} else {
|
1257 |
|
|
$postreply = "Status=OK Network $uuid ($id) unchanged\n";
|
1258 |
|
|
}
|
1259 |
|
|
|
1260 |
|
|
if ($params{'PUTDATA'}) {
|
1261 |
|
|
my %jitem = %{$register{$uuid}};
|
1262 |
|
|
my $json_text = to_json(\%jitem);
|
1263 |
|
|
$json_text =~ s/null/"--"/g;
|
1264 |
|
|
$json_text =~ s/""/"--"/g;
|
1265 |
|
|
$postreply = $json_text;
|
1266 |
d3d1a2d4
|
Origo
|
$postmsg = $postmsg || "OK, updated network $name";
|
1267 |
95b003ff
|
Origo
|
}
|
1268 |
|
|
|
1269 |
|
|
return $postreply;
|
1270 |
|
|
|
1271 |
|
|
} else {
|
1272 |
|
|
if ($id ne $regnet->{'id'} ||
|
1273 |
|
|
$internalip ne $regnet->{'internalip'} || $externalip ne $regnet->{'externalip'}) {
|
1274 |
|
|
return "Status=ERROR Cannot modify active network: $uuid\n";
|
1275 |
|
|
} elsif ($name ne $regnet->{'name'}) {
|
1276 |
|
|
$register{$uuid}->{'name'} = $name;
|
1277 |
|
|
$postreply .= "Status=OK Network \"$register{$uuid}->{'name'}\" saved: $uuid\n";
|
1278 |
|
|
if ($params{'PUTDATA'}) {
|
1279 |
|
|
my %jitem = %{$register{$uuid}};
|
1280 |
|
|
my $json_text = to_json(\%jitem);
|
1281 |
|
|
$json_text =~ s/null/"--"/g;
|
1282 |
|
|
$postreply = $json_text;
|
1283 |
d3d1a2d4
|
Origo
|
$postmsg = "OK, updated network $name";
|
1284 |
95b003ff
|
Origo
|
}
|
1285 |
|
|
} else {
|
1286 |
|
|
$postreply .= "Status=OK Nothing to save\n";
|
1287 |
|
|
if ($params{'PUTDATA'}) {
|
1288 |
|
|
my %jitem = %{$register{$uuid}};
|
1289 |
|
|
my $json_text = to_json(\%jitem);
|
1290 |
|
|
$json_text =~ s/null/"--"/g;
|
1291 |
|
|
$postreply = $json_text;
|
1292 |
|
|
}
|
1293 |
|
|
}
|
1294 |
|
|
}
|
1295 |
|
|
|
1296 |
|
|
}
|
1297 |
|
|
|
1298 |
|
|
sub Activate {
|
1299 |
d3d1a2d4
|
Origo
|
my ($uuid, $action, $obj) = @_;
|
1300 |
95b003ff
|
Origo
|
if ($help) {
|
1301 |
|
|
return <<END
|
1302 |
|
|
GET:uuid:
|
1303 |
|
|
Activate a network which must be in status down or nat.
|
1304 |
|
|
END
|
1305 |
|
|
}
|
1306 |
d3d1a2d4
|
Origo
|
$uuid = $obj->{'uuid'} if ($obj->{'uuid'});
|
1307 |
95b003ff
|
Origo
|
$action = 'activate' || $action;
|
1308 |
d3d1a2d4
|
Origo
|
my $regnet = $register{$uuid};
|
1309 |
|
|
my $id = $regnet->{'id'};
|
1310 |
|
|
my $name = $regnet->{'name'};
|
1311 |
|
|
my $type = $regnet->{'type'};
|
1312 |
|
|
my $status = $regnet->{'status'};
|
1313 |
|
|
my $domains = $regnet->{'domains'};
|
1314 |
|
|
my $systems = $regnet->{'systems'};
|
1315 |
|
|
my $internalip = $regnet->{'internalip'};
|
1316 |
|
|
my $externalip = $regnet->{'externalip'};
|
1317 |
|
|
my $ports = $regnet->{'ports'};
|
1318 |
95b003ff
|
Origo
|
my $idleft = ($id>99)?(substr $id,0,-2)+0 : 0;
|
1319 |
|
|
my $idright = (substr $id,-2) + 0;
|
1320 |
|
|
my $interfaces = `/sbin/ifconfig`;
|
1321 |
|
|
my $dom = $domreg{$domains};
|
1322 |
|
|
my $nicindex = ($dom->{'networkuuid1'} eq $uuid)?1:
|
1323 |
|
|
($dom->{'networkuuid2'} eq $uuid)?2:
|
1324 |
|
|
($dom->{'networkuuid3'} eq $uuid)?3:
|
1325 |
|
|
0;
|
1326 |
|
|
my $nicmac = $dom->{"nicmac$nicindex"};
|
1327 |
|
|
my $e;
|
1328 |
|
|
|
1329 |
|
|
if (!$id || $id==0 || $id==1 || $id>4095) {
|
1330 |
|
|
$postreply .= "Status=ERROR Invalid ID activating $type\n";
|
1331 |
|
|
return $postreply;
|
1332 |
|
|
} elsif (overQuotas()) { # Enforce quotas
|
1333 |
|
|
$postreply .= "Status=ERROR Over quota activating $type " . overQuotas() . "\n";
|
1334 |
|
|
return $postreply;
|
1335 |
|
|
} elsif (($status ne 'down' && $status ne 'nat')) {
|
1336 |
|
|
$postreply .= "Status=ERROR Cannot activate $type $name (current status is: $status)\n";
|
1337 |
|
|
return $postreply;
|
1338 |
|
|
}
|
1339 |
|
|
|
1340 |
|
|
# Check if vlan with $id is created and doing nat, if not create it and create the gateway
|
1341 |
|
|
unless (-e "/proc/net/vlan/$datanic.$id") {
|
1342 |
|
|
eval {`/sbin/vconfig add $datanic $id`;} or do {$e=1; $postreply .= "Status=ERROR Problem adding vlan $datanic.$id $@\n"; return $postreply;};
|
1343 |
|
|
eval {`/sbin/ifconfig $datanic.$id up`;}# or do {$e=1; $postreply .= "Status=ERROR Problem activating vlan $datanic.$id $@\n"; return $postreply;};
|
1344 |
|
|
}
|
1345 |
|
|
# if (!($interfaces =~ m/$datanic\.$id /)) {
|
1346 |
|
|
if (!($interfaces =~ m/br$id /)) {
|
1347 |
|
|
# check if gw is created locally
|
1348 |
|
|
unless (`arping -C1 -c2 -D -I $datanic.$id 10.$idleft.$idright.1` =~ /reply from/) { # check if gw is created on another engine
|
1349 |
|
|
# Create gw
|
1350 |
|
|
# eval {`/sbin/ifconfig $datanic.$id 10.$idleft.$idright.1 netmask 255.255.255.0 broadcast 10.$idleft.$idright.255 up`; 1;} or do {
|
1351 |
|
|
# $e=1; $postreply .= "Status=ERROR $@\n"; return $postreply;
|
1352 |
|
|
# };
|
1353 |
|
|
# To support local instances on valve, gw is now created as a bridge
|
1354 |
|
|
eval {`/sbin/brctl addbr br$id`; 1;} or do {$e=1; $postreply .= "Status=ERROR $@\n"; return $postreply; };
|
1355 |
|
|
eval {`/sbin/brctl addif br$id $datanic.$id`; 1;} or do {$e=1; $postreply .= "Status=ERROR $@\n"; return $postreply; };
|
1356 |
|
|
eval {`/sbin/ifconfig br$id 10.$idleft.$idright.1/24 up`; 1;} or do {
|
1357 |
|
|
$e=1; $postreply .= "Status=ERROR $@\n"; return $postreply; }
|
1358 |
|
|
} else {
|
1359 |
|
|
$postreply .= "Status=OK GW is active on another Engine, assuming this is OK\n";
|
1360 |
|
|
}
|
1361 |
|
|
}
|
1362 |
|
|
my $astatus = "nat" unless ($e);
|
1363 |
|
|
`/usr/bin/touch $etcpath/dhcp-hosts-$id` unless (-e "$etcpath/dhcp-hosts-$id");
|
1364 |
d3d1a2d4
|
Origo
|
if ($action eq "activate") { #} && $domains) {
|
1365 |
95b003ff
|
Origo
|
if ($type eq "internalip" || $type eq "ipmapping") {
|
1366 |
d3d1a2d4
|
Origo
|
# Configure internal dhcp server
|
1367 |
|
|
if ($domains) {
|
1368 |
|
|
my $result = addDHCPAddress($id, $domains, $internalip, "10.$idleft.$idright.1", $nicmac);
|
1369 |
|
|
if ($result eq "OK") {
|
1370 |
|
|
$astatus = "up" if ($type eq "internalip");
|
1371 |
|
|
} else {
|
1372 |
|
|
$e = 1;
|
1373 |
|
|
$postreply .= "$result\n";
|
1374 |
|
|
}
|
1375 |
95b003ff
|
Origo
|
}
|
1376 |
|
|
|
1377 |
|
|
# Also export storage pools to user's network
|
1378 |
|
|
my @spl = split(/,\s*/, $storagepools);
|
1379 |
|
|
my $reloadnfs;
|
1380 |
|
|
my $uid = `id -u irigo-$user`; chomp $uid;
|
1381 |
|
|
$uid = `id -u nobody` unless ($uid =~ /\d+/); chomp $uid;
|
1382 |
|
|
my $gid = `id -g irigo-$user`; chomp $gid;
|
1383 |
|
|
$gid = `id -g nobody` unless ($gid =~ /\d+/); chomp $gid;
|
1384 |
|
|
|
1385 |
|
|
# We are dealing with multiple upstream routes - configure local routing
|
1386 |
|
|
if ($proxynic && $proxynic ne $extnic) {
|
1387 |
|
|
if (-e "/etc/iproute2/rt_tables" && !grep(/1 proxyarp/, `cat /etc/iproute2/rt_tables`)) {
|
1388 |
|
|
`/bin/echo "1 proxyarp" >> /etc/iproute2/rt_tables`;
|
1389 |
|
|
}
|
1390 |
|
|
if (!grep(/$datanic\.$id/, `/sbin/ip route show table proxyarp`)) {
|
1391 |
|
|
`/sbin/ip route add "10.$idleft.$idright.0/24" dev $datanic.$id table proxyarp`;
|
1392 |
|
|
}
|
1393 |
|
|
}
|
1394 |
|
|
|
1395 |
d24d9a01
|
hq
|
# Manuipulate NFS exports and related disk quotas
|
1396 |
95b003ff
|
Origo
|
foreach my $p (@spl) {
|
1397 |
|
|
if ($tenderlist[$p] && $tenderpathslist[$p]) {
|
1398 |
|
|
my $fuelpath = $tenderpathslist[$p] . "/$user/fuel";
|
1399 |
|
|
unless (-e $fuelpath) {
|
1400 |
1a56bdde
|
Origo
|
if ($tenderlist[$p] eq 'local') { # We only support fuel on local tender for now
|
1401 |
|
|
`mkdir "$fuelpath"`;
|
1402 |
|
|
`chmod 777 "$fuelpath"`;
|
1403 |
|
|
}
|
1404 |
95b003ff
|
Origo
|
}
|
1405 |
|
|
if ($tenderlist[$p] eq "local") {
|
1406 |
|
|
`chown irigo-$user:irigo-$user "$fuelpath"`;
|
1407 |
|
|
my $mpoint = `df -P "$fuelpath" | tail -1 | cut -d' ' -f 1`;
|
1408 |
|
|
chomp $mpoint;
|
1409 |
|
|
my $storagequota = $Stabile::userstoragequota;
|
1410 |
|
|
if (!$storagequota) {
|
1411 |
|
|
$storagequota = $Stabile::config->get('STORAGE_QUOTA');
|
1412 |
|
|
}
|
1413 |
|
|
my $nfsquota = $storagequota * 1024 ; # quota is in MB
|
1414 |
|
|
$nfsquota = 0 if ($nfsquota < 0); # quota of -1 means no limit
|
1415 |
d24d9a01
|
hq
|
`setquota -u irigo-$user $nfsquota $nfsquota 0 0 "$mpoint"` if (-e "$mntpoint");
|
1416 |
|
|
if (!(`grep "$fuelpath 10\.$idleft\.$idright" /etc/exports`) && -e $fuelpath) {
|
1417 |
95b003ff
|
Origo
|
`echo "$fuelpath 10.$idleft.$idright.0/255.255.255.0(sync,no_subtree_check,all_squash,rw,anonuid=$uid,anongid=$gid)" >> /etc/exports`;
|
1418 |
|
|
$reloadnfs = 1;
|
1419 |
|
|
}
|
1420 |
|
|
}
|
1421 |
|
|
}
|
1422 |
|
|
}
|
1423 |
|
|
`/usr/sbin/exportfs -r` if ($reloadnfs); #Reexport nfs shares
|
1424 |
|
|
|
1425 |
|
|
} elsif ($type eq "externalip") {
|
1426 |
d24d9a01
|
hq
|
# A proxy is needed to route traffic, don't go any further if not configured
|
1427 |
95b003ff
|
Origo
|
if ($proxyip) {
|
1428 |
d24d9a01
|
hq
|
# Set up proxy
|
1429 |
95b003ff
|
Origo
|
if (!($interfaces =~ m/$proxyip/ && $interfaces =~ m/br$id:proxy/)) {
|
1430 |
|
|
eval {`/sbin/ifconfig br$id:proxy $proxyip/$proxysubnet up`; 1;}
|
1431 |
e837d785
|
hq
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up proxy arp gw $proxyip on br$id:proxy $@\n";};
|
1432 |
95b003ff
|
Origo
|
eval {`/sbin/ifconfig $proxynic:proxy $proxyip/$proxysubnet up`; 1;}
|
1433 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up proxy arp gw $proxynic $@\n";};
|
1434 |
|
|
}
|
1435 |
d3d1a2d4
|
Origo
|
my $result = "OK";
|
1436 |
d24d9a01
|
hq
|
# Configure dhcp server
|
1437 |
d3d1a2d4
|
Origo
|
if ($domains) {
|
1438 |
|
|
$result = addDHCPAddress($id, $domains, $externalip, "10.$idleft.$idright.1", $nicmac) if ($domains);
|
1439 |
|
|
if ($result eq "OK") {
|
1440 |
|
|
;
|
1441 |
|
|
} else {
|
1442 |
|
|
$e = 1;
|
1443 |
|
|
$postreply .= "$result\n";
|
1444 |
|
|
}
|
1445 |
95b003ff
|
Origo
|
}
|
1446 |
|
|
} else {
|
1447 |
|
|
$postreply .= "Status=ERROR Cannot set up external IP without Proxy ARP gateway\n";
|
1448 |
|
|
}
|
1449 |
|
|
}
|
1450 |
|
|
|
1451 |
d24d9a01
|
hq
|
# Handle routing with Iptables
|
1452 |
|
|
if ($type eq "ipmapping" || $type eq "internalip") {
|
1453 |
|
|
`iptables -I FORWARD -d $internalip -m state --state ESTABLISHED,RELATED -j RETURN`;
|
1454 |
|
|
}
|
1455 |
95b003ff
|
Origo
|
# Check if external ip exists and routing configured, if not create and configure it
|
1456 |
|
|
if ($type eq "ipmapping") {
|
1457 |
2a63870a
|
Christian Orellana
|
if ($internalip && $internalip ne "--" && $externalip && $externalip ne "--" && !($interfaces =~ m/$externalip /g)) { # the space is important
|
1458 |
64c667ea
|
hq
|
$externalip =~ /\d+\.\d+\.(\d+)\.(\d+)/;
|
1459 |
|
|
my $ipend = "$1$2"; # Linux NIC names are limited to 15 chars - we will have to find a way to support long NIC names and bigger than /24 subnets
|
1460 |
|
|
$ipend = $2 if (length("$extnic:$id-$ipend")>15);
|
1461 |
95b003ff
|
Origo
|
eval {`/sbin/ifconfig $extnic:$id-$ipend $externalip/$extsubnet up`; 1;}
|
1462 |
d3d1a2d4
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem adding interface $extnic:$id-$ipend $@\n";};
|
1463 |
48fcda6b
|
Origo
|
unless (`ip addr show dev $extnic` =~ /$externalip/) {
|
1464 |
|
|
$e=10;
|
1465 |
d3d1a2d4
|
Origo
|
$postreply .= "Status=ERROR Problem adding interface $extnic:$id-$ipend\n";
|
1466 |
48fcda6b
|
Origo
|
}
|
1467 |
d24d9a01
|
hq
|
# `/sbin/iptables -A POSTROUTING -t nat -s $internalip -j LOG --log-prefix "SNAT-POST"`;
|
1468 |
|
|
# `/sbin/iptables -A INPUT -t nat -s $internalip -j LOG --log-prefix "SNAT-INPUT"`;
|
1469 |
|
|
# `/sbin/iptables -A OUTPUT -t nat -s $internalip -j LOG --log-prefix "SNAT-OUTPUT"`;
|
1470 |
|
|
# `/sbin/iptables -A PREROUTING -t nat -s $internalip -j LOG --log-prefix "SNAT-PRE"`;
|
1471 |
95b003ff
|
Origo
|
if ($ports && $ports ne "--") { # Port mapping is defined
|
1472 |
|
|
my @portslist = split(/, ?| /, $ports);
|
1473 |
|
|
foreach $port (@portslist) {
|
1474 |
|
|
my $ipfilter;
|
1475 |
|
|
if ($port =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)(\/\d+)?:(\d+)/) {
|
1476 |
|
|
my $portip = "$1.$2.$3.$4$5";
|
1477 |
|
|
$port = $6;
|
1478 |
|
|
$ipfilter = "-s $portip";
|
1479 |
|
|
} else {
|
1480 |
|
|
$port = 0 unless ($port =~ /\d+/);
|
1481 |
|
|
}
|
1482 |
|
|
if ($port<1 || $port>65535) {
|
1483 |
|
|
$postreply .= "Status=ERROR Invalid port mapping for $name\n";
|
1484 |
|
|
$ports = "--";
|
1485 |
|
|
last;
|
1486 |
|
|
}
|
1487 |
|
|
if ($port>1 || $port<65535) {
|
1488 |
d24d9a01
|
hq
|
# DNAT externalip -> internalip
|
1489 |
95b003ff
|
Origo
|
eval {`/sbin/iptables -A PREROUTING -t nat -p tcp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`; 1;}
|
1490 |
d24d9a01
|
hq
|
or do {$e=2; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1491 |
95b003ff
|
Origo
|
eval {`/sbin/iptables -A PREROUTING -t nat -p udp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`; 1;}
|
1492 |
d24d9a01
|
hq
|
or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1493 |
2a63870a
|
Christian Orellana
|
# PREROUTING is not parsed for packets coming from local host...
|
1494 |
|
|
eval {`/sbin/iptables -A OUTPUT -t nat -p tcp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`; 1;}
|
1495 |
|
|
or do {$e=2; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1496 |
|
|
eval {`/sbin/iptables -A OUTPUT -t nat -p udp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`; 1;}
|
1497 |
|
|
or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1498 |
d24d9a01
|
hq
|
# Allow access to ipmapped internal ip on $port
|
1499 |
|
|
`iptables -I FORWARD -d $internalip -p tcp --dport $port -j RETURN`;
|
1500 |
|
|
`iptables -I FORWARD -d $internalip -p udp --dport $port -j RETURN`;
|
1501 |
95b003ff
|
Origo
|
}
|
1502 |
|
|
}
|
1503 |
|
|
eval {`/sbin/iptables -D INPUT -d $externalip -j DROP`; 1;} # Drop traffic to all other ports
|
1504 |
48fcda6b
|
Origo
|
or do {$e=5; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1505 |
95b003ff
|
Origo
|
eval {`/sbin/iptables -A INPUT -d $externalip -j DROP`; 1;} # Drop traffic to all other ports
|
1506 |
48fcda6b
|
Origo
|
or do {$e=6; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1507 |
95b003ff
|
Origo
|
} else {
|
1508 |
d24d9a01
|
hq
|
# DNAT externalip -> internalip coming from outside , --in-interface $extnic
|
1509 |
95b003ff
|
Origo
|
eval {`/sbin/iptables -A PREROUTING -t nat -d $externalip -j DNAT --to $internalip`; 1;}
|
1510 |
48fcda6b
|
Origo
|
or do {$e=7; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1511 |
d24d9a01
|
hq
|
# PREROUTING is not parsed for packets coming from local host...
|
1512 |
2a63870a
|
Christian Orellana
|
eval {`/sbin/iptables -A OUTPUT -t nat -d $externalip -j DNAT --to $internalip`; 1;}
|
1513 |
|
|
or do {$e=7; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1514 |
d24d9a01
|
hq
|
# Allow blanket access to ipmapped internal ip
|
1515 |
|
|
`iptables -I FORWARD -d $internalip -j RETURN`;
|
1516 |
|
|
}
|
1517 |
|
|
# We masquerade packets going to internalip from externalip to avoid confusion
|
1518 |
|
|
#eval {`/sbin/iptables -A POSTROUTING -t nat --out-interface br$id -s $externalip -j MASQUERADE`; 1;}
|
1519 |
|
|
# or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1520 |
6fdc8676
|
hq
|
|
1521 |
|
|
# Masquerade packets from internal ip's not going to our own subnet
|
1522 |
|
|
# `/sbin/iptables -D POSTROUTING -t nat --out-interface br$id ! -d 10.$idleft.$idright.0/24 -j MASQUERADE`;
|
1523 |
|
|
#eval {`/sbin/iptables -A POSTROUTING -t nat --out-interface br$id ! -d 10.$idleft.$idright.0/24 -j MASQUERADE`; 1;}
|
1524 |
|
|
# or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1525 |
|
|
|
1526 |
d24d9a01
|
hq
|
# When receiving packet from client, if it's been routed, and outgoing interface is the external interface, SNAT.
|
1527 |
|
|
unless ($Stabile::disablesnat) {
|
1528 |
|
|
eval {`/sbin/iptables -A POSTROUTING -t nat -s $internalip ! -d 10.$idleft.$idright.0/24 -j SNAT --to-source $externalip`; 1; }
|
1529 |
|
|
or do {$e=4; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1530 |
|
|
# eval {`/sbin/iptables -A POSTROUTING -t nat -s $internalip -j SNAT --to-source $externalip`; 1; }
|
1531 |
|
|
# or do {$e=4; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1532 |
|
|
eval {`/sbin/iptables -I INPUT -t nat -s $internalip ! -d 10.$idleft.$idright.0/24 -j SNAT --to-source $externalip`; 1; }
|
1533 |
|
|
or do {$e=4; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1534 |
|
|
# eval {`/sbin/iptables -I INPUT -t nat -s $internalip -j SNAT --to-source $externalip`; 1; }
|
1535 |
|
|
# or do {$e=4; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1536 |
95b003ff
|
Origo
|
}
|
1537 |
d24d9a01
|
hq
|
|
1538 |
48fcda6b
|
Origo
|
if ($e) {
|
1539 |
|
|
$main::syslogit->($user, 'info', "Problem $action network $uuid ($name, $id): $@");
|
1540 |
|
|
} else {
|
1541 |
|
|
$astatus = "up"
|
1542 |
|
|
}
|
1543 |
95b003ff
|
Origo
|
}
|
1544 |
|
|
} elsif ($type eq "externalip") {
|
1545 |
|
|
my $route = `/sbin/ip route`;
|
1546 |
|
|
my $tables = `/sbin/iptables -L -n`;
|
1547 |
|
|
|
1548 |
d24d9a01
|
hq
|
# Allow external IP send packets out
|
1549 |
|
|
`/sbin/iptables -D FORWARD --in-interface br$id -s $externalip -j RETURN`;
|
1550 |
|
|
`/sbin/iptables -I FORWARD --in-interface br$id -s $externalip -j RETURN`;
|
1551 |
|
|
|
1552 |
95b003ff
|
Origo
|
# We are dealing with multiple upstream routes - configure local routing
|
1553 |
e837d785
|
hq
|
if ($proxynic && ($proxynic ne $extnic)) {
|
1554 |
95b003ff
|
Origo
|
if (-e "/etc/iproute2/rt_tables" && !grep(/1 proxyarp/, `cat /etc/iproute2/rt_tables`)) {
|
1555 |
|
|
`/bin/echo "1 proxyarp" >> /etc/iproute2/rt_tables`;
|
1556 |
|
|
}
|
1557 |
|
|
if (!grep(/$proxygw/, `/sbin/ip route show table proxyarp`)) {
|
1558 |
e837d785
|
hq
|
`/sbin/ip route del default dev $proxynic table proxyarp`; # delete first in case proxygw has changed
|
1559 |
95b003ff
|
Origo
|
`/sbin/ip route add default via $proxygw dev $proxynic table proxyarp`;
|
1560 |
|
|
}
|
1561 |
|
|
if (!grep(/proxyarp/, `/sbin/ip rule show`)) {
|
1562 |
|
|
`/sbin/ip rule add to $proxygw/$proxysubnet table main`;
|
1563 |
|
|
`/sbin/ip rule add from $proxygw/$proxysubnet table proxyarp`;
|
1564 |
|
|
}
|
1565 |
|
|
my $proxyroute = `/sbin/ip route show table proxyarp`;
|
1566 |
|
|
# `/sbin/ip route add $externalip/32 dev $datanic.$id:proxy src $proxyip table proxyarp` unless ($proxyroute =~ /$externalip/);
|
1567 |
|
|
`/sbin/ip route add $externalip/32 dev br$id:proxy src $proxyip table proxyarp` unless ($proxyroute =~ /$externalip/);
|
1568 |
|
|
}
|
1569 |
|
|
eval {`/bin/echo 1 > /proc/sys/net/ipv4/conf/$datanic.$id/proxy_arp`; 1;}
|
1570 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up proxy arp $@\n";};
|
1571 |
|
|
eval {`/bin/echo 1 > /proc/sys/net/ipv4/conf/$proxynic/proxy_arp`; 1;}
|
1572 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up proxy arp $@\n";};
|
1573 |
|
|
eval {`/sbin/ip route add $externalip/32 dev br$id:proxy src $proxyip` unless ($route =~ /$externalip/); 1;}
|
1574 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up proxy arp $@\n";};
|
1575 |
|
|
|
1576 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -m state --state ESTABLISHED,RELATED -j RETURN`; 1;}
|
1577 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1578 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -A FORWARD -i $proxynic -d $externalip -m state --state ESTABLISHED,RELATED -j RETURN`; 1;}
|
1579 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1580 |
|
|
|
1581 |
|
|
|
1582 |
|
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j REJECT` if
|
1583 |
|
|
($tables =~ /REJECT .+ all .+ $externalip/); 1;}
|
1584 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1585 |
|
|
|
1586 |
|
|
if ($ports && $ports ne "--") {
|
1587 |
|
|
my @portslist = split(/, ?| /, $ports);
|
1588 |
|
|
foreach $port (@portslist) {
|
1589 |
|
|
my $ipfilter;
|
1590 |
|
|
if ($port =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)(\/\d+)?:(\d+)/) {
|
1591 |
|
|
my $portip = "$1.$2.$3.$4$5";
|
1592 |
|
|
$port = $6;
|
1593 |
|
|
$ipfilter = "-s $portip";
|
1594 |
|
|
} else {
|
1595 |
|
|
$port = 0 unless ($port =~ /\d+/);
|
1596 |
|
|
}
|
1597 |
|
|
if ($port<1 || $port>65535) {
|
1598 |
|
|
$postreply .= "Status=ERROR Invalid port mapping for $name\n";
|
1599 |
|
|
$ports = "--";
|
1600 |
|
|
last;
|
1601 |
|
|
}
|
1602 |
|
|
|
1603 |
|
|
if ($port>1 && $port<65535 && $port!=67) { # Disallow setting up a dhcp server
|
1604 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -A FORWARD -p tcp -i $proxynic $portfilter -d $externalip --dport $port -j RETURN`; 1;}
|
1605 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1606 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -A FORWARD -p udp -i $proxynic $portfilter -d $externalip --dport $port -j RETURN`; 1;}
|
1607 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1608 |
|
|
}
|
1609 |
|
|
}
|
1610 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j REJECT`; 1;} # Drop traffic to all other ports
|
1611 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1612 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -A FORWARD -i $proxynic -d $externalip -j REJECT`; 1;} # Drop traffic to all other ports
|
1613 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1614 |
|
|
} else {
|
1615 |
d24d9a01
|
hq
|
# First allow everything else to this ip
|
1616 |
|
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j RETURN`; 1;}
|
1617 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1618 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -A FORWARD -i $proxynic -d $externalip -j RETURN`; 1;}
|
1619 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1620 |
d24d9a01
|
hq
|
# Then disallow setting up a dhcp server
|
1621 |
|
|
eval {`/sbin/iptables -D FORWARD -p udp -i $proxynic -d $externalip --dport 67 -j REJECT`; 1;}
|
1622 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1623 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -A FORWARD -p udp -i $proxynic -d $externalip --dport 67 -j REJECT`; 1;}
|
1624 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1625 |
|
|
}
|
1626 |
|
|
}
|
1627 |
|
|
}
|
1628 |
|
|
|
1629 |
d24d9a01
|
hq
|
# Allow all inter-VLAN communication
|
1630 |
|
|
`iptables -D FORWARD --in-interface br$id --out-interface br$id -j RETURN 2>/dev/null`;
|
1631 |
|
|
`iptables -I FORWARD --in-interface br$id --out-interface br$id -j RETURN`;
|
1632 |
|
|
# Disallow any access to vlan except mapped from external NIC i.e. ipmappings
|
1633 |
|
|
`iptables -D FORWARD ! --in-interface $extnic --out-interface br$id -j DROP 2>/dev/null`;
|
1634 |
|
|
`iptables -A FORWARD ! --in-interface $extnic --out-interface br$id -j DROP`;
|
1635 |
|
|
|
1636 |
95b003ff
|
Origo
|
# Only forward packets coming from subnet assigned to vlan unless we are setting up a gateway on the proxy nic and the proxy nic is on a vlan
|
1637 |
d24d9a01
|
hq
|
# `/sbin/iptables --delete FORWARD --in-interface $datanic.$id ! -s 10.$idleft.$idright.0/24 -j DROP`;
|
1638 |
95b003ff
|
Origo
|
unless ($proxynic eq "$datanic.$id") {
|
1639 |
d24d9a01
|
hq
|
# `/sbin/iptables --append FORWARD --in-interface $datanic.$id ! -s 10.$idleft.$idright.0/24 -j DROP`;
|
1640 |
95b003ff
|
Origo
|
}
|
1641 |
|
|
|
1642 |
a439a9c4
|
hq
|
# Enable nat'ing
|
1643 |
|
|
eval {
|
1644 |
64c667ea
|
hq
|
#my $masq = `/sbin/iptables -L -n -t nat`;
|
1645 |
a439a9c4
|
hq
|
# if (!($masq =~ "MASQUERADE.+all.+--.+0\.0\.0\.0/0")) {
|
1646 |
|
|
`/sbin/iptables -D POSTROUTING -t nat --out-interface $extnic -s 10.0.0.0/8 -j MASQUERADE`;
|
1647 |
|
|
`/sbin/iptables -A POSTROUTING -t nat --out-interface $extnic -s 10.0.0.0/8 -j MASQUERADE`;
|
1648 |
|
|
# Christian's dev environment
|
1649 |
|
|
# my $interfaces = `/sbin/ifconfig`;
|
1650 |
|
|
# if ($interfaces =~ m/ppp0/) {
|
1651 |
|
|
# `/sbin/iptables --table nat --append POSTROUTING --out-interface ppp0 -s 10.0.0.0/8 -j MASQUERADE`;
|
1652 |
|
|
# }
|
1653 |
|
|
# };
|
1654 |
|
|
1;
|
1655 |
|
|
} or do {print "Unable to enable masquerading: $@\n";};
|
1656 |
|
|
|
1657 |
95b003ff
|
Origo
|
$uistatus = ($e)?"":validateStatus($register{$uuid});
|
1658 |
|
|
if ($uistatus && $uistatus ne 'down') {
|
1659 |
|
|
$uiuuid = $uuid;
|
1660 |
|
|
$postreply .= "Status=$uistatus OK $action $type $name\n";
|
1661 |
|
|
} else {
|
1662 |
|
|
$postreply .= "Status=ERROR Cannot $action $type $name ($uistatus)\n";
|
1663 |
|
|
}
|
1664 |
|
|
$main::syslogit->($user, 'info', "$action network $uuid ($name, $id) -> $uistatus");
|
1665 |
|
|
updateBilling("$uistatus $uuid ($id)");
|
1666 |
d24d9a01
|
hq
|
# $main::updateUI->({tab=>"networks", user=>$user, uuid=>$uiuuid, status=>$uistatus}) if ($uistatus);
|
1667 |
95b003ff
|
Origo
|
return $postreply;
|
1668 |
|
|
}
|
1669 |
|
|
|
1670 |
|
|
sub Removeusernetworks {
|
1671 |
|
|
my $username = shift;
|
1672 |
|
|
return unless (($isadmin || $user eq $username) && !$isreadonly);
|
1673 |
|
|
$user = $username;
|
1674 |
|
|
foreach my $uuid (keys %register) {
|
1675 |
|
|
if ($register{$uuid}->{'user'} eq $user) {
|
1676 |
|
|
$postreply .= "Removing network $register{$path}->{'name'}, $uuid" . ($console?'':'<br>') . "\n";
|
1677 |
|
|
Deactivate($uuid);
|
1678 |
|
|
Remove('remove', $uuid);
|
1679 |
|
|
}
|
1680 |
|
|
}
|
1681 |
|
|
}
|
1682 |
|
|
|
1683 |
|
|
sub Remove {
|
1684 |
d3d1a2d4
|
Origo
|
my ($uuid, $action, $obj) = @_;
|
1685 |
95b003ff
|
Origo
|
if ($help) {
|
1686 |
|
|
return <<END
|
1687 |
d3d1a2d4
|
Origo
|
DELETE:uuid,force:
|
1688 |
|
|
Delete a network which must be in status down or nat and should not be used by any servers, or linked to any stacks.
|
1689 |
95b003ff
|
Origo
|
May also be called with endpoints "/stabile/[uuid]" or "/stabile?uuid=[uuid]"
|
1690 |
d3d1a2d4
|
Origo
|
Set [force] to remove even if linked to a system.
|
1691 |
95b003ff
|
Origo
|
END
|
1692 |
|
|
}
|
1693 |
d3d1a2d4
|
Origo
|
$uuid = $obj->{'uuid'} if ($curuuid && $obj->{'uuid'}); # we are called from a VM with an ip address as target
|
1694 |
|
|
my $force = $obj->{'force'};
|
1695 |
95b003ff
|
Origo
|
( my $domains, my $domainnames ) = getDomains($uuid);
|
1696 |
d3d1a2d4
|
Origo
|
( my $systems, my $systemnames ) = getSystems($uuid);
|
1697 |
95b003ff
|
Origo
|
|
1698 |
|
|
if ($register{$uuid}) {
|
1699 |
|
|
my $id = $register{$uuid}->{'id'};
|
1700 |
|
|
my $name = $register{$uuid}->{'name'};
|
1701 |
|
|
utf8::decode($name);
|
1702 |
|
|
my $status = $register{$uuid}->{'status'};
|
1703 |
|
|
my $type = $register{$uuid}->{'type'};
|
1704 |
|
|
my $internalip = $register{$uuid}->{'internalip'};
|
1705 |
|
|
my $externalip = $register{$uuid}->{'externalip'};
|
1706 |
|
|
|
1707 |
|
|
my @regvalues = values %register;
|
1708 |
d3d1a2d4
|
Origo
|
if (
|
1709 |
|
|
$id!=0 && $id!=1 && (!$domains || $domains eq '--')
|
1710 |
2a63870a
|
Christian Orellana
|
&& ((!$systems || $systems eq '--' || $force)
|
1711 |
d3d1a2d4
|
Origo
|
# allow internalip's to be removed if active and only linked, i.e. not providing dhcp
|
1712 |
2a63870a
|
Christian Orellana
|
|| ($status eq 'down' || $status eq 'new' || $status eq 'nat' || ($type eq 'internalip' && $systems && $systems ne '--')))
|
1713 |
d3d1a2d4
|
Origo
|
) {
|
1714 |
95b003ff
|
Origo
|
# Deconfigure internal dhcp server and DNS
|
1715 |
|
|
if ($type eq "internalip") {
|
1716 |
|
|
my $result = removeDHCPAddress($id, $domains, $internalip);
|
1717 |
|
|
$postreply .= "$result\n" unless $result eq "OK";
|
1718 |
|
|
} elsif ($type eq "ipmapping") {
|
1719 |
|
|
my $result = removeDHCPAddress($id, $domains, $internalip);
|
1720 |
|
|
$postreply .= "$result\n" unless $result eq "OK";
|
1721 |
|
|
if ($dodns) {
|
1722 |
e9af6c24
|
Origo
|
$main::dnsDelete->($engineid, $externalip) if ($enginelinked);
|
1723 |
95b003ff
|
Origo
|
}
|
1724 |
|
|
} elsif ($type eq "externalip") {
|
1725 |
|
|
my $result = removeDHCPAddress($id, $domains, $externalip);
|
1726 |
|
|
$postreply .= "$result\n" unless $result eq "OK";
|
1727 |
|
|
if ($dodns) {
|
1728 |
e9af6c24
|
Origo
|
$main::dnsDelete->($engineid, $externalip) if ($enginelinked);
|
1729 |
95b003ff
|
Origo
|
}
|
1730 |
|
|
}
|
1731 |
|
|
if ($status eq 'nat') {
|
1732 |
|
|
# Check if last network in vlan. If so take it down
|
1733 |
|
|
my $notlast;
|
1734 |
|
|
foreach my $val (@regvalues) {
|
1735 |
|
|
if ($val->{'user'} eq $user && $val->{'id'} == $id) {
|
1736 |
|
|
$notlast = 1;
|
1737 |
|
|
}
|
1738 |
|
|
}
|
1739 |
|
|
if (!$notlast) {
|
1740 |
|
|
eval {`/sbin/ifconfig $datanic.$id down`; 1;} or do {;};
|
1741 |
|
|
eval {`/sbin/vconfig rem $datanic.$id`; 1;} or do {;};
|
1742 |
|
|
}
|
1743 |
|
|
}
|
1744 |
d3d1a2d4
|
Origo
|
|
1745 |
|
|
unless (tie(%sysreg,'Tie::DBI', Hash::Merge::merge({table=>'systems'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access systems register"}|; return $res;};
|
1746 |
|
|
if ($sysreg{$systems}) { # Remove existing link to system
|
1747 |
|
|
$sysreg{$systems}->{'networkuuids'} =~ s/$uuid,?//;
|
1748 |
|
|
$sysreg{$systems}->{'networknames'} = s/$name,?//;
|
1749 |
|
|
}
|
1750 |
|
|
tied(%sysreg)->commit;
|
1751 |
|
|
untie(%sysreg);
|
1752 |
|
|
|
1753 |
|
|
|
1754 |
95b003ff
|
Origo
|
delete $register{$uuid};
|
1755 |
|
|
tied(%register)->commit;
|
1756 |
|
|
updateBilling("delete $val->{'externalip'}") if ($type eq "ipmapping");
|
1757 |
|
|
$main::syslogit->($user, "info", "Deleted network $uuid ($id)");
|
1758 |
d3d1a2d4
|
Origo
|
$postreply = "[]" || $postreply;
|
1759 |
|
|
$main::updateUI->({tab=>"networks", user=>$user, type=>"update"});
|
1760 |
95b003ff
|
Origo
|
} else {
|
1761 |
d3d1a2d4
|
Origo
|
$postreply .= "Status=ERROR Cannot remove $uuid which is $status. Cannot delete network 0,1 or a network which is active or in use.\n";
|
1762 |
|
|
$main::updateUI->({tab=>"networks", user=>$user, message=>"Cannot remove a network which is active, linked or in use."});
|
1763 |
95b003ff
|
Origo
|
}
|
1764 |
|
|
} else {
|
1765 |
d3d1a2d4
|
Origo
|
$postreply .= "Status=ERROR Network $uuid $ipaddress not found\n";
|
1766 |
95b003ff
|
Origo
|
}
|
1767 |
|
|
return $postreply;
|
1768 |
|
|
}
|
1769 |
|
|
|
1770 |
|
|
sub Deactivate {
|
1771 |
d3d1a2d4
|
Origo
|
my ($uuid, $action, $obj) = @_;
|
1772 |
95b003ff
|
Origo
|
|
1773 |
|
|
if ($help) {
|
1774 |
|
|
return <<END
|
1775 |
|
|
GET:uuid:
|
1776 |
|
|
Deactivate a network which must be in status up.
|
1777 |
|
|
END
|
1778 |
|
|
}
|
1779 |
d3d1a2d4
|
Origo
|
$uuid = $obj->{'uuid'} if ($obj->{'uuid'});
|
1780 |
|
|
|
1781 |
|
|
unless ($register{$uuid}) {
|
1782 |
|
|
$postreply .= "Status=ERROR Connection with uuid $uuid not found\n";
|
1783 |
|
|
return $postreply;
|
1784 |
|
|
}
|
1785 |
|
|
my $regnet = $register{$uuid};
|
1786 |
95b003ff
|
Origo
|
|
1787 |
|
|
$action = $action || 'deactivate';
|
1788 |
|
|
( my $domains, my $domainnames ) = getDomains($uuid);
|
1789 |
|
|
my $interfaces = `/sbin/ifconfig`;
|
1790 |
|
|
|
1791 |
d3d1a2d4
|
Origo
|
my $id = $regnet->{'id'};
|
1792 |
|
|
my $name = $regnet->{'name'};
|
1793 |
|
|
my $type = $regnet->{'type'};
|
1794 |
|
|
my $internalip = $regnet->{'internalip'};
|
1795 |
|
|
my $externalip = $regnet->{'externalip'};
|
1796 |
|
|
my $ports = $regnet->{'ports'};
|
1797 |
95b003ff
|
Origo
|
|
1798 |
|
|
if ($id!=0 && $id!=1 && $status ne 'down') {
|
1799 |
|
|
# If gateway is created, take it down along with all user's networks
|
1800 |
|
|
if ($action eq "stop") {
|
1801 |
|
|
my $res = Stop($id, $action);
|
1802 |
|
|
if ($res) {
|
1803 |
|
|
unlink "$etcpath/dhcp-hosts-$id" if (-e "$etcpath/dhcp-hosts-$id");
|
1804 |
|
|
};
|
1805 |
|
|
}
|
1806 |
|
|
} else {
|
1807 |
|
|
$postreply .= "Status=ERROR Cannot $action network $name\n";
|
1808 |
|
|
return $postreply;
|
1809 |
|
|
}
|
1810 |
|
|
|
1811 |
2a63870a
|
Christian Orellana
|
my $idleft = ($id>99)?(substr $id,0,-2)+0 : 0;
|
1812 |
|
|
my $idright = (substr $id,-2) + 0;
|
1813 |
95b003ff
|
Origo
|
my $e = 0;
|
1814 |
2a63870a
|
Christian Orellana
|
my $duprules = 0;
|
1815 |
d24d9a01
|
hq
|
|
1816 |
|
|
if ($type eq "ipmapping" || $type eq "internalip") {
|
1817 |
|
|
`iptables -D FORWARD -d $internalip -m state --state ESTABLISHED,RELATED -j RETURN`;
|
1818 |
|
|
}
|
1819 |
95b003ff
|
Origo
|
if ($type eq "ipmapping") {
|
1820 |
d24d9a01
|
hq
|
# Check if external ip exists and take it down if so
|
1821 |
95b003ff
|
Origo
|
if ($internalip && $internalip ne "--" && $externalip && $externalip ne "--" && ($interfaces =~ m/$externalip/g)) {
|
1822 |
64c667ea
|
hq
|
$externalip =~ /\d+\.\d+\.(\d+)\.(\d+)/;
|
1823 |
|
|
my $ipend = "$1$2"; # Linux NIC names are limited to 15 chars - we will have to find a way to support long NIC names and bigger than /24 subnets
|
1824 |
|
|
$ipend = $2 if (length("$extnic:$id-$ipend")>15);
|
1825 |
95b003ff
|
Origo
|
eval {`/sbin/ifconfig $extnic:$id-$ipend down`; 1;} or do {$e=1; $postreply .= "Status=ERROR $@\n";};
|
1826 |
|
|
|
1827 |
|
|
if ($ports && $ports ne "--") { # Port mapping is defined
|
1828 |
|
|
my @portslist = split(/, ?| /, $ports);
|
1829 |
2a63870a
|
Christian Orellana
|
foreach my $port (@portslist) {
|
1830 |
95b003ff
|
Origo
|
my $ipfilter;
|
1831 |
|
|
if ($port =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)(\/\d+)?:(\d+)/) {
|
1832 |
|
|
my $portip = "$1.$2.$3.$4$5";
|
1833 |
|
|
$port = $6;
|
1834 |
|
|
$ipfilter = "-s $portip";
|
1835 |
|
|
} else {
|
1836 |
|
|
$port = 0 unless ($port =~ /\d+/);
|
1837 |
|
|
}
|
1838 |
|
|
if ($port<1 || $port>65535) {
|
1839 |
|
|
$postreply .= "Status=ERROR Invalid port mapping for $name\n";
|
1840 |
|
|
$ports = "--";
|
1841 |
|
|
last;
|
1842 |
|
|
}
|
1843 |
d24d9a01
|
hq
|
# Remove DNAT rules
|
1844 |
95b003ff
|
Origo
|
if ($port>1 || $port<65535) {
|
1845 |
|
|
# repeat for good measure
|
1846 |
2a63870a
|
Christian Orellana
|
for (my $di=0; $di < 10; $di++) {
|
1847 |
|
|
$duprules = 0;
|
1848 |
|
|
eval {$duprules++ if (`/sbin/iptables -D PREROUTING -t nat -p tcp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`); 1;}
|
1849 |
95b003ff
|
Origo
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1850 |
2a63870a
|
Christian Orellana
|
eval {$duprules++ if (`/sbin/iptables -D PREROUTING -t nat -p udp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`); 1;}
|
1851 |
95b003ff
|
Origo
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1852 |
2a63870a
|
Christian Orellana
|
eval {$duprules++ if (`/sbin/iptables -D OUTPUT -t nat -p tcp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`); 1;}
|
1853 |
|
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1854 |
|
|
eval {$duprules++ if (`/sbin/iptables -D OUTPUT -t nat -p udp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`); 1;}
|
1855 |
|
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1856 |
|
|
eval {$duprules++ if (`/sbin/iptables -D POSTROUTING -t nat --out-interface br$id -s $externalip -j MASQUERADE`); 1;}
|
1857 |
|
|
or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1858 |
d24d9a01
|
hq
|
# Remove access to ipmapped internal ip on $port
|
1859 |
|
|
eval {$duprules++ if (`/sbin/iptables -D FORWARD -d $internalip -p udp --dport $port -j RETURN`); 1;}
|
1860 |
|
|
or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1861 |
|
|
eval {$duprules++ if (`/sbin/iptables -D FORWARD -d $internalip -p tcp --dport $port -j RETURN`); 1;}
|
1862 |
|
|
or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1863 |
|
|
last if ($duprules >6);
|
1864 |
95b003ff
|
Origo
|
}
|
1865 |
|
|
}
|
1866 |
|
|
}
|
1867 |
d24d9a01
|
hq
|
# Remove SNAT rules
|
1868 |
95b003ff
|
Origo
|
# repeat for good measure
|
1869 |
2a63870a
|
Christian Orellana
|
for (my $di=0; $di < 10; $di++) {
|
1870 |
|
|
$duprules = 0;
|
1871 |
|
|
eval {$duprules++ if (`/sbin/iptables -D POSTROUTING -t nat -s $internalip ! -d 10.$idleft.$idright.0/24 -j SNAT --to-source $externalip`); 1; }
|
1872 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1873 |
2a63870a
|
Christian Orellana
|
last if ($duprules);
|
1874 |
95b003ff
|
Origo
|
}
|
1875 |
d24d9a01
|
hq
|
# Remove rule to drop traffic to all other ports
|
1876 |
|
|
eval {`/sbin/iptables -D INPUT -d $externalip -j DROP`; 1;}
|
1877 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1878 |
|
|
} else {
|
1879 |
d24d9a01
|
hq
|
# Remove DNAT rules
|
1880 |
95b003ff
|
Origo
|
# repeat for good measure
|
1881 |
2a63870a
|
Christian Orellana
|
for (my $di=0; $di < 10; $di++) {
|
1882 |
|
|
$duprules = 0;
|
1883 |
|
|
eval {$duprules++ if (`/sbin/iptables -D PREROUTING -t nat -d $externalip -j DNAT --to $internalip`); 1;}
|
1884 |
95b003ff
|
Origo
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1885 |
2a63870a
|
Christian Orellana
|
eval {$duprules++ if (`/sbin/iptables -D OUTPUT -t nat -d $externalip -j DNAT --to $internalip`); 1;}
|
1886 |
|
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1887 |
d24d9a01
|
hq
|
last if ($duprules >1);
|
1888 |
95b003ff
|
Origo
|
}
|
1889 |
d24d9a01
|
hq
|
# Remove blanket access to ipmapped internal ip
|
1890 |
|
|
`iptables -D FORWARD -d $internalip -j RETURN`;
|
1891 |
|
|
}
|
1892 |
|
|
# Remove SNAT and MASQUERADE rules
|
1893 |
|
|
# repeat for good measure
|
1894 |
|
|
for (my $di=0; $di < 10; $di++) {
|
1895 |
|
|
$duprules = 0;
|
1896 |
|
|
# eval {$duprules++ if (`/sbin/iptables -D POSTROUTING -t nat --out-interface br$id -s $externalip -j MASQUERADE`); 1;}
|
1897 |
|
|
# or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1898 |
6fdc8676
|
hq
|
eval {$duprules++ if (`/sbin/iptables -D POSTROUTING -t nat --out-interface br$id ! -d 10.$idleft.$idright.0/24 -j MASQUERADE`); 1;}
|
1899 |
d24d9a01
|
hq
|
or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1900 |
|
|
|
1901 |
|
|
eval {$duprules++ if (`/sbin/iptables -D POSTROUTING -t nat -s $internalip ! -d 10.$idleft.$idright.0/24 -j SNAT --to-source $externalip`); 1; }
|
1902 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1903 |
|
|
# eval {$duprules++ if (`/sbin/iptables -D POSTROUTING -t nat -s $internalip -j SNAT --to-source $externalip`); 1; }
|
1904 |
|
|
# or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1905 |
|
|
eval {$duprules++ if (`/sbin/iptables -D INPUT -t nat -s $internalip ! -d 10.$idleft.$idright.0/24 -j SNAT --to-source $externalip`); 1; }
|
1906 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1907 |
|
|
# eval {$duprules++ if (`/sbin/iptables -D INPUT -t nat -s $internalip -j SNAT --to-source $externalip`); 1; }
|
1908 |
|
|
# or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1909 |
|
|
# eval {$duprules++ if (`/sbin/iptables -D INPUT -t nat -s $internalip ! -d 10.$idleft.$idright.0/24 -j SNAT --to-source $externalip`); 1; }
|
1910 |
|
|
# or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1911 |
|
|
# eval {$duprules++ if (`/sbin/iptables -D INPUT -t nat -s $internalip -j SNAT --to-source $externalip`); 1; }
|
1912 |
|
|
# or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1913 |
|
|
last if ($duprules >1);
|
1914 |
95b003ff
|
Origo
|
}
|
1915 |
d24d9a01
|
hq
|
# `/sbin/iptables -D POSTROUTING -t nat -s $internalip -j LOG --log-prefix "SNAT-POST"`;
|
1916 |
|
|
# `/sbin/iptables -D INPUT -t nat -s $internalip -j LOG --log-prefix "SNAT-INPUT"`;
|
1917 |
|
|
# `/sbin/iptables -D OUTPUT -t nat -s $internalip -j LOG --log-prefix "SNAT-OUTPUT"`;
|
1918 |
|
|
# `/sbin/iptables -D PREROUTING -t nat -s $internalip -j LOG --log-prefix "SNAT-PRE"`;
|
1919 |
95b003ff
|
Origo
|
}
|
1920 |
|
|
} elsif ($type eq "externalip") {
|
1921 |
|
|
if ($externalip && $externalip ne "--") {
|
1922 |
|
|
# We are dealing with multiple upstream routes - configure local routing
|
1923 |
|
|
if ($proxynic && $proxynic ne $extnic) {
|
1924 |
|
|
my $proxyroute = `/sbin/ip route show table proxyarp`;
|
1925 |
|
|
`/sbin/ip route del $externalip/32 dev br$id:proxy src $proxyip table proxyarp` if ($proxyroute =~ /$externalip/);
|
1926 |
|
|
}
|
1927 |
|
|
|
1928 |
|
|
eval {`/sbin/ip route del $externalip/32 dev br$id:proxy`; 1;}
|
1929 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem deconfiguring proxy arp $@\n";};
|
1930 |
|
|
|
1931 |
|
|
if ($ports && $ports ne "--") {
|
1932 |
|
|
my @portslist = split(/, ?| /, $ports);
|
1933 |
2a63870a
|
Christian Orellana
|
foreach my $port (@portslist) {
|
1934 |
95b003ff
|
Origo
|
my $ipfilter;
|
1935 |
|
|
if ($port =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)(\/\d+)?:(\d+)/) {
|
1936 |
|
|
my $portip = "$1.$2.$3.$4$5";
|
1937 |
|
|
$port = $6;
|
1938 |
|
|
$ipfilter = "-s $portip";
|
1939 |
|
|
} else {
|
1940 |
|
|
$port = 0 unless ($port =~ /\d+/);
|
1941 |
|
|
}
|
1942 |
|
|
if ($port<1 || $port>65535) {
|
1943 |
|
|
$postreply .= "Status=ERROR Invalid port mapping for $name\n";
|
1944 |
|
|
$ports = "--";
|
1945 |
|
|
last;
|
1946 |
|
|
}
|
1947 |
|
|
|
1948 |
|
|
if ($port>1 || $port<65535) {
|
1949 |
|
|
# repeat for good measure
|
1950 |
2a63870a
|
Christian Orellana
|
for (my $di=0; $di < 10; $di++) {
|
1951 |
|
|
$duprules = 0;
|
1952 |
d24d9a01
|
hq
|
eval {$duprules++ if (`/sbin/iptables -D FORWARD -p tcp -i $proxynic $ipfilter -d $externalip --dport $port -j RETURN`); 1;}
|
1953 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1954 |
d24d9a01
|
hq
|
eval {$duprules++ if (`/sbin/iptables -D FORWARD -p udp -i $proxynic $ipfilter -d $externalip --dport $port -j RETURN`); 1;}
|
1955 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1956 |
2a63870a
|
Christian Orellana
|
last if ($duprules > 1);
|
1957 |
|
|
}
|
1958 |
95b003ff
|
Origo
|
}
|
1959 |
|
|
}
|
1960 |
|
|
}
|
1961 |
2a63870a
|
Christian Orellana
|
# Remove rule to allow forwarding from $externalip
|
1962 |
d24d9a01
|
hq
|
`/sbin/iptables --delete FORWARD --in-interface br$id -s $externalip -j RETURN`;
|
1963 |
95b003ff
|
Origo
|
# Remove rule to disallow setting up a dhcp server
|
1964 |
|
|
eval {`/sbin/iptables -D FORWARD -p udp -i $proxynic -d $externalip --dport 67 -j REJECT`; 1;}
|
1965 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1966 |
|
|
# Leave outgoing connectivity - not
|
1967 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -m state --state ESTABLISHED,RELATED -j RETURN`; 1;}
|
1968 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1969 |
d24d9a01
|
hq
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j RETURN`; 1;}
|
1970 |
95b003ff
|
Origo
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1971 |
|
|
# No need to reject - we reject all per default to the subnet
|
1972 |
|
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j REJECT`; 1;}
|
1973 |
|
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1974 |
|
|
}
|
1975 |
|
|
}
|
1976 |
|
|
# Deconfigure internal dhcp server
|
1977 |
|
|
if ($type eq "internalip" || $type eq "ipmapping") {
|
1978 |
|
|
my $result = removeDHCPAddress($id, $domains, $internalip);
|
1979 |
|
|
if ($result ne "OK") {
|
1980 |
|
|
$e=1;
|
1981 |
|
|
$postreply .= "$result\n";
|
1982 |
|
|
}
|
1983 |
d3d1a2d4
|
Origo
|
} elsif ($type eq "externalip" && $domains) {
|
1984 |
95b003ff
|
Origo
|
my $result = removeDHCPAddress($id, $domains, $externalip);
|
1985 |
|
|
if ($result ne "OK") {
|
1986 |
|
|
$e=1;
|
1987 |
|
|
$postreply .= "$result\n";
|
1988 |
|
|
}
|
1989 |
|
|
}
|
1990 |
|
|
$uistatus = ($e)?"":validateStatus($register{$uuid});
|
1991 |
|
|
if ($uistatus) {
|
1992 |
|
|
$uiuuid = $uuid;
|
1993 |
|
|
$postreply .= "Status=$uistatus OK $action $type $name: $uistatus\n";
|
1994 |
|
|
} else {
|
1995 |
|
|
$postreply .= "Status=ERROR Cannot $action $type $name: $uistatus\n";
|
1996 |
|
|
}
|
1997 |
|
|
$main::syslogit->($user, 'info', "$action network $uuid ($name, $id) -> $uistatus");
|
1998 |
|
|
updateBilling("$uistatus $uuid ($id)");
|
1999 |
d24d9a01
|
hq
|
# $main::updateUI->({tab=>"networks", user=>$user, uuid=>$uiuuid, status=>$uistatus}) if ($uistatus);
|
2000 |
95b003ff
|
Origo
|
return $postreply;
|
2001 |
|
|
}
|
2002 |
|
|
|
2003 |
|
|
sub Stop {
|
2004 |
|
|
my ($id, $action) = @_;
|
2005 |
|
|
# Check if we were passed a uuid
|
2006 |
|
|
if ($id =~ /\-/ && $register{$id} && ($register{$id}->{'user'} eq $user || $isadmin)) {
|
2007 |
|
|
$id = $register{$id}->{'id'}
|
2008 |
|
|
}
|
2009 |
|
|
if ($help) {
|
2010 |
|
|
return <<END
|
2011 |
|
|
GET:uuid:
|
2012 |
|
|
Stops a network by removing gateway. Network must be in status up or nat.
|
2013 |
|
|
END
|
2014 |
|
|
}
|
2015 |
|
|
|
2016 |
|
|
my $idleft = ($id>99)?(substr $id,0,-2)+0 : 0;
|
2017 |
|
|
my $idright = (substr $id,-2) + 0;
|
2018 |
|
|
my $e = 0;
|
2019 |
|
|
# First deactivate all user's networks with same id
|
2020 |
|
|
my @regkeys = (tied %register)->select_where("user = '$user'");
|
2021 |
|
|
foreach my $key (@regkeys) {
|
2022 |
|
|
my $valref = $register{$key};
|
2023 |
|
|
my $cuuid = $valref->{'uuid'};
|
2024 |
|
|
my $ctype = $valref->{'type'};
|
2025 |
|
|
my $cdbuser = $valref->{'user'};
|
2026 |
|
|
my $cid = $valref->{'id'};
|
2027 |
|
|
# Only list networks belonging to current user
|
2028 |
|
|
if ($user eq $cdbuser && $id eq $cid && $ctype ne "gateway") {
|
2029 |
|
|
if ($ctype eq "internalip" || $ctype eq "ipmapping" || $ctype eq "externalip") {
|
2030 |
|
|
my $result = Deactivate($cuuid, 'deactivate');
|
2031 |
|
|
if ($result =~ /\w+=ERROR (.+)/i) {
|
2032 |
|
|
$e = $1;
|
2033 |
|
|
}
|
2034 |
|
|
}
|
2035 |
|
|
}
|
2036 |
|
|
}
|
2037 |
|
|
my $interfaces = `/sbin/ifconfig br$id`;
|
2038 |
|
|
# Only take down interface and vlan if gateway IP is active on interface
|
2039 |
|
|
if ($e) {
|
2040 |
|
|
$postreply .= "Status=Error Not taking down gateway, got an error: $e\n"
|
2041 |
|
|
# } elsif ($interfaces =~ /^$datanic\.$id.+\n.+inet .+10\.$idleft\.$idright\.1/
|
2042 |
|
|
} elsif ($interfaces =~ /10\.$idleft\.$idright\.1/
|
2043 |
|
|
&& !$e) {
|
2044 |
|
|
eval {`/sbin/brctl delif br$id $datanic.$id`; 1;} or do {$e=1;};
|
2045 |
|
|
eval {`/sbin/ifconfig br$id down`; 1;} or do {$e=1;};
|
2046 |
|
|
eval {`/sbin/ifconfig $datanic.$id down`; 1;} or do {$e=1;};
|
2047 |
|
|
eval {`/sbin/vconfig rem $datanic.$id`; 1;} or do {$e=1;};
|
2048 |
|
|
} else {
|
2049 |
|
|
$postreply .= "Status=Error Not taking down interface, gateway 10.$idleft.$idright.1 is not active on interface br$id - $interfaces.\n"
|
2050 |
|
|
}
|
2051 |
|
|
# Remove rule to only forward packets coming from subnet assigned to vlan
|
2052 |
d24d9a01
|
hq
|
# `/sbin/iptables --delete FORWARD --in-interface $datanic.$id ! -s 10.$idleft.$idright.0/24 -j DROP`;
|
2053 |
95b003ff
|
Origo
|
|
2054 |
|
|
$uistatus = ($e)?$uistatus:"down";
|
2055 |
|
|
if ($uistatus eq 'down') {
|
2056 |
|
|
$uiuuid = $uuid;
|
2057 |
|
|
$postreply .= "Status=$uistatus OK $action gateway: $uistatus\n";
|
2058 |
|
|
} else {
|
2059 |
|
|
$postreply .= "Status=Error Cannot $action $type $name: $uistatus\n";
|
2060 |
|
|
}
|
2061 |
|
|
return $postreply;
|
2062 |
|
|
}
|
2063 |
|
|
|
2064 |
|
|
sub getDomains {
|
2065 |
|
|
my $uuid = shift;
|
2066 |
|
|
my $domains;
|
2067 |
|
|
my $domainnames;
|
2068 |
|
|
my @domregvalues = values %domreg;
|
2069 |
|
|
foreach my $domval (@domregvalues) {
|
2070 |
|
|
if (($domval->{'networkuuid1'} eq $uuid || $domval->{'networkuuid2'} eq $uuid || $domval->{'networkuuid3'} eq $uuid)
|
2071 |
|
|
&& $domval->{'user'} eq $user) {
|
2072 |
|
|
$domains .= $domval->{'uuid'} . ", ";
|
2073 |
|
|
$domainnames .= $domval->{'name'} . ", ";
|
2074 |
|
|
}
|
2075 |
|
|
}
|
2076 |
|
|
$domains = substr $domains, 0, -2;
|
2077 |
|
|
$domainnames = substr $domainnames, 0, -2;
|
2078 |
|
|
return ($domains, $domainnames);
|
2079 |
|
|
}
|
2080 |
|
|
|
2081 |
d3d1a2d4
|
Origo
|
sub getSystems {
|
2082 |
|
|
my $uuid = shift;
|
2083 |
|
|
my $systems;
|
2084 |
|
|
my $systemnames;
|
2085 |
|
|
unless (tie(%sysreg,'Tie::DBI', Hash::Merge::merge({table=>'systems'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access systems register"}|; return $res;};
|
2086 |
|
|
my @sysregvalues = values %sysreg;
|
2087 |
|
|
foreach my $sysval (@sysregvalues) {
|
2088 |
|
|
my $networkuuids = $sysval->{'networkuuids'};
|
2089 |
|
|
if ($networkuuids =~ /$uuid/ && $sysval->{'user'} eq $user) {
|
2090 |
|
|
$systems = $sysval->{'uuid'};
|
2091 |
|
|
$systemnames = $sysval->{'name'};
|
2092 |
|
|
last;
|
2093 |
|
|
}
|
2094 |
|
|
}
|
2095 |
|
|
unless ($systems) {
|
2096 |
|
|
my @sysregvalues = values %domreg;
|
2097 |
|
|
foreach my $sysval (@sysregvalues) {
|
2098 |
|
|
my $networkuuids = $sysval->{'networkuuids'};
|
2099 |
|
|
if ($networkuuids =~ /$uuid/ && $sysval->{'user'} eq $user) {
|
2100 |
|
|
$systems = $sysval->{'uuid'};
|
2101 |
|
|
$systemnames = $sysval->{'name'};
|
2102 |
|
|
last;
|
2103 |
|
|
}
|
2104 |
|
|
}
|
2105 |
|
|
}
|
2106 |
|
|
return ($systems, $systemnames);
|
2107 |
|
|
}
|
2108 |
|
|
|
2109 |
95b003ff
|
Origo
|
sub getNextId {
|
2110 |
|
|
# Find the next available vlan id
|
2111 |
|
|
my $reqid = shift;
|
2112 |
|
|
my $username = shift;
|
2113 |
|
|
$username = $user unless ($username);
|
2114 |
|
|
my $nextid = 1;
|
2115 |
|
|
my $vlanstart = $Stabile::config->get('VLAN_RANGE_START');
|
2116 |
|
|
my $vlanend = $Stabile::config->get('VLAN_RANGE_END');
|
2117 |
|
|
|
2118 |
|
|
if ($reqid eq 0 || $reqid == 1) {
|
2119 |
|
|
return $requid;
|
2120 |
|
|
} elsif ($reqid && ($reqid > $vlanend || $reqid < $vlanstart)) {
|
2121 |
|
|
return -1 unless ($isadmin);
|
2122 |
|
|
}
|
2123 |
|
|
|
2124 |
|
|
$reqid = $reqid + 0;
|
2125 |
|
|
|
2126 |
|
|
my %ids;
|
2127 |
|
|
# First check if the user has an existing vlan, if so use the first we find as default value
|
2128 |
|
|
my @regvalues = values %register;
|
2129 |
|
|
@regvalues = (sort {$a->{id} <=> $b->{id}} @regvalues);
|
2130 |
|
|
foreach my $val (@regvalues) { # Traverse all id's in use
|
2131 |
|
|
my $id = 0 + $val->{'id'};
|
2132 |
|
|
my $dbuser = $val->{'user'};
|
2133 |
|
|
if ($id > 1) {
|
2134 |
|
|
if ($username eq $dbuser) { # If a specific id was requested map all id's
|
2135 |
|
|
if (!$reqid) {# If no specific id was asked for, stop now, and use the user's first one
|
2136 |
|
|
$nextid = $id;
|
2137 |
|
|
last;
|
2138 |
|
|
}
|
2139 |
|
|
} else {
|
2140 |
|
|
$ids{$id} = 1; # Mark this id as used (by another user)
|
2141 |
|
|
}
|
2142 |
|
|
}
|
2143 |
|
|
}
|
2144 |
|
|
if ($nextid>1) {
|
2145 |
|
|
return $nextid;
|
2146 |
|
|
} elsif ($reqid) {
|
2147 |
|
|
if (!$ids{$reqid} || $isadmin) { # If an admin is requesting id used by another, assume he knows what he is doing
|
2148 |
|
|
$nextid = $reqid; # Safe to use
|
2149 |
|
|
} else {
|
2150 |
|
|
$nextid = -1; # Id already in use by another
|
2151 |
|
|
}
|
2152 |
|
|
} elsif ($nextid == 1) { # This user is not currently using any vlan's, find the first free one
|
2153 |
|
|
for ($n=$vlanstart; $n<$vlanend; $n++) {
|
2154 |
|
|
if (!$ids{$n}) { # Don't return an id used (by another user)
|
2155 |
|
|
$nextid = $n;
|
2156 |
|
|
last;
|
2157 |
|
|
}
|
2158 |
|
|
}
|
2159 |
|
|
}
|
2160 |
|
|
return $nextid;
|
2161 |
|
|
}
|
2162 |
|
|
|
2163 |
|
|
sub getNextExternalIP {
|
2164 |
|
|
# Find the next available IP
|
2165 |
|
|
my $extip = shift;
|
2166 |
|
|
my $extuuid = shift;
|
2167 |
|
|
my $proxyarp = shift; # Are we trying to assign a proxy arp's external IP?
|
2168 |
|
|
$extip="" if ($extip eq "--");
|
2169 |
|
|
|
2170 |
|
|
my $extipstart;
|
2171 |
|
|
my $extipend;
|
2172 |
|
|
|
2173 |
|
|
if ($proxyarp) {
|
2174 |
|
|
$extipstart = $Stabile::config->get('PROXY_IP_RANGE_START');
|
2175 |
|
|
$extipend = $Stabile::config->get('PROXY_IP_RANGE_END');
|
2176 |
|
|
} else {
|
2177 |
|
|
$extipstart = $Stabile::config->get('EXTERNAL_IP_RANGE_START');
|
2178 |
|
|
$extipend = $Stabile::config->get('EXTERNAL_IP_RANGE_END');
|
2179 |
|
|
}
|
2180 |
|
|
|
2181 |
|
|
return "" unless ($extipstart && $extipend);
|
2182 |
|
|
|
2183 |
|
|
my $interfaces = `/sbin/ifconfig`;
|
2184 |
|
|
# $interfaces =~ m/eth0 .+\n.+inet addr:(\d+\.\d+\.\d+)\.(\d+)/;
|
2185 |
|
|
$extipstart =~ m/(\d+\.\d+\.\d+)\.(\d+)/;
|
2186 |
|
|
my $bnet1 = $1;
|
2187 |
|
|
my $bhost1 = $2+0;
|
2188 |
|
|
$extipend =~ m/(\d+\.\d+\.\d+)\.(\d+)/;
|
2189 |
|
|
my $bnet2 = $1;
|
2190 |
|
|
my $bhost2 = $2+0;
|
2191 |
|
|
my $nextip = "";
|
2192 |
|
|
if ($bnet1 ne $bnet2) {
|
2193 |
|
|
print "Status=ERROR Only 1 class C subnet is supported for $name\n";
|
2194 |
|
|
return "";
|
2195 |
|
|
}
|
2196 |
|
|
my %ids;
|
2197 |
|
|
# First create map of IP's reserved by other servers in DB
|
2198 |
|
|
my @regvalues = values %register;
|
2199 |
|
|
foreach my $val (@regvalues) {
|
2200 |
|
|
my $ip = $val->{'externalip'};
|
2201 |
|
|
# $ip =~ m/(\d+\.\d+\.\d+)\.(\d+)/;
|
2202 |
|
|
# my $id = $2;
|
2203 |
|
|
$ids{$ip} = $val->{'uuid'} unless ($extuuid eq $val->{'uuid'});
|
2204 |
|
|
}
|
2205 |
54401133
|
hq
|
my $oc = overQuotas(1);
|
2206 |
|
|
if ($oc) { # Enforce quotas
|
2207 |
95b003ff
|
Origo
|
$postreply .= "Status=ERROR Over quota allocating external IP\n";
|
2208 |
|
|
} elsif ($extip && $extip =~ m/($bnet1)\.(\d+)/ && $2>=$bhost1 && $2<$bhost2) {
|
2209 |
|
|
# An external ip was supplied - check if it's free and ok
|
2210 |
|
|
if (!$ids{$extip} && !($interfaces =~ m/$extip.+\n.+inet addr:$extip/) && $extip=~/$bnet$\.(\d)/) {
|
2211 |
|
|
$nextip = $extip;
|
2212 |
|
|
}
|
2213 |
|
|
} else {
|
2214 |
|
|
# Find random IP not reserved, and check it is not in use (for other purposes)
|
2215 |
|
|
my @bhosts = ($bhost1..$bhost2);
|
2216 |
|
|
my @rbhosts = shuffle @bhosts;
|
2217 |
|
|
for ($n=0; $n<$bhost2-$bhost1; $n++) {
|
2218 |
|
|
my $nb = $rbhosts[$n];
|
2219 |
|
|
if (!$ids{"$bnet1.$nb"}) {
|
2220 |
|
|
if (!($interfaces =~ m/$extip.+\n.+inet addr:$bnet1\.$nb/)) {
|
2221 |
|
|
$nextip = "$bnet1.$nb";
|
2222 |
|
|
last;
|
2223 |
|
|
}
|
2224 |
|
|
}
|
2225 |
|
|
}
|
2226 |
|
|
}
|
2227 |
54401133
|
hq
|
$postreply .= "Status=ERROR No more ($oc) external IPs available\n" unless ($nextip);
|
2228 |
95b003ff
|
Origo
|
return $nextip;
|
2229 |
|
|
}
|
2230 |
|
|
|
2231 |
|
|
sub ip2domain {
|
2232 |
|
|
my $ip = shift;
|
2233 |
|
|
my $ruuid;
|
2234 |
|
|
if ($ip) {
|
2235 |
|
|
my @regkeys = (tied %register)->select_where("internalip = '$ip' OR externalip = '$ip'");
|
2236 |
|
|
foreach my $k (@regkeys) {
|
2237 |
|
|
my $valref = $register{$k};
|
2238 |
|
|
if ($valref->{'internalip'} eq $ip || $valref->{'externalip'} eq $ip) {
|
2239 |
|
|
$ruuid = $valref->{'domains'};
|
2240 |
|
|
last;
|
2241 |
|
|
}
|
2242 |
|
|
}
|
2243 |
|
|
}
|
2244 |
|
|
return $ruuid;
|
2245 |
|
|
}
|
2246 |
|
|
|
2247 |
|
|
sub getNextInternalIP {
|
2248 |
|
|
my $intip = shift;
|
2249 |
|
|
my $uuid = shift;
|
2250 |
|
|
my $id = shift;
|
2251 |
|
|
my $username = shift;
|
2252 |
|
|
$username = $user unless ($username);
|
2253 |
|
|
my $nextip = "";
|
2254 |
|
|
my $intipnum;
|
2255 |
|
|
my $subnet;
|
2256 |
|
|
my %ids;
|
2257 |
|
|
my $ping = Net::Ping->new();
|
2258 |
|
|
|
2259 |
|
|
$id = getNextId() unless ($id);
|
2260 |
|
|
my $idleft = ($id>99)?(substr $id,0,-2)+0 : 0;
|
2261 |
|
|
my $idright = (substr $id,-2) + 0;
|
2262 |
|
|
$intip = "10.$idleft.$idright.0" if (!$intip || $intip eq '--');
|
2263 |
|
|
|
2264 |
|
|
return '' unless ($intip =~ m/(\d+\.\d+\.\d+)\.(\d+)/ );
|
2265 |
|
|
$subnet = $1;
|
2266 |
|
|
$intipnum = $2;
|
2267 |
|
|
|
2268 |
|
|
# First create hash of IP's reserved by other servers in DB
|
2269 |
|
|
my @regvalues = values %register;
|
2270 |
|
|
foreach my $val (@regvalues) {
|
2271 |
|
|
if ($val->{'user'} eq $username) {
|
2272 |
|
|
my $ip = $val->{'internalip'} ;
|
2273 |
|
|
$ids{$ip} = $val->{'uuid'};
|
2274 |
|
|
}
|
2275 |
|
|
}
|
2276 |
|
|
|
2277 |
|
|
if ($intipnum && $intipnum>1 && $intipnum<255) {
|
2278 |
|
|
# An internal ip was supplied - check if it's free, if not keep the ip already registered in the db
|
2279 |
|
|
if (!$ids{$intip}
|
2280 |
|
|
# && !($ping->ping($intip, 0.1)) # 0.1 secs timeout, check if ip is in use, possibly on another engine
|
2281 |
|
|
&& !(`arping -C1 -c2 -D -I $datanic.$id $intip` =~ /reply from/) # check if ip is created on another engine
|
2282 |
|
|
) {
|
2283 |
|
|
$nextip = $intip;
|
2284 |
|
|
} else {
|
2285 |
|
|
$nextip = $register{$uuid}->{'internalip'}
|
2286 |
|
|
}
|
2287 |
|
|
} else {
|
2288 |
|
|
# Find first IP not reserved
|
2289 |
|
|
for ($n=2; $n<255; $n++) {
|
2290 |
|
|
if (!$ids{"$subnet.$n"}
|
2291 |
|
|
# TODO: The arping check takes too long - two networks created by the same user can too easily be assigned the same IP's
|
2292 |
|
|
# && !(`arping -f -c2 -D -I $datanic.$id $subnet.$n` =~ /reply from/) # check if ip is created on another engine
|
2293 |
|
|
) {
|
2294 |
|
|
$nextip = "$subnet.$n";
|
2295 |
|
|
last;
|
2296 |
|
|
}
|
2297 |
|
|
}
|
2298 |
|
|
}
|
2299 |
|
|
$postreply .= "Status=ERROR No more internal IPs available\n" if (!$nextip);
|
2300 |
|
|
return $nextip;
|
2301 |
|
|
}
|
2302 |
|
|
|
2303 |
|
|
sub validateStatus {
|
2304 |
|
|
my $valref = shift;
|
2305 |
|
|
|
2306 |
|
|
my $interfaces = `/sbin/ifconfig`;
|
2307 |
|
|
my $uuid = $valref->{'uuid'};
|
2308 |
|
|
my $type = $valref->{'type'};
|
2309 |
|
|
my $id = $valref->{'id'};
|
2310 |
|
|
my $idleft = ($id>99)?(substr $id,0,-2)+0 : 0;
|
2311 |
|
|
my $idright = (substr $id,-2) + 0;
|
2312 |
|
|
|
2313 |
|
|
( $valref->{'domains'}, $valref->{'domainnames'} ) = getDomains($uuid);
|
2314 |
d3d1a2d4
|
Origo
|
my ( $systems, $systemnames ) = getSystems($uuid);
|
2315 |
95b003ff
|
Origo
|
my $extip = $valref->{'externalip'};
|
2316 |
|
|
my $intip = $valref->{'internalip'};
|
2317 |
|
|
|
2318 |
|
|
if ($type eq "gateway") {
|
2319 |
|
|
$valref->{'internalip'} = "10.$idleft.$idright.1" if ($id>1);
|
2320 |
|
|
} else {
|
2321 |
|
|
$type = "gateway";
|
2322 |
|
|
if ($intip && $intip ne "--" && $extip && $extip ne "--") {
|
2323 |
|
|
$type = "ipmapping";
|
2324 |
|
|
} elsif ($intip && $intip ne "--") {
|
2325 |
|
|
$type = "internalip";
|
2326 |
|
|
} elsif ($extip && $extip ne "--") {
|
2327 |
|
|
$type = "externalip";
|
2328 |
|
|
}
|
2329 |
|
|
$valref->{'type'} = $type;
|
2330 |
|
|
}
|
2331 |
|
|
|
2332 |
|
|
$valref->{'status'} = "down";
|
2333 |
|
|
my $nat;
|
2334 |
|
|
if ($id == 0 || $id == 1) {
|
2335 |
|
|
$valref->{'status'} = "nat";
|
2336 |
|
|
# Check if vlan $id is created (and doing nat)
|
2337 |
|
|
# } elsif ($interfaces =~ m/$datanic\.$id.+\n.+10\.$idleft\.$idright\.1/) {
|
2338 |
|
|
} elsif (-e "/proc/net/vlan/$datanic.$id") {
|
2339 |
|
|
$nat = 1;
|
2340 |
|
|
}
|
2341 |
d24d9a01
|
hq
|
|
2342 |
95b003ff
|
Origo
|
if (($type eq "internalip" || $type eq "ipmapping")) { # && $val->{'domains'}) {
|
2343 |
|
|
$valref->{'status'} = "nat" if ($nat);
|
2344 |
|
|
my $dhcprunning;
|
2345 |
|
|
my $dhcpconfigured;
|
2346 |
|
|
eval {
|
2347 |
|
|
my $psid;
|
2348 |
|
|
$psid = `/bin/cat /var/run/stabile-$id.pid` if (-e "/var/run/stabile-$id.pid");
|
2349 |
|
|
chomp $psid;
|
2350 |
|
|
$dhcprunning = -e "/proc/$psid" if ($psid);
|
2351 |
|
|
my $dhcphosts;
|
2352 |
|
|
$dhcphosts = lc `/bin/cat $etcpath/dhcp-hosts-$id` if (-e "$etcpath/dhcp-hosts-$id");
|
2353 |
|
|
$dhcpconfigured = ($dhcphosts =~ /$intip/);
|
2354 |
|
|
1;
|
2355 |
|
|
} or do {;};
|
2356 |
|
|
|
2357 |
|
|
if ($type eq "internalip") {
|
2358 |
|
|
# Check if external ip has been created and dhcp is ok
|
2359 |
d3d1a2d4
|
Origo
|
if ($nat && (($dhcprunning && $dhcpconfigured) || $systems)) {
|
2360 |
95b003ff
|
Origo
|
$valref->{'status'} = "up";
|
2361 |
|
|
}
|
2362 |
|
|
} elsif ($type eq "ipmapping") {
|
2363 |
|
|
# Check if external ip has been created, dhcp is ok and vlan interface is created
|
2364 |
d3d1a2d4
|
Origo
|
# An ipmapping linked to a system is considered up if external interface exists
|
2365 |
|
|
if ($nat && $interfaces =~ m/$extip/ && (($dhcprunning && $dhcpconfigured) || $systems)) {
|
2366 |
95b003ff
|
Origo
|
$valref->{'status'} = "up";
|
2367 |
|
|
}
|
2368 |
|
|
}
|
2369 |
|
|
|
2370 |
|
|
} elsif ($type eq "externalip") {
|
2371 |
|
|
my $dhcprunning;
|
2372 |
|
|
my $dhcpconfigured;
|
2373 |
|
|
eval {
|
2374 |
|
|
my $psid;
|
2375 |
|
|
$psid = `/bin/cat /var/run/stabile-$id.pid` if (-e "/var/run/stabile-$id.pid");
|
2376 |
|
|
chomp $psid;
|
2377 |
|
|
$dhcprunning = -e "/proc/$psid" if ($psid);
|
2378 |
|
|
my $dhcphosts;
|
2379 |
|
|
$dhcphosts = `/bin/cat $etcpath/dhcp-hosts-$id` if (-e "$etcpath/dhcp-hosts-$id");
|
2380 |
|
|
$dhcpconfigured = ($dhcphosts =~ /$extip/);
|
2381 |
|
|
1;
|
2382 |
|
|
} or do {;};
|
2383 |
|
|
|
2384 |
|
|
my $vproxy = `/bin/cat /proc/sys/net/ipv4/conf/$datanic.$id/proxy_arp`; chomp $vproxy;
|
2385 |
|
|
my $eproxy = `/bin/cat /proc/sys/net/ipv4/conf/$proxynic/proxy_arp`; chomp $eproxy;
|
2386 |
|
|
my $proute = `/sbin/ip route | grep "$extip dev"`; chomp $proute;
|
2387 |
d3d1a2d4
|
Origo
|
if ($vproxy && $eproxy && $proute) {
|
2388 |
|
|
if ((($dhcprunning && $dhcpconfigured) || $systems)) {
|
2389 |
|
|
$valref->{'status'} = "up";
|
2390 |
|
|
} elsif (!$valref->{'domains'}) {
|
2391 |
|
|
$valref->{'status'} = "nat";
|
2392 |
|
|
}
|
2393 |
95b003ff
|
Origo
|
} else {
|
2394 |
|
|
#print "$vproxy && $eproxy && $proute && $dhcprunning && $dhcpconfigured :: $extip\n";
|
2395 |
|
|
}
|
2396 |
|
|
|
2397 |
|
|
} elsif ($type eq "gateway") {
|
2398 |
|
|
if ($nat || $id == 0 || $id == 1) {$valref->{'status'} = "up";}
|
2399 |
|
|
}
|
2400 |
|
|
return $valref->{'status'};
|
2401 |
|
|
}
|
2402 |
|
|
|
2403 |
|
|
sub trim{
|
2404 |
|
|
my $string = shift;
|
2405 |
|
|
$string =~ s/^\s+|\s+$//g;
|
2406 |
|
|
return $string;
|
2407 |
|
|
}
|
2408 |
|
|
|
2409 |
|
|
sub overQuotas {
|
2410 |
|
|
my $reqips = shift; # number of new ip's we are asking for
|
2411 |
|
|
my $usedexternalips = 0;
|
2412 |
|
|
my $overquota = 0;
|
2413 |
|
|
return $overquota if ($Stabile::userprivileges =~ /a/); # Don't enforce quotas for admins
|
2414 |
|
|
|
2415 |
54401133
|
hq
|
my $externalipquota = $Stabile::userexternalipquota;
|
2416 |
95b003ff
|
Origo
|
if (!$externalipquota) {
|
2417 |
|
|
$externalipquota = $Stabile::config->get('EXTERNAL_IP_QUOTA');
|
2418 |
|
|
}
|
2419 |
|
|
|
2420 |
54401133
|
hq
|
my $rxquota = $Stabile::userrxquota;
|
2421 |
95b003ff
|
Origo
|
if (!$rxquota) {
|
2422 |
|
|
$rxquota = $Stabile::config->get('RX_QUOTA');
|
2423 |
|
|
}
|
2424 |
|
|
|
2425 |
54401133
|
hq
|
my $txquota = $Stabile::usertxquota;
|
2426 |
95b003ff
|
Origo
|
if (!$txquota) {
|
2427 |
|
|
$txquota = $Stabile::config->get('TX_QUOTA');
|
2428 |
|
|
}
|
2429 |
|
|
|
2430 |
|
|
my @regkeys = (tied %register)->select_where("user = '$user'");
|
2431 |
|
|
foreach my $k (@regkeys) {
|
2432 |
|
|
my $val = $register{$k};
|
2433 |
|
|
if ($val->{'user'} eq $user && $val->{'externalip'} && $val->{'externalip'} ne "--" ) {
|
2434 |
|
|
$usedexternalips += 1;
|
2435 |
|
|
}
|
2436 |
|
|
}
|
2437 |
54401133
|
hq
|
if ((($usedexternalips + $reqips) > $externalipquota) && $externalipquota > 0) { # -1 means no quota
|
2438 |
95b003ff
|
Origo
|
$overquota = $usedexternalips;
|
2439 |
|
|
} elsif ($rx > $rxquota*1024 && $rxquota > 0) {
|
2440 |
|
|
$overquota = -1;
|
2441 |
|
|
} elsif ($tx > $txquota*1024 && $txquota > 0) {
|
2442 |
|
|
$overquota = -2;
|
2443 |
|
|
}
|
2444 |
|
|
return $overquota;
|
2445 |
|
|
}
|
2446 |
|
|
|
2447 |
|
|
sub updateBilling {
|
2448 |
|
|
my $event = shift;
|
2449 |
|
|
my %billing;
|
2450 |
|
|
my @regkeys = (tied %register)->select_where("user = '$user' or user = 'common'") unless ($fulllist);
|
2451 |
|
|
foreach my $k (@regkeys) {
|
2452 |
|
|
my $valref = $register{$k};
|
2453 |
|
|
my %val = %{$valref}; # Deference and assign to new array, effectively cloning object
|
2454 |
|
|
if ($val{'user'} eq $user && ($val{'type'} eq 'ipmapping' || $val{'type'} eq 'externalip') && $val{'externalip'} ne '--') {
|
2455 |
|
|
$billing{$val{'id'}}->{'externalip'} += 1;
|
2456 |
|
|
}
|
2457 |
|
|
}
|
2458 |
|
|
|
2459 |
|
|
my %billingreg;
|
2460 |
|
|
my $monthtimestamp = timelocal(0,0,0,1,$mon,$year); #$sec,$min,$hour,$mday,$mon,$year
|
2461 |
|
|
|
2462 |
|
|
unless ( tie(%billingreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_networks', key=>'useridtime'}, $Stabile::dbopts)) ) {return "Unable to access billing register"};
|
2463 |
|
|
|
2464 |
|
|
my $rx_bytes_total = 0;
|
2465 |
|
|
my $tx_bytes_total = 0;
|
2466 |
|
|
|
2467 |
|
|
my $prevmonth = $month-1;
|
2468 |
|
|
my $prevyear = $year;
|
2469 |
|
|
if ($prevmonth == 0) {$prevmonth=12; $prevyear--;};
|
2470 |
|
|
$prevmonth = substr("0" . $prevmonth, -2);
|
2471 |
|
|
my $prev_rx_bytes_total = 0;
|
2472 |
|
|
my $prev_tx_bytes_total = 0;
|
2473 |
|
|
|
2474 |
|
|
foreach my $id (keys %billing) {
|
2475 |
|
|
my $b = $billing{$id};
|
2476 |
|
|
my $externalip = $b->{'externalip'};
|
2477 |
|
|
my $externalipavg = 0;
|
2478 |
|
|
my $startexternalipavg = 0;
|
2479 |
|
|
my $starttimestamp = $current_time;
|
2480 |
|
|
my $rx_bytes = 0;
|
2481 |
|
|
my $tx_bytes = 0;
|
2482 |
|
|
my $rx_stats = "/sys/class/net/$datanic.$id/statistics/rx_bytes";
|
2483 |
|
|
my $tx_stats = "/sys/class/net/$datanic.$id/statistics/tx_bytes";
|
2484 |
|
|
$rx_bytes = `/bin/cat $rx_stats` if (-e $rx_stats);
|
2485 |
|
|
chomp $rx_bytes;
|
2486 |
|
|
$tx_bytes = `/bin/cat $tx_stats` if (-e $tx_stats);
|
2487 |
|
|
chomp $tx_bytes;
|
2488 |
|
|
|
2489 |
|
|
if ($current_time - $monthtimestamp < 4*3600) {
|
2490 |
|
|
$starttimestamp = $monthtimestamp;
|
2491 |
|
|
$externalipavg = $externalip;
|
2492 |
|
|
$startexternalipavg = $externalip;
|
2493 |
|
|
}
|
2494 |
|
|
|
2495 |
|
|
my $bill = $billingreg{"$user-$id-$year-$month"};
|
2496 |
|
|
my $regrx_bytes = $bill->{'rx'};
|
2497 |
|
|
my $regtx_bytes = $bill->{'tx'};
|
2498 |
|
|
$rx_bytes += $regrx_bytes if ($regrx_bytes > $rx_bytes); # Network interface was reloaded
|
2499 |
|
|
$tx_bytes += $regtx_bytes if ($regtx_bytes > $tx_bytes); # Network interface was reloaded
|
2500 |
|
|
|
2501 |
|
|
# Update timestamp and averages on existing row
|
2502 |
|
|
if ($billingreg{"$user-$id-$year-$month"}) {
|
2503 |
|
|
$startexternalipavg = $bill->{'startexternalipavg'};
|
2504 |
|
|
$starttimestamp = $bill->{'starttimestamp'};
|
2505 |
|
|
|
2506 |
|
|
$externalipavg = ($startexternalipavg*($starttimestamp - $monthtimestamp) + $externalip*($current_time - $starttimestamp)) /
|
2507 |
|
|
($current_time - $monthtimestamp);
|
2508 |
|
|
|
2509 |
|
|
$billingreg{"$user-$id-$year-$month"}->{'externalip'} = $externalip;
|
2510 |
|
|
$billingreg{"$user-$id-$year-$month"}->{'externalipavg'} = $externalipavg;
|
2511 |
|
|
$billingreg{"$user-$id-$year-$month"}->{'timestamp'} = $current_time;
|
2512 |
|
|
$billingreg{"$user-$id-$year-$month"}->{'rx'} = $rx_bytes;
|
2513 |
|
|
$billingreg{"$user-$id-$year-$month"}->{'tx'} = $tx_bytes;
|
2514 |
|
|
}
|
2515 |
|
|
|
2516 |
|
|
# No row found or something happened which justifies writing a new row
|
2517 |
|
|
if (!$billingreg{"$user-$id-$year-$month"}
|
2518 |
|
|
|| ($b->{'externalip'} != $bill->{'externalip'})
|
2519 |
|
|
) {
|
2520 |
|
|
|
2521 |
|
|
my $inc = 0;
|
2522 |
|
|
if ($billingreg{"$user-$id-$year-$month"}) {
|
2523 |
|
|
$startexternalipavg = $externalipavg;
|
2524 |
|
|
$starttimestamp = $current_time;
|
2525 |
|
|
$inc = $bill->{'inc'};
|
2526 |
|
|
}
|
2527 |
|
|
# Write a new row
|
2528 |
|
|
$billingreg{"$user-$id-$year-$month"} = {
|
2529 |
|
|
externalip=>$externalip+0,
|
2530 |
|
|
externalipavg=>$externalipavg,
|
2531 |
|
|
startexternalipavg=>$startexternalipavg,
|
2532 |
|
|
timestamp=>$current_time,
|
2533 |
|
|
starttimestamp=>$starttimestamp,
|
2534 |
|
|
event=>$event,
|
2535 |
|
|
inc=>$inc+1,
|
2536 |
|
|
rx=>$rx_bytes,
|
2537 |
|
|
tx=>$tx_bytes
|
2538 |
|
|
};
|
2539 |
|
|
}
|
2540 |
|
|
|
2541 |
|
|
$rx_bytes_total += $rx_bytes;
|
2542 |
|
|
$tx_bytes_total += $tx_bytes;
|
2543 |
|
|
my $prevbill = $billingreg{"$user-$id-$prevyear-$prevmonth"};
|
2544 |
|
|
$prev_rx_bytes_total += $prevbill->{'rx'};
|
2545 |
|
|
$prev_tx_bytes_total += $prevbill->{'tx'};
|
2546 |
|
|
}
|
2547 |
|
|
untie %billingreg;
|
2548 |
|
|
$rx = ($rx_bytes_total>$prev_rx_bytes_total)?$rx_bytes_total - $prev_rx_bytes_total:$rx_bytes_total;
|
2549 |
|
|
$tx = ($tx_bytes_total>$prev_tx_bytes_total)?$tx_bytes_total - $prev_tx_bytes_total:$tx_bytes_total;
|
2550 |
|
|
my $oq = overQuotas();
|
2551 |
54401133
|
hq
|
if ($oq && $oq<0) {
|
2552 |
95b003ff
|
Origo
|
foreach my $id (keys %billing) {
|
2553 |
|
|
$main::syslogit->($user, 'info', "$user over rx/tx quota ($oq) stopping network $id");
|
2554 |
|
|
Stop($id, 'stop');
|
2555 |
|
|
}
|
2556 |
|
|
}
|
2557 |
|
|
}
|
2558 |
|
|
|
2559 |
|
|
sub Bit2netmask {
|
2560 |
|
|
my $netbit = shift;
|
2561 |
|
|
my $_bit = ( 2 ** (32 - $netbit) ) - 1;
|
2562 |
|
|
my ($full_mask) = unpack( "N", pack( "C4", split(/./, '255.255.255.255') ) );
|
2563 |
|
|
my $netmask = join( '.', unpack( "C4", pack( "N", ( $full_mask ^ $_bit ) ) ) );
|
2564 |
|
|
return $netmask;
|
2565 |
|
|
} |