Handle hostnames with upper-case letters
[webmin.git] / net / save_bifc.cgi
1 #!/usr/local/bin/perl
2 # save_bifc.cgi
3 # Create, save or delete a boot-time interface
4
5 require './net-lib.pl';
6 &ReadParse();
7 @boot = &boot_interfaces();
8
9 if ($in{'delete'} || $in{'unapply'}) {
10         # Delete interface
11         &error_setup($text{'bifc_err1'});
12         $b = $boot[$in{'idx'}];
13         &can_iface($b) || &error($text{'ifcs_ecannot_this'});
14
15         if ($in{'unapply'}) {
16                 # Shut down this interface active (if active)
17                 &error_setup($text{'bifc_err4'});
18                 @active = &active_interfaces();
19                 ($act) = grep { $_->{'fullname'} eq $b->{'fullname'} } @active;
20                 if ($act) {
21                         if (defined(&unapply_interface)) {
22                                 $err = &unapply_interface($act);
23                                 $err && &error("<pre>$err</pre>");
24                                 }
25                         else {
26                                 &deactivate_interface($act);
27                                 }
28                         }
29
30                 }
31         &delete_interface($b);
32         &webmin_log("delete", "bifc", $b->{'fullname'}, $b);
33         }
34 else {
35         # Save or create interface
36         &error_setup($text{'bifc_err2'});
37         if (!$in{'new'}) {
38                 # Modifying an interface
39                 $oldb = $boot[$in{'idx'}];
40                 &can_iface($oldb) || &error($text{'ifcs_ecannot_this'});
41                 $b->{'name'} = $oldb->{'name'};
42                 $b->{'file'} = $oldb->{'file'};
43                 $b->{'gateway'} = $oldb->{'gateway'};
44                 $b->{'virtual'} = $oldb->{'virtual'}
45                         if (defined($oldb->{'virtual'}));
46                 $b->{'code'} = $oldb->{'code'};
47                 $b->{'fullname'} = $oldb->{'fullname'};
48                 $b->{'bridge'} = $oldb->{'bridge'};
49                 }
50         elsif (defined($in{'virtual'})) {
51                 # creating a virtual interface
52                 $in{'virtual'} =~ /^\d+$/ ||
53                         &error($text{'bifc_evirt'});
54                 $in{'virtual'} >= $min_virtual_number ||
55                         &error(&text('aifc_evirtmin', $min_virtual_number));
56                 foreach $eb (@boot) {
57                         if ($eb->{'name'} eq $in{'name'} &&
58                             $eb->{'virtual'} eq $in{'virtual'}) {
59                                 &error(&text('bifc_evirtdup',
60                                        "$in{'name'}:$in{'virtual'}"));
61                                 }
62                         }
63                 $b->{'name'} = $in{'name'};
64                 $b->{'virtual'} = $in{'virtual'};
65                 $b->{'fullname'} = $b->{'name'}.":".$b->{'virtual'};
66                 &can_create_iface() || &error($text{'ifcs_ecannot'});
67                 &can_iface($b) || &error($text{'ifcs_ecannot'});
68                 }
69         elsif ($in{'name'} =~ /^([a-z]+\d*(\.\d+)?):(\d+)$/) {
70                 # also creating a virtual interface
71                 foreach $eb (@boot) {
72                         if ($eb->{'name'} eq $1 &&
73                             $eb->{'virtual'} eq $3) {
74                                 &error(&text('bifc_evirtdup', $in{'name'}));
75                                 }
76                         }
77                 $3 >= $min_virtual_number ||
78                         &error(&text('aifc_evirtmin', $min_virtual_number));
79                 $b->{'name'} = $1;
80                 $b->{'virtual'} = $3;
81                 $b->{'fullname'} = $b->{'name'}.":".$b->{'virtual'};
82                 }
83         elsif ($in{'bridge'}) {
84                 # Creating a bridge interface
85                 $in{'name'} =~ /^\d+$/ || &error($text{'bifc_ebridge'});
86                 $b->{'name'} = $b->{'fullname'} = "br".$in{'name'};
87                 $b->{'bridge'} = 1;
88                 }
89         elsif ($in{'name'} =~/^[a-z]+\d*(\.\d+)?$/) {
90                 # creating a real interface
91                 $b->{'name'} = $in{'name'};
92                 $b->{'fullname'} = $in{'name'};
93                 }
94         elsif ($in{'name'} eq 'auto') {
95                 # creating a vlan interface
96                 $b->{'name'} = $in{'name'};
97                 $b->{'fullname'} = $in{'name'};
98                 }
99         else {
100                 &error($text{'bifc_ename'});
101                 }
102
103         if ($in{'new'}) {
104                 # Check permissions
105                 &can_create_iface() || &error($text{'ifcs_ecannot'});
106                 &can_iface($b) || &error($text{'ifcs_ecannot'});
107
108                 # Check for clash
109                 foreach $eb (@boot) {
110                         if ($eb->{'fullname'} eq $b->{'fullname'}) {
111                                 &error(&text('bifc_edup', $in{'name'}));
112                                 }
113                         }
114                 }
115
116         # Check for address clash
117         $allow_clash = defined(&allow_interface_clash) ?
118                         &allow_interface_clash($b, 1) : 1;
119         if (!$allow_clash && $in{'mode'} eq 'address' &&
120             ($in{'new'} || $oldb->{'address'} ne $in{'address'})) {
121                 ($clash) = grep { $_->{'address'} eq $in{'address'} &&
122                                   $_->{'up'} } @boot;
123                 $clash && &error(&text('aifc_eclash', $clash->{'fullname'}));
124                 }
125
126         # Validate and store inputs
127         if ($in{'mode'} eq 'dhcp' || $in{'mode'} eq 'bootp') {
128                 $in{'activate'} && !defined(&apply_interface) &&
129                         &error($text{'bifc_eapply'});
130                 $b->{$in{'mode'}}++;
131                 $auto++;
132                 }
133         elsif ($in{'mode'} eq 'none') {
134                 delete($b->{'address'});
135                 }
136         else {
137                 &valid_boot_address($in{'address'}) ||
138                         &error(&text('bifc_eip', $in{'address'}));
139                 $b->{'address'} = $in{'address'};
140                 }
141
142         # Set description if possible
143         if (defined($in{'desc'})) {
144                 $b->{'desc'} = $in{'desc'};
145                 }
146
147         if ($in{'mode'} eq 'none') {
148                 # No netmask needed
149                 delete($b->{'netmask'});
150                 }
151         elsif ($virtual_netmask && $b->{'virtual'} ne "") {
152                 # Always use this netmask for virtuals
153                 $b->{'netmask'} = $virtual_netmask;
154                 }
155         elsif (!$access{'netmask'}) {
156                 # Use default netmask
157                 $b->{'netmask'} = $in{'new'} ?
158                         $config{'def_netmask'} || "255.255.255.0" :
159                         $oldb->{'netmask'};
160                 }
161         elsif (&can_edit("netmask", $b) && $access{'netmask'}) {
162                 $auto && !$in{'netmask'} ||
163                     &check_netmask($in{'netmask'},$in{'address'}) ||
164                         &error(&text('bifc_emask', $in{'netmask'}));
165                 $b->{'netmask'} = $in{'netmask'};
166                 }
167
168         if ($in{'mode'} eq 'none') {
169                 # No broadcast needed
170                 delete($b->{'broadcast'});
171                 }
172         elsif (!$access{'broadcast'} || $in{'broadcast_def'}) {
173                 # Work out broadcast
174                 $b->{'broadcast'} = $in{'new'} ? 
175                         &compute_broadcast($b->{'address'}, $b->{'netmask'}) :
176                         $oldb->{'broadcast'};
177                 }
178         elsif (&can_edit("broadcast", $b)) {
179                 # Manually entered broadcast
180                 ($auto && !$in{'broadcast'}) ||
181                         &check_ipaddress($in{'broadcast'}) ||
182                         &error(&text('bifc_ebroad', $in{'broadcast'}));
183                 $b->{'broadcast'} = $in{'broadcast'};
184                 }
185
186         if ($in{'mode'} eq 'none') {
187                 # No MTU needed
188                 delete($b->{'mtu'});
189                 }
190         elsif (!$access{'mtu'}) {
191                 # Use default MTU
192                 $b->{'mtu'} = $in{'new'} ? $config{'def_mtu'}
193                                          : $oldb->{'mtu'};
194                 }
195         elsif (&can_edit("mtu", $b) && $access{'mtu'}) {
196                 $auto && !$in{'mtu'} ||
197                         $in{'mtu_def'} ||
198                         $in{'mtu'} =~ /^\d+$/ ||
199                         &error(&text('bifc_emtu', $in{'mtu'}));
200                 $b->{'mtu'} = $in{'mtu_def'} ? undef : $in{'mtu'};
201                 }
202
203         # MAC address
204         if (defined($in{'ether'}) && !$in{'ether_def'}) {
205                 $in{'ether'} =~ /^[A-Fa-f0-9:]+$/ ||
206                         &error(&text('aifc_ehard', $in{'ether'}));
207                 $b->{'ether'} = $in{'ether'};
208                 }
209
210         # Activate at boot flag
211         if ($in{'new'} && !$access{'up'} ||
212             &can_edit("up", $b) && $in{'up'} && $access{'up'}) {
213                 $b->{'up'}++;
214                 }
215         elsif (!$access{'up'}) {
216                 $b->{'up'} = $oldb->{'up'};
217                 }
218
219         # Save IPv6 addresses
220         if (&supports_address6($b) && $in{'mode6'} eq 'auto') {
221                 # Dynamic configuration
222                 delete($b->{'address6'});
223                 delete($b->{'netmask6'});
224                 $b->{'auto6'} = 1;
225                 }
226         elsif (&supports_address6($b) && $in{'mode6'} eq 'address') {
227                 # Static addresses
228                 @address6 = ( );
229                 @netmask6 = ( );
230                 %clash6 = ( );
231                 foreach $eb (@boot) {
232                         if ($eb->{'fullname'} ne $b->{'fullname'}) {
233                                 foreach $a6 (@{$eb->{'address6'}}) {
234                                         $clash6{$a6} = $eb;
235                                         }
236                                 }
237                         }
238                 for($i=0; defined($in{'address6_'.$i}); $i++) {
239                         next if ($in{'address6_'.$i} !~ /\S/);
240                         &check_ip6address($in{'address6_'.$i}) ||
241                                 &error(&text('aifc_eaddress6', $i+1));
242                         $c = $clash6{$in{'address6_'.$i}};
243                         $c && &error(&text('aifc_eclash6', $i+1, $c->{'name'}));
244                         push(@address6, $in{'address6_'.$i});
245                         $in{'netmask6_'.$i} =~ /^\d+$/ &&
246                             $in{'netmask6_'.$i} > 0 &&
247                             $in{'netmask6_'.$i} <= 128 ||
248                                 &error(&text('aifc_enetmask6', $i+1));
249                         push(@netmask6, $in{'netmask6_'.$i});
250                         $clash6{$in{'address6_'.$i}} = $b;
251                         }
252                 @address6 || &error($text{'aifc_eaddresses6'});
253                 delete($b->{'auto6'});
254                 $b->{'address6'} = \@address6;
255                 $b->{'netmask6'} = \@netmask6;
256                 }
257         elsif (&supports_address6($b) && $in{'mode6'} eq 'none') {
258                 # IPv6 disabled
259                 delete($b->{'address6'});
260                 delete($b->{'netmask6'});
261                 delete($b->{'auto6'});
262                 }
263
264         # Save bonding settings
265         if ($in{'bond'}) {
266                 $b->{'bond'} = 1;
267                 if ($in{'partner'}) {
268                         $b->{'partner'} = $in{'partner'};
269                         }
270                 if ($in{'bondmode'} ne ''){
271                         $mode = $in{'bondmode'};
272                         $b->{'mode'} = $mode;
273                         }
274                 if ($in{'miimon'} ne ''){
275                         $b->{'miimon'} = $in{'miimon'};
276                         }
277                 if ($in{'updelay'} ne ''){
278                         $b->{'updelay'} = $in{'updelay'};
279                         }
280                 if ($in{'downdelay'} ne ''){
281                         $b->{'downdelay'} = $in{'downdelay'};
282                         }
283                 }
284         
285         # Save VLAN settings
286         if ($in{'vlan'} == 1) {
287                 $b->{'vlan'} = 1;
288                 if ($in{'physical'}) {
289                         $b->{'physical'} = $in{'physical'};
290                         }
291                 if ($in{'vlanid'}) {
292                         $b->{'vlanid'} = $in{'vlanid'};
293                         }
294                 }
295
296         # Save bridge settings
297         if ($b->{'bridge'}) {
298                 $in{'bridgeto'} =~ /^eth\d+$/ ||
299                         &error($text{'bifc_ebridgeto'});
300                 ($bt) = grep { $_->{'fullname'} eq $in{'bridgeto'} } @boot;
301                 $bt || &error($text{'bifc_ebridgeto'});
302                 ($bt->{'address'} || $bt->{'dhcp'} || $bt->{'bootp'}) &&
303                         &error($text{'bifc_ebridgeto2'});
304                 $b->{'bridgeto'} = $in{'bridgeto'};
305                 }
306
307         # Save the interface with its final name
308         $b->{'fullname'} = $b->{'name'}.
309                 ( $b->{'virtual'} eq '' ? '' : ':'.$b->{'virtual'});
310         &save_interface($b);
311
312         if ($in{'activate'}) {
313                 # Make this interface active (if possible)
314                 &error_setup($text{'bifc_err3'});
315                 $b->{'up'}++;
316                 $b->{'address'} = &to_ipaddress($b->{'address'});
317                 if (defined(&apply_interface)) {
318                         $err = &apply_interface($b);
319                         $err && &error("<pre>$err</pre>");
320                         }
321                 else {
322                         if ($in{'bond'}) {
323                                 if (($gconfig{'os_type'} eq 'debian-linux') &&
324                                     ($gconfig{'os_version'} >= 5)) {}
325                                 else {&load_module($b);}
326                                 }
327                         &activate_interface($b);
328                         }
329                 }
330         &webmin_log($in{'new'} ? 'create' : 'modify',
331                     "bifc", $b->{'fullname'}, $b);
332         }
333 &redirect("list_ifcs.cgi?mode=boot");
334