1
|
#!/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
|
($datanic, $extnic) = $main::getNics->();
|
23
|
$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
|
$enginelinked = $Stabile::config->get('ENGINE_LINKED') || "";
|
31
|
|
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
|
my $obj;
|
73
|
$action = $action || $h{'action'};
|
74
|
if (
|
75
|
$action =~ /^dns/
|
76
|
) {
|
77
|
$obj = \%h;
|
78
|
return $obj;
|
79
|
}
|
80
|
$uuid = $curuuid if ($uuid eq 'this');
|
81
|
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
|
my $dbobj = $register{$uuid} || {};
|
90
|
my $status = $dbobj->{'status'} || $h{"status"}; # Trust db status if it exists
|
91
|
if ((!$uuid && $uuid ne '0') && (!$status || $status eq 'new') && ($action eq 'save')) {
|
92
|
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
|
my $systems = $h{"systems"} || $dbobj->{'systems'};
|
120
|
my $force = $h{"force"};
|
121
|
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
|
if (($user ne $reguser && index($privileges,"a")==-1 && $action ne 'save' ) ||
|
133
|
($reguser && $status eq "new"))
|
134
|
{
|
135
|
$postreply .= "Stroke=ERROR Bad user: $user, $action\n";
|
136
|
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
|
}
|
145
|
|
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
|
systems => $systems,
|
156
|
force => $force,
|
157
|
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
|
my ($uuid, $action, $obj) = @_;
|
213
|
if ($help) {
|
214
|
return <<END
|
215
|
GET:uuid:
|
216
|
List networks current user has access to.
|
217
|
END
|
218
|
}
|
219
|
|
220
|
my $res;
|
221
|
my $filter;
|
222
|
my $statusfilter;
|
223
|
my $uuidfilter;
|
224
|
$uuid = $obj->{'uuid'} if ($obj->{'uuid'});
|
225
|
|
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
|
$uuidfilter = $2;
|
233
|
} elsif ($uuid) {
|
234
|
$uuidfilter = $uuid;
|
235
|
}
|
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
|
# updateBilling();
|
253
|
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
|
$val{'domainnames'} = decode('utf8', $val{'domainnames'});
|
279
|
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
|
if (($id>0 || index($privileges,"a")!=-1) && ((!$valref->{'domains'} && !$valref->{'systems'}) || $type eq 'gateway' || ($curnetwork eq $uuid && !$curnetwork1) || $curnetwork1 eq $uuid)) {
|
297
|
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
|
sub do_dnslist {
|
455
|
my ($uuid, $action) = @_;
|
456
|
if ($help) {
|
457
|
return <<END
|
458
|
GET:domain:
|
459
|
Lists entries in [domain] or if not specified, the default zone: $dnsdomain.
|
460
|
END
|
461
|
}
|
462
|
|
463
|
my $res = $main::dnsList->($engineid, $user, $params{'domain'});
|
464
|
return $res;
|
465
|
}
|
466
|
|
467
|
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
|
sub do_dnscreate {
|
480
|
my ($uuid, $action) = @_;
|
481
|
if ($help) {
|
482
|
return <<END
|
483
|
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
|
END
|
487
|
}
|
488
|
|
489
|
my $res = $main::dnsCreate->($engineid, $params{'name'}, $params{'value'}, $params{'type'}, $user);
|
490
|
return $res;
|
491
|
}
|
492
|
|
493
|
sub do_dnsupdate {
|
494
|
my ($uuid, $action, $obj) = @_;
|
495
|
if ($help) {
|
496
|
return <<END
|
497
|
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
|
END
|
500
|
}
|
501
|
|
502
|
my $res = $main::dnsUpdate->($engineid, $obj->{'name'}, $obj->{'value'}, $obj->{'type'}, $obj->{'oldname'}, $obj->{'oldvalue'}, $user);
|
503
|
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
|
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
|
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
|
&& $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
|
GET:name, value, type:
|
561
|
Delete a DNS record in the configured zone.
|
562
|
END
|
563
|
}
|
564
|
|
565
|
my $res = $main::dnsDelete->($engineid, $params{'name'}, $params{'value'}, $params{'type'}, $user);
|
566
|
return $res;
|
567
|
}
|
568
|
|
569
|
sub do_getappstoreurl {
|
570
|
my ($uuid, $action) = @_;
|
571
|
if ($help) {
|
572
|
return <<END
|
573
|
GET::
|
574
|
Get URL to the app store belonging to engine or user (uverrides engine default).
|
575
|
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
|
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
|
sub do_getdnsdomain {
|
608
|
my ($uuid, $action) = @_;
|
609
|
if ($help) {
|
610
|
return <<END
|
611
|
GET::
|
612
|
Get the default DNS domain and the subdomain this Engine registers entries in.
|
613
|
END
|
614
|
}
|
615
|
my $domain = ($enginelinked)?$dnsdomain:'';
|
616
|
my $subdomain = ($enginelinked)?substr($engineid, 0, 8):'';
|
617
|
my $linked = ($enginelinked)?'true':'false';
|
618
|
my $res;
|
619
|
$res .= header('application/json') unless $console;
|
620
|
$res .= qq|{"domain": "$domain", "subdomain": "$subdomain", "enginelinked": "$linked"}|;
|
621
|
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
|
# 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
|
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
|
# Turns out the VM's gateway has to be $proxyip and not $proxygw in our proxyarp setup
|
912
|
print TEMP1 <<END;
|
913
|
tag:external,option:router,$proxyip
|
914
|
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
|
$main::syslogit->($user, 'info', "HUPing dnsmasq 1: $id");
|
927
|
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
|
# 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
|
|
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
|
} or do {$error .= "Status=ERROR Problem deconfiguring dhcp for $name $@\n";};
|
961
|
|
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
|
$main::syslogit->($user, 'info', "Releasing dhcp lease: br$id $dhcpip $1");
|
970
|
`/usr/bin/dhcp_release br$id $dhcpip $1`;
|
971
|
} elsif ($mac && $line =~ /^$mac/i) {
|
972
|
# If we find a stale assigment to the mac we are removing, remove this also
|
973
|
$main::syslogit->($user, 'info', "Releasing stale dhcp lease: br$id $dhcpip $mac");
|
974
|
`/usr/bin/dhcp_release br$id $dhcpip $mac`;
|
975
|
} 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
|
$main::syslogit->($user, 'info', "HUPing dnsmasq 2: $id");
|
990
|
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
|
# 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
|
# 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
|
POST:uuid, id, name, internalip, externalip, ports, type, systems, activate:
|
1032
|
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
|
For now, [activate] only has effect when creating a new connection with a linked system/server.
|
1035
|
END
|
1036
|
}
|
1037
|
$uuid = $obj->{'uuid'} if ($obj->{'uuid'});
|
1038
|
my $regnet = $register{$uuid};
|
1039
|
my $id = $obj->{id};
|
1040
|
my $name = $obj->{name};
|
1041
|
my $status = $obj->{status};
|
1042
|
my $type = $obj->{type} || $regnet->{type};
|
1043
|
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
|
my $systems = $obj->{systems}; # Optionally link this network to a system
|
1049
|
|
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
|
my $systemnames = $regnet->{'systemnames'};
|
1066
|
|
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
|
$regnet->{'systems'} ne $systems ||
|
1125
|
$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
|
$main::dnsCreate->($engineid, $externalip, $externalip, 'A', $user);
|
1139
|
}
|
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
|
$postreply .= "Status=OK Trying to register DNS ";
|
1152
|
$main::dnsCreate->($engineid, $externalip, $externalip, 'A', $user);
|
1153
|
}
|
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
|
$postreply .= "Status=OK Allocated internal IP: $internalip for $name\n" unless ($regnet->{'internalip'} eq $internalip);
|
1175
|
}
|
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
|
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
|
$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
|
systems=>$systems,
|
1242
|
systemnames=>$systemnames,
|
1243
|
action=>""
|
1244
|
};
|
1245
|
my $res = tied(%register)->commit;
|
1246
|
my $obj = $register{$uuid};
|
1247
|
$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
|
$postmsg = "Created connection $name";
|
1252
|
$uiupdatetype = "update";
|
1253
|
}
|
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
|
$postmsg = $postmsg || "OK, updated network $name";
|
1267
|
}
|
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
|
$postmsg = "OK, updated network $name";
|
1284
|
}
|
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
|
my ($uuid, $action, $obj) = @_;
|
1300
|
if ($help) {
|
1301
|
return <<END
|
1302
|
GET:uuid:
|
1303
|
Activate a network which must be in status down or nat.
|
1304
|
END
|
1305
|
}
|
1306
|
$uuid = $obj->{'uuid'} if ($obj->{'uuid'});
|
1307
|
$action = 'activate' || $action;
|
1308
|
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
|
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
|
if ($action eq "activate") { #} && $domains) {
|
1365
|
if ($type eq "internalip" || $type eq "ipmapping") {
|
1366
|
# 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
|
}
|
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
|
# Manuipulate NFS exports and related disk quotas
|
1396
|
foreach my $p (@spl) {
|
1397
|
if ($tenderlist[$p] && $tenderpathslist[$p]) {
|
1398
|
my $fuelpath = $tenderpathslist[$p] . "/$user/fuel";
|
1399
|
unless (-e $fuelpath) {
|
1400
|
if ($tenderlist[$p] eq 'local') { # We only support fuel on local tender for now
|
1401
|
`mkdir "$fuelpath"`;
|
1402
|
`chmod 777 "$fuelpath"`;
|
1403
|
}
|
1404
|
}
|
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
|
`setquota -u irigo-$user $nfsquota $nfsquota 0 0 "$mpoint"` if (-e "$mntpoint");
|
1416
|
if (!(`grep "$fuelpath 10\.$idleft\.$idright" /etc/exports`) && -e $fuelpath) {
|
1417
|
`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
|
# A proxy is needed to route traffic, don't go any further if not configured
|
1427
|
if ($proxyip) {
|
1428
|
# Set up proxy
|
1429
|
if (!($interfaces =~ m/$proxyip/ && $interfaces =~ m/br$id:proxy/)) {
|
1430
|
eval {`/sbin/ifconfig br$id:proxy $proxyip/$proxysubnet up`; 1;}
|
1431
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up proxy arp gw $proxyip on br$id:proxy $@\n";};
|
1432
|
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
|
my $result = "OK";
|
1436
|
# Configure dhcp server
|
1437
|
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
|
}
|
1446
|
} else {
|
1447
|
$postreply .= "Status=ERROR Cannot set up external IP without Proxy ARP gateway\n";
|
1448
|
}
|
1449
|
}
|
1450
|
|
1451
|
# 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
|
# Check if external ip exists and routing configured, if not create and configure it
|
1456
|
if ($type eq "ipmapping") {
|
1457
|
if ($internalip && $internalip ne "--" && $externalip && $externalip ne "--" && !($interfaces =~ m/$externalip /g)) { # the space is important
|
1458
|
$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
|
eval {`/sbin/ifconfig $extnic:$id-$ipend $externalip/$extsubnet up`; 1;}
|
1462
|
or do {$e=1; $postreply .= "Status=ERROR Problem adding interface $extnic:$id-$ipend $@\n";};
|
1463
|
unless (`ip addr show dev $extnic` =~ /$externalip/) {
|
1464
|
$e=10;
|
1465
|
$postreply .= "Status=ERROR Problem adding interface $extnic:$id-$ipend\n";
|
1466
|
}
|
1467
|
# `/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
|
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
|
# DNAT externalip -> internalip
|
1489
|
eval {`/sbin/iptables -A PREROUTING -t nat -p tcp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`; 1;}
|
1490
|
or do {$e=2; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1491
|
eval {`/sbin/iptables -A PREROUTING -t nat -p udp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`; 1;}
|
1492
|
or do {$e=3; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1493
|
# 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
|
# 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
|
}
|
1502
|
}
|
1503
|
eval {`/sbin/iptables -D INPUT -d $externalip -j DROP`; 1;} # Drop traffic to all other ports
|
1504
|
or do {$e=5; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1505
|
eval {`/sbin/iptables -A INPUT -d $externalip -j DROP`; 1;} # Drop traffic to all other ports
|
1506
|
or do {$e=6; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1507
|
} else {
|
1508
|
# DNAT externalip -> internalip coming from outside , --in-interface $extnic
|
1509
|
eval {`/sbin/iptables -A PREROUTING -t nat -d $externalip -j DNAT --to $internalip`; 1;}
|
1510
|
or do {$e=7; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1511
|
# PREROUTING is not parsed for packets coming from local host...
|
1512
|
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
|
# 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
|
|
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
|
# 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
|
}
|
1537
|
|
1538
|
if ($e) {
|
1539
|
$main::syslogit->($user, 'info', "Problem $action network $uuid ($name, $id): $@");
|
1540
|
} else {
|
1541
|
$astatus = "up"
|
1542
|
}
|
1543
|
}
|
1544
|
} elsif ($type eq "externalip") {
|
1545
|
my $route = `/sbin/ip route`;
|
1546
|
my $tables = `/sbin/iptables -L -n`;
|
1547
|
|
1548
|
# 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
|
# We are dealing with multiple upstream routes - configure local routing
|
1553
|
if ($proxynic && ($proxynic ne $extnic)) {
|
1554
|
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
|
`/sbin/ip route del default dev $proxynic table proxyarp`; # delete first in case proxygw has changed
|
1559
|
`/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
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -m state --state ESTABLISHED,RELATED -j RETURN`; 1;}
|
1577
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1578
|
eval {`/sbin/iptables -A FORWARD -i $proxynic -d $externalip -m state --state ESTABLISHED,RELATED -j RETURN`; 1;}
|
1579
|
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
|
eval {`/sbin/iptables -A FORWARD -p tcp -i $proxynic $portfilter -d $externalip --dport $port -j RETURN`; 1;}
|
1605
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1606
|
eval {`/sbin/iptables -A FORWARD -p udp -i $proxynic $portfilter -d $externalip --dport $port -j RETURN`; 1;}
|
1607
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1608
|
}
|
1609
|
}
|
1610
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j REJECT`; 1;} # Drop traffic to all other ports
|
1611
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1612
|
eval {`/sbin/iptables -A FORWARD -i $proxynic -d $externalip -j REJECT`; 1;} # Drop traffic to all other ports
|
1613
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1614
|
} else {
|
1615
|
# First allow everything else to this ip
|
1616
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j RETURN`; 1;}
|
1617
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1618
|
eval {`/sbin/iptables -A FORWARD -i $proxynic -d $externalip -j RETURN`; 1;}
|
1619
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1620
|
# 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
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1623
|
eval {`/sbin/iptables -A FORWARD -p udp -i $proxynic -d $externalip --dport 67 -j REJECT`; 1;}
|
1624
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1625
|
}
|
1626
|
}
|
1627
|
}
|
1628
|
|
1629
|
# 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
|
# 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
|
# `/sbin/iptables --delete FORWARD --in-interface $datanic.$id ! -s 10.$idleft.$idright.0/24 -j DROP`;
|
1638
|
unless ($proxynic eq "$datanic.$id") {
|
1639
|
# `/sbin/iptables --append FORWARD --in-interface $datanic.$id ! -s 10.$idleft.$idright.0/24 -j DROP`;
|
1640
|
}
|
1641
|
|
1642
|
# Enable nat'ing
|
1643
|
eval {
|
1644
|
#my $masq = `/sbin/iptables -L -n -t nat`;
|
1645
|
# 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
|
$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
|
# $main::updateUI->({tab=>"networks", user=>$user, uuid=>$uiuuid, status=>$uistatus}) if ($uistatus);
|
1667
|
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
|
my ($uuid, $action, $obj) = @_;
|
1685
|
if ($help) {
|
1686
|
return <<END
|
1687
|
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
|
May also be called with endpoints "/stabile/[uuid]" or "/stabile?uuid=[uuid]"
|
1690
|
Set [force] to remove even if linked to a system.
|
1691
|
END
|
1692
|
}
|
1693
|
$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
|
( my $domains, my $domainnames ) = getDomains($uuid);
|
1696
|
( my $systems, my $systemnames ) = getSystems($uuid);
|
1697
|
|
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
|
if (
|
1709
|
$id!=0 && $id!=1 && (!$domains || $domains eq '--')
|
1710
|
&& ((!$systems || $systems eq '--' || $force)
|
1711
|
# allow internalip's to be removed if active and only linked, i.e. not providing dhcp
|
1712
|
|| ($status eq 'down' || $status eq 'new' || $status eq 'nat' || ($type eq 'internalip' && $systems && $systems ne '--')))
|
1713
|
) {
|
1714
|
# 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
|
$main::dnsDelete->($engineid, $externalip) if ($enginelinked);
|
1723
|
}
|
1724
|
} elsif ($type eq "externalip") {
|
1725
|
my $result = removeDHCPAddress($id, $domains, $externalip);
|
1726
|
$postreply .= "$result\n" unless $result eq "OK";
|
1727
|
if ($dodns) {
|
1728
|
$main::dnsDelete->($engineid, $externalip) if ($enginelinked);
|
1729
|
}
|
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
|
|
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
|
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
|
$postreply = "[]" || $postreply;
|
1759
|
$main::updateUI->({tab=>"networks", user=>$user, type=>"update"});
|
1760
|
} else {
|
1761
|
$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
|
}
|
1764
|
} else {
|
1765
|
$postreply .= "Status=ERROR Network $uuid $ipaddress not found\n";
|
1766
|
}
|
1767
|
return $postreply;
|
1768
|
}
|
1769
|
|
1770
|
sub Deactivate {
|
1771
|
my ($uuid, $action, $obj) = @_;
|
1772
|
|
1773
|
if ($help) {
|
1774
|
return <<END
|
1775
|
GET:uuid:
|
1776
|
Deactivate a network which must be in status up.
|
1777
|
END
|
1778
|
}
|
1779
|
$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
|
|
1787
|
$action = $action || 'deactivate';
|
1788
|
( my $domains, my $domainnames ) = getDomains($uuid);
|
1789
|
my $interfaces = `/sbin/ifconfig`;
|
1790
|
|
1791
|
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
|
|
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
|
my $idleft = ($id>99)?(substr $id,0,-2)+0 : 0;
|
1812
|
my $idright = (substr $id,-2) + 0;
|
1813
|
my $e = 0;
|
1814
|
my $duprules = 0;
|
1815
|
|
1816
|
if ($type eq "ipmapping" || $type eq "internalip") {
|
1817
|
`iptables -D FORWARD -d $internalip -m state --state ESTABLISHED,RELATED -j RETURN`;
|
1818
|
}
|
1819
|
if ($type eq "ipmapping") {
|
1820
|
# Check if external ip exists and take it down if so
|
1821
|
if ($internalip && $internalip ne "--" && $externalip && $externalip ne "--" && ($interfaces =~ m/$externalip/g)) {
|
1822
|
$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
|
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
|
foreach my $port (@portslist) {
|
1830
|
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
|
# Remove DNAT rules
|
1844
|
if ($port>1 || $port<65535) {
|
1845
|
# repeat for good measure
|
1846
|
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
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1850
|
eval {$duprules++ if (`/sbin/iptables -D PREROUTING -t nat -p udp $ipfilter -d $externalip --dport $port -j DNAT --to $internalip`); 1;}
|
1851
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1852
|
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
|
# 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
|
}
|
1865
|
}
|
1866
|
}
|
1867
|
# Remove SNAT rules
|
1868
|
# repeat for good measure
|
1869
|
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
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1873
|
last if ($duprules);
|
1874
|
}
|
1875
|
# Remove rule to drop traffic to all other ports
|
1876
|
eval {`/sbin/iptables -D INPUT -d $externalip -j DROP`; 1;}
|
1877
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1878
|
} else {
|
1879
|
# Remove DNAT rules
|
1880
|
# repeat for good measure
|
1881
|
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
|
or do {$postreply .= "Status=ERROR $@\n"; $e=1};
|
1885
|
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
|
last if ($duprules >1);
|
1888
|
}
|
1889
|
# 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
|
eval {$duprules++ if (`/sbin/iptables -D POSTROUTING -t nat --out-interface br$id ! -d 10.$idleft.$idright.0/24 -j MASQUERADE`); 1;}
|
1899
|
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
|
}
|
1915
|
# `/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
|
}
|
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
|
foreach my $port (@portslist) {
|
1934
|
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
|
for (my $di=0; $di < 10; $di++) {
|
1951
|
$duprules = 0;
|
1952
|
eval {$duprules++ if (`/sbin/iptables -D FORWARD -p tcp -i $proxynic $ipfilter -d $externalip --dport $port -j RETURN`); 1;}
|
1953
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1954
|
eval {$duprules++ if (`/sbin/iptables -D FORWARD -p udp -i $proxynic $ipfilter -d $externalip --dport $port -j RETURN`); 1;}
|
1955
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1956
|
last if ($duprules > 1);
|
1957
|
}
|
1958
|
}
|
1959
|
}
|
1960
|
}
|
1961
|
# Remove rule to allow forwarding from $externalip
|
1962
|
`/sbin/iptables --delete FORWARD --in-interface br$id -s $externalip -j RETURN`;
|
1963
|
# 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
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -m state --state ESTABLISHED,RELATED -j RETURN`; 1;}
|
1968
|
or do {$e=1; $postreply .= "Status=ERROR Problem setting up routing $@\n";};
|
1969
|
eval {`/sbin/iptables -D FORWARD -i $proxynic -d $externalip -j RETURN`; 1;}
|
1970
|
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
|
} elsif ($type eq "externalip" && $domains) {
|
1984
|
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
|
# $main::updateUI->({tab=>"networks", user=>$user, uuid=>$uiuuid, status=>$uistatus}) if ($uistatus);
|
2000
|
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
|
# `/sbin/iptables --delete FORWARD --in-interface $datanic.$id ! -s 10.$idleft.$idright.0/24 -j DROP`;
|
2053
|
|
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
|
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
|
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
|
my $oc = overQuotas(1);
|
2206
|
if ($oc) { # Enforce quotas
|
2207
|
$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
|
$postreply .= "Status=ERROR No more ($oc) external IPs available\n" unless ($nextip);
|
2228
|
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
|
my ( $systems, $systemnames ) = getSystems($uuid);
|
2315
|
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
|
|
2342
|
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
|
if ($nat && (($dhcprunning && $dhcpconfigured) || $systems)) {
|
2360
|
$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
|
# An ipmapping linked to a system is considered up if external interface exists
|
2365
|
if ($nat && $interfaces =~ m/$extip/ && (($dhcprunning && $dhcpconfigured) || $systems)) {
|
2366
|
$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
|
if ($vproxy && $eproxy && $proute) {
|
2388
|
if ((($dhcprunning && $dhcpconfigured) || $systems)) {
|
2389
|
$valref->{'status'} = "up";
|
2390
|
} elsif (!$valref->{'domains'}) {
|
2391
|
$valref->{'status'} = "nat";
|
2392
|
}
|
2393
|
} 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
|
my $externalipquota = $Stabile::userexternalipquota;
|
2416
|
if (!$externalipquota) {
|
2417
|
$externalipquota = $Stabile::config->get('EXTERNAL_IP_QUOTA');
|
2418
|
}
|
2419
|
|
2420
|
my $rxquota = $Stabile::userrxquota;
|
2421
|
if (!$rxquota) {
|
2422
|
$rxquota = $Stabile::config->get('RX_QUOTA');
|
2423
|
}
|
2424
|
|
2425
|
my $txquota = $Stabile::usertxquota;
|
2426
|
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
|
if ((($usedexternalips + $reqips) > $externalipquota) && $externalipquota > 0) { # -1 means no quota
|
2438
|
$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
|
if ($oq && $oq<0) {
|
2552
|
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
|
}
|