diff --git a/Makefile b/Makefile index 697d8d1..4e4a9d4 100644 --- a/Makefile +++ b/Makefile @@ -8,19 +8,19 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -DEPENDS = dhclient,iproute2,perl +DEPENDS = dhclient,iproute2 ARCH = none URL = BRIEF = Scripts for starting and stopping network interfaces DESC = Scripts which use the iproute2 tools for automatically starting and \ stopping network devices during startup. -SNAPVER = 2 +SNAPVER = 0 ARCHIVE := SRCDIR := $(PWD)/SRC/iftools PATCHDIR := $(PWD)/SRC/patches -VERSION := $(shell grep 'VERSION\s*=>' SRC/iftools/ifup| \ - cut -d "'" -f2)-$(SNAPVER) +VERSION := $(shell grep 'VERSION=' SRC/iftools/ifup| \ + cut -d "=" -f2)-$(SNAPVER) include /usr/share/snap/Makefile.snaplinux diff --git a/SRC/iftools/Makefile b/SRC/iftools/Makefile index 430766f..00f0a8f 100644 --- a/SRC/iftools/Makefile +++ b/SRC/iftools/Makefile @@ -16,10 +16,8 @@ files: links: ln -s ifup.8 $(DESTDIR)/usr/share/man/man8/ifdown.8 - ln -s ifup.8 $(DESTDIR)/usr/share/man/man8/ifquery.8 ln -s ifup.8 $(DESTDIR)/usr/share/man/man8/ifreload.8 ln -s ifup $(DESTDIR)/sbin/ifdown - ln -s ifup $(DESTDIR)/sbin/ifquery ln -s ifup $(DESTDIR)/sbin/ifreload install: dirs files links diff --git a/SRC/iftools/ifup b/SRC/iftools/ifup index 26be13d..610a927 100755 --- a/SRC/iftools/ifup +++ b/SRC/iftools/ifup @@ -1,911 +1,417 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use IPC::Open3; -use IO::Select; -use Fcntl qw( LOCK_EX LOCK_NB ); -use Data::Dumper; - -open( SELF, "<$0" ) || error( int( $! ), "open(): $0: $!" ); -flock( SELF, LOCK_EX|LOCK_NB ) || error( -1, "Another instance is running" ); - -use constant CONFDIR => '/etc'; -use constant CONFIGFILE => CONFDIR . '/network.conf'; -use constant NOACT => eval { - for ( my $i = 0; $i <= $#ARGV; $i++ ) { - if ( $ARGV[$i] eq '-n' || $ARGV[$i] eq '--no-act' ) { - splice( @ARGV, $i, 1 ); - - return( 1 ); - } - } - - return( 0 ); - }; -use constant VERBOSE => eval { - for ( my $i = 0; $i <= $#ARGV; $i++ ) { - if ( $ARGV[$i] eq '-v' || $ARGV[$i] eq '--verbose' ) { - splice( @ARGV, $i, 1 ); - - return( 1 ); - } - } - - return( 0 ); - }; -use constant VERSION => '0.1'; - -sub aliasdown { - my $alias = shift; - my $runningconf = shift; - my $aliases = $runningconf->{$alias->{'dev'}}{'aliases'}; - my $result; - - if ( my $running = $aliases->{$alias->{'name'}} ) { - if ( VERBOSE ) { - print "Deleting $running->{'address'}" - . " from $alias->{'dev'}" - . " (label $alias->{'dev'}:" - . "$alias->{'name'})\n"; - } - - $result = runcmd( "ip address delete" - . " $running->{'address'}" - . " dev $running->{'dev'} label" - . " $running->{'dev'}:$alias->{'name'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - return( $result->{'stat'} ); - } - } - -sub aliasup { - my $alias = shift; - my $runningconf = shift; - my $dev = $alias->{'dev'}; - my $name = $alias->{'name'}; - my $result; - - if ( my $old = $runningconf->{$dev}{'aliases'}{$name} ) { - if ( $old->{'address'} eq $alias->{'address'} && - $old->{'dev'} eq $alias->{'dev'} && - $old->{'name'} eq $alias->{'name'} ) { - if ( VERBOSE ) { - print STDERR "Interface $dev:$name" - . " is already up\n"; - } - - return( 1 ); - } - - if ( my $retval = aliasdown( $old, $runningconf ) ) { - return( $retval ); - } - } - - if ( VERBOSE ) { - print "Adding $alias->{'address'} to $alias->{'dev'}" - . " (label $alias->{'dev'}" - . ":$alias->{'name'})\n"; - } - - $result = runcmd( "ip address add $alias->{'address'}" - . " dev $alias->{'dev'}" - . " label $alias->{'dev'}:$alias->{'name'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - return( $result->{'stat'} ); - } - -sub cidr2netmask { - my $cidr = shift; - my $bit = ( 2 ** ( 32 - $cidr ) ) - 1; - my $full_mask = unpack( 'N', pack( 'C4', 255,255,255,255 ) ); - my $netmask = join( '.', unpack( 'C4', pack( 'N', - ( $full_mask ^ $bit ) ) ) ); - - return( $netmask ); - } - -sub error { - my $status = shift; - my $errstr = shift; - my $level = 1; - my @stack = (); - - chomp( $errstr ); - - print "\n"; - - print STDERR ( caller() )[1] .":\n $errstr at line " - . ( caller() )[2] . "\n"; - - if ( VERBOSE ) { - if ( caller( $level ) ) { - print "\n=== Stack Trace ===\n"; - } - - while ( my @trace = caller( $level++ ) ) { - print STDERR " $trace[1]:\n" - . " $trace[3]() called at line $trace[2]\n"; - } - } - - print "\n"; - - if ( $status ) { - exit( $status ); - } - } - -sub getroutes { - my $routes = {}; - my $result = runcmd( 'ip route show' ); - - if ( $result->{'stat'} || ! $result->{'stdout'} ) { - return; - } - - open( my $fh, '<', \$result->{'stdout'} ); - - while ( <$fh> ) { - if ( $_ =~ /^(\S+)\s+via\s+(\S+)\s+dev\s+(\S+)/ ) { - $routes->{$1}{'via'} = $2; - $routes->{$1}{'dev'} = $3; - } - } - - close( $fh ); - - return( $routes ); - } - -sub ifdown { - my $iface = shift; - my $result = {}; - my $stat = 0; - - if ( VERBOSE ) { - print "Flushing interface $iface->{'name'}\n"; - } - - $result = runcmd( "ip addr flush dev $iface->{'name'}" ); - - if ( $result->{'stat'} ) { - $stat = $result->{'stat'}; - } - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - - print "Bringing down interface $iface->{'name'}\n"; - } - - $result = runcmd( "ip link set $iface->{'name'} down" ); - - if ( $result->{'stat'} ) { - $stat = $result->{'stat'}; - } - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - return( $stat ); - } - -sub ifup { - my $iface = shift; - my $runningconf = shift; - my $routes = getroutes(); - my $result; - my $stat = 0; - - if ( my $old = $runningconf->{$iface->{'name'}} ) { - if ( ( $old->{'address'} && $iface->{'address'} && - $old->{'address'} eq $iface->{'address'} ) || - ( $old->{'state'} eq 'UP' && $iface->{'inet'} eq 'dhcp' ) ) { - if ( VERBOSE ) { - print STDERR "Interface $iface->{'name'}" - . " is already up\n"; - } - - return; - } - - if ( VERBOSE ) { - print "Flushing interface $iface->{'name'}\n"; - } - - $result = runcmd( "ip addr flush dev $iface->{'name'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - } - - if ( $iface->{'macaddr'} ) { - if ( VERBOSE ) { - print "Setting MAC address on interface" - . " $iface->{'name'} to $iface->{'macaddr'}\n"; - } - - $result = runcmd( "ip link set dev $iface->{'name'}" - . " address $iface->{'macaddr'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - } - - if ( VERBOSE ) { - print "Bringing up interface $iface->{'name'}\n"; - } - - if ( $iface->{'inet'} && $iface->{'inet'} eq 'static' ) { - if ( VERBOSE ) { - print "Setting address to $iface->{'address'}" - . " on interface $iface->{'name'}\n"; - } - - $result = runcmd( "ip address add $iface->{'address'}" - . " dev $iface->{'name'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - } - elsif ( $iface->{'inet'} && $iface->{'inet'} eq 'loopback' && - ! $runningconf->{$iface->{'name'}}{'name'} ) { - if ( VERBOSE ) { - print "Setting address to $iface->{'address'}" - . " on interface $iface->{'name'}\n"; - } - - $result = runcmd( "ip -d address add $iface->{'address'}" - . " dev $iface->{'name'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - } - elsif ( $iface->{'inet'} && $iface->{'inet'} eq 'dhcp' ) { - if ( -f '/var/run/dhclient.pid' ) { - system( "dhclient -r $iface->{'name'}" ); - } - - if ( VERBOSE ) { - print "Starting dhclient for $iface->{'name'}\n"; - } - - $result = runcmd( "dhclient $iface->{'name'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - } - - $result = runcmd( "ip link set $iface->{'name'} up" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - - if ( ! $routes->{'default'} && $iface->{'gateway'} ) { - if ( VERBOSE ) { - print "Adding default gateway $iface->{'gateway'}\n"; - } - - $result = runcmd( "ip route add default" - . " via $iface->{'gateway'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - } - elsif ( $routes->{'default'}{'via'} && $iface->{'gateway'} && - $routes->{'default'}{'via'} ne $iface->{'gateway'} && - $routes->{'default'}{'dev'} eq $iface->{'name'} ) { - if ( VERBOSE ) { - print "Changing default gateway to" - . " $iface->{'gateway'}\n"; - } - - $result = runcmd( "ip route delete default via" - . " $routes->{'default'}{'via'} dev $iface->{'name'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - - $result = runcmd( "ip route add default" - . " via $iface->{'gateway'}" ); - - if ( VERBOSE ) { - if ( $result->{'stdout'} ) { - print $result->{'stdout'}; - } - if ( $result->{'stderr'} ) { - print STDERR $result->{'stderr'}; - } - } - - if ( $result->{'stat'} ) { - return( $result->{'stat'} ); - } - } - - if ( $iface->{'routes'} ) { - foreach my $target ( keys( %{$iface->{'routes'}} ) ) { - if ( VERBOSE ) { - print "Adding route $target via" - . " $iface->{'routes'}{$target}" - . " dev $iface->{'name'}\n"; - } - - system( "ip route add $target via" - . " $iface->{'routes'}{$target}" - . " dev $iface->{'name'}" ); - } - } - } - -sub listfiles { - my $dir = shift; - my $files = []; - my $sorted = []; - - if ( ! -d $dir ) { - return; - } - - opendir( DIR, $dir ) || error( int( $! ), "opendir(): $dir: $!" ); - - while ( readdir( DIR ) ) { - if ( ! -f "$dir/$_" || $_ =~ /^\./ ) { - next; - } - - push ( @$files, $_ ); - } - - @$sorted = sort( @$files ); - - return( $sorted ); - } - -sub netmask2cidr { - my $netmask = shift; - my $bits = { - 0 => 0, - 128 => 1, - 192 => 2, - 224 => 3, - 240 => 4, - 248 => 5, - 252 => 6, - 254 => 7, - 255 => 8 - }; - my $lastoct; - my $cidr = 0; - - foreach ( split( /\./, $netmask ) ) { - if ( ( $lastoct && $lastoct != 255 && $_ != 0 ) || - ! defined( $bits->{$_} ) ) { - error( int( $! ), "netmask2cidr(): $netmask:" - . " Invalid netmask" ); - } - - $cidr += $bits->{$_}; - $lastoct = $_; - } - - return( $cidr ); - } - -sub readconf { - my $file = shift; - my $conf = shift || {}; - my $iface; - - open( my $config, "<$file" ) || error( int( $! ), "open(): $file: $!" ); - - while ( <$config> ) { - if ( $_ =~ /^\s*#/ ) { - next; - } - - if ( $_ =~ /source-directory\s+(\S+)/ ) { - my $path = $1; - my $files; - - if ( substr( $path, 0, 1 ) ne '/' ) { - $path = CONFDIR . "/$path"; - } - - $files = listfiles( $path ); - - foreach my $file ( @$files ) { - readconf( "$path/$file", $conf ); - } - } - elsif ( $_ =~ /auto\s+(\S+)/ && $1 =~ /^(\S+):(\S+)$/ ) { - $conf->{$1}{'aliases'}{$2}{'auto'} = 1; - } - elsif ( $_ =~ /auto\s+(\S+)/ ) { - $conf->{$1}{'auto'} = 1; - } - elsif ( $_ =~ /iface\s+(\S+):(\S+)/ ) { - $iface = "$1:$2"; - $conf->{$1}{'aliases'}{$2}{'dev'} = $1; - $conf->{$1}{'aliases'}{$2}{'name'} = $2; - $conf->{$1}{'aliases'}{$2}{'cnt'} = - keys( %{$conf->{$1}{'aliases'}} ); - } - elsif ( $_ =~ /iface\s+(\S+)\s+(\S+)\s+(\S+)/ ) { - $iface = $1; - - if ( $conf->{$iface}{'inet'} ) { - error( -1, "Multiple instances of $iface" - . " in $file" ); - } - - $conf->{$iface}{$2} = $3; - $conf->{$iface}{'name'} = $iface; - - if ( $3 eq 'loopback' ) { - $conf->{$iface}{'address'} = '127.0.0.1/8'; - } - - $conf->{$iface}{'cnt'} = scalar( keys( %$conf ) ); - } - elsif ( $_ =~ /route\s+(\S+)\s+via\s+(\S+)/ ) { - $conf->{$iface}{'routes'}{$1} = $2; - } - elsif ( $iface && $_ =~ /^\s*(\S+)\s+(\S+)/ ) { - my ( $attr, $value ) = ( $1, $2 ); - - if ( $iface =~ /^(\S+):(\S+)/ ) { - $conf->{$1}{'aliases'}{$2}{$attr} = $value; - } - else { - $conf->{$iface}{$attr} = $value; - } - } - elsif ( $iface && $_ =~ /^\s*(\S+)\s+(\S+)/ ) { - $conf->{$iface}{$1} = $2; - } - } - - close( $config ); - - foreach my $devname ( keys( %$conf ) ) { - my $dev = $conf->{$devname}; - - if ( $dev->{'address'} && $dev->{'netmask'} ) { - $dev->{'address'} .= '/' - . netmask2cidr( $dev->{'netmask'} ); - - undef( $dev->{'netmask'} ); - } - - if ( ! keys( %{$dev->{'aliases'}} ) ) { - next; - } - - foreach my $aliasname ( keys( %{$dev->{'aliases'}} ) ) { - my $alias = $dev->{'aliases'}{$aliasname}; - - if ( $alias->{'address'} && $alias->{'netmask'} ) { - $alias->{'address'} .= '/' - . netmask2cidr( $alias->{'netmask'} ); - - undef( $alias->{'netmask'} ); - } - } - } - - return( $conf ); - } - -sub runcmd { - if ( NOACT ) { - return( { stat => 0 } );; - } - - my $cmd = shift; - my $result = { - stdout => '', - stderr => '', - stat => '' - }; - my $sel = IO::Select->new(); - my $pid = eval { - return( open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR, $cmd ) ); - } || error( int( $! ), "open3(): $cmd: $!" ); - - close( CHLDIN ); - - $sel->add( *CHLDOUT, *CHLDERR ); - - while ( my @fhs = $sel->can_read ) { - foreach my $fh ( @fhs ) { - if ( eof( $fh ) ) { - $sel->remove( $fh ); - - next; - } - - if ( fileno( $fh ) == fileno( *CHLDOUT ) ) { - $result->{'stdout'} .= <$fh>; - } - elsif ( fileno( $fh ) == fileno( *CHLDERR ) ) { - $result->{'stderr'} .= <$fh>; - } - } - } - - close( CHLDOUT ); - close( CHLDERR ); - - waitpid( $pid, 0 ); - $result->{'stat'} = $? >> 8; - - return( $result ); - } - -sub runningconf { - my $cmd = 'ip -d address show'; - my $sel = IO::Select->new(); - my $pid = eval { - return( open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR, $cmd ) ); - } || error( int( $! ), "open3(): $cmd: $!" ); - my $stat; - my $stdout = ''; - my $stderr = ''; - my $runningconf = {}; - my $macaddr; - my $dev; - - close( CHLDIN ); - - $sel->add( *CHLDOUT, *CHLDERR ); - - while ( my @fhs = $sel->can_read ) { - foreach my $fh ( @fhs ) { - if ( eof( $fh ) ) { - $sel->remove( $fh ); - - next; - } - - if ( fileno( $fh ) == fileno( *CHLDOUT ) ) { - $stdout .= <$fh>; - } - elsif ( fileno( $fh ) == fileno( *CHLDERR ) ) { - $stderr .= <$fh>; - } - } - } - - close( CHLDOUT ); - close( CHLDERR ); - - waitpid( $pid, 0 ); - $stat = $? >> 8; - - if ( $stat ) { - error( int( $! ), "open3: $cmd: $stderr" ); - } - - open( my $fh, '<', \$stdout ) || error( int( $! ), "open(): $!" ); - - while ( <$fh> ) { - if ( $_ =~ /^\d+:\s*(\S+):/ ) { - $dev = $1; - } - - if ( $_ =~ /\s+mtu\s+(\d+)/ ) { - $runningconf->{$dev}{'mtu'} = $1; - } - if ( $_ =~ /\s+qdisc\s+(\S+)/ ) { - $runningconf->{$dev}{'qdisc'} = $1; - } - if ( $_ =~ /\s+state\s+(\S+)/ ) { - $runningconf->{$dev}{'state'} = $1; - } - if ( $_ =~ /\s+group\s+(\S+)/ ) { - $runningconf->{$dev}{'group'} = $1; - } - if ( $_ =~ /\s+qlen\s+(\S+)/ ) { - $runningconf->{$dev}{'qlen'} = $1; - } - if ( $_ =~ /^\s+link\/(\S+)\s+(\S+)/ ) { - $runningconf->{$dev}{'link'} = $1; - $runningconf->{$dev}{'macaddr'} = $2; - } - if ( $_ =~ /\s+promiscuity\s+(\S+)/ ) { - $runningconf->{$dev}{'promiscuity'} = $1; - } - - if ( $_ =~ /^\s+inet\s+(\S+).*\s+(\S+):(\S+)/ ) { - $runningconf->{$2}{'aliases'}{$3}{'address'} = $1; - $runningconf->{$2}{'aliases'}{$3}{'dev'} = $dev; - $runningconf->{$2}{'aliases'}{$3}{'name'} = $3; - } - elsif ( $_ =~ /^\s+inet\s+(\S+).*(\S+)$/ ) { - if ( $runningconf->{$dev}{'address'} ) { - next; - } - - $runningconf->{$dev}{'address'} = $1; - } - } - - close( $fh ); - - return( $runningconf ); - } - -my $conf = readconf( CONFIGFILE ); -my $runningconf = runningconf(); -my $self = ( split( '/', $0 ) )[-1]; -my $ifaces = []; -my $all = eval { - for ( my $i = 0; $i <= $#ARGV; $i++ ) { - if ( $ARGV[$i] eq '-a' || $ARGV[$i] eq '--all' ) { - splice( @ARGV, $i, 1 ); - - return( 1 ); - } - } - }; -my $stat = 0; -#print Dumper( $conf ); exit; - -if ( grep( $_ eq '-h' || $_ eq '--help', @ARGV ) ) { - print "Usage: $self [OPTIONS] [INTERFACES]\n"; - - if ( $self eq 'ifup' ) { - print "Bring a network interface up\n\n"; - } - elsif ( $self eq 'ifdown' ) { - print "Bring a network interface down\n\n"; - } - elsif ( $self eq 'ifreload' ) { - print "Reload interface configuration\n\n"; - } - elsif ( $self eq 'ifquery' ) { - print "View current status of interfaces\n\n"; - } - - print "Options:\n" - . "\t-a, --all\t\tperform actions on all 'auto' interfaces\n" - . "\t-h, --help\t\tprint usage information\n"; - - if ( $self ne 'ifquery' ) { - print "\t-n, --no-act\t\tdisplay actions without taking them\n" - . "\t-v, --verbose\t\tdisplay actions as they occur\n"; - } - - print "\t-V, --version\t\tdisplay version information\n"; - - exit( 0 ); - } -elsif ( grep( $_ eq '-V' || $_ eq '--version', @ARGV ) ) { - print "iftools version " . VERSION . "\n"; - - exit( 0 ); - } - -if ( ! $all ) { - foreach ( @ARGV ) { - ( my $dev = $_ ) =~ s/:.*//; - - if ( $runningconf->{$dev} ) { - push( @$ifaces, $_ ); - } - elsif ( VERBOSE ) { - print STDERR "$_: No such device\n"; - } - } - } -else { - foreach ( sort { $conf->{$a}{'cnt'} <=> $conf->{$b}{'cnt'} } - ( keys( %$conf ) ) ) { - ( my $dev = $_ ) =~ s/:.*//; - - if ( $self eq 'ifup' && ! $conf->{$_}{'auto'} ) { - next; - } - - if ( $runningconf->{$dev} ) { - push( @$ifaces, $_ ); - } - elsif ( VERBOSE ) { - print STDERR "$_: No such device\n"; - - next; - } - - foreach my $alias ( sort { - $conf->{$dev}{'aliases'}{$a}{'cnt'} <=> - $conf->{$dev}{'aliases'}{$b}{'cnt'} } - keys( %{$conf->{$dev}{'aliases'}} ) ) { - push( @$ifaces, "$dev:$alias" ); - } - } - } - -foreach my $iface ( @$ifaces ) { - if ( $self eq 'ifup' ) { - if ( $iface =~ /^(\S+):(\S+)/ ) { - $stat = aliasup( $conf->{$1}{'aliases'}{$2}, - $runningconf ) || $stat; - } - else { - $stat = ifup( $conf->{$iface}, $runningconf ) || $stat; - } - } - elsif ( $self eq 'ifdown' ) { - if ( $iface =~ /^(\S+):(\S+)/ ) { - $stat = aliasdown( $conf->{$1}{'aliases'}{$2}, - $runningconf ) || $stat; - } - else { - $stat = ifdown( $conf->{$iface}, $runningconf ) || - $stat; - } - } - elsif ( $self eq 'ifreload' ) { - if ( $iface =~ /^(\S+):(\S+)/ ) { - $stat = aliasdown( $conf->{$1}{'aliases'}{$2}, - $runningconf ) || $stat; - $runningconf = runningconf(); - $stat = aliasup( $conf->{$1}{'aliases'}{$2}, - $runningconf ) || $stat; - } - else { - $stat = ifdown( $conf->{$iface}, $runningconf ) || - $stat; - $runningconf = runningconf(); - $stat = ifup( $conf->{$iface}, $runningconf ) || - $stat; - } - } - elsif ( $self eq 'ifquery' ) { - if ( $iface =~ /^\S+:\S+/ ) { - next; - } - elsif ( ! $runningconf->{$iface} ) { - $runningconf->{$iface} = { - state => 'No such device', - address => '', - macaddr => '' - }; - } - - print "[$iface]\n" - . " State: $runningconf->{$iface}{'state'}\n"; - - if ( $runningconf->{$iface}{'address'} ) { - print " Address: $runningconf->{$iface}{'address'}\n"; - } - if ( $runningconf->{$iface}{'macaddr'} ) { - print " MAC: $runningconf->{$iface}{'macaddr'}\n"; - } - - foreach my $name ( sort( keys( - %{$runningconf->{$iface}{'aliases'}} ) ) ) { - my $alias = $runningconf->{$iface}{'aliases'}{$name}; - print "[$iface:$name]\n" - . " Address: $alias->{'address'}\n"; - } - } - - $runningconf = runningconf(); - } - -close( SELF ); -exit( $stat ); +#!/bin/sh + +VERSION=1.0 +CONFDIR=/etc +CONFIGFILE=$CONFDIR/network.conf +NL=' +' + +auto () { + autoifaces='' + + while read -r line; do + case "$line" in + auto*) + if [ -z "$autoifaces" ]; then + autoifaces="${line#* }" + else + autoifaces="$autoifaces ${line#* }" + fi + ;; + esac + done <<< "$1" + + echo "$autoifaces" + } + +down () { + iface=$1 + + if [ -f /var/run/dhclient.$iface.pid ]; then + [ -n "$verbose" ] && echo "Stopping dhclient for $iface" + + if [ -n "$noact" ]; then + echo "dhclient -x -pf /var/run/dhclient.$iface.pid" + else + dhclient -x -pf /var/run/dhclient.$iface.pid + fi + fi + + case "$iface" in + *:*) + real=${iface%:*} + address=$(getinet $iface) + + if [ -z "$address" ] || [ -n "$noact" ]; then + return + fi + + [ -n "$verbose" ] && echo "Removing label $iface from $real" + + if [ -n "$noact" ]; then + echo "ip address del $address dev $real label $iface" + else + ip address del $address dev $real label $iface + fi + ;; + *) + [ -n "$verbose" ] && echo "Flushing interface $iface" + + if [ -n "$noact" ]; then + echo "ip address flush dev $iface" + else + ip address flush dev $iface + fi + + [ -n "$verbose" ] && echo "Bringing down $iface" + + if [ -n "$noact" ]; then + echo "ip link set dev $iface down" + else + ip link set dev $iface down + fi + ;; + esac + } + +getinet () { + iface=$1 + + while read -r line; do + case "$line" in + "inet "*$iface) + address=${line#inet* } + address=${address%% *} + ;; + esac + done <<< "$(ip addr show $iface)" + + echo $address + } + +mask2cidr () { + bits=0 + IFS=. + + for dec in $1; do + case $dec in + 255) bits=$((bits+8));; + 254) bits=$((bits+7));; + 252) bits=$((bits+6));; + 248) bits=$((bits+5));; + 240) bits=$((bits+4));; + 224) bits=$((bits+3));; + 192) bits=$((bits+2));; + 128) bits=$((bits+1));; + 0);; + *) + echo "Error: '$dec': invalid octet" + return + ;; + esac + done + + echo "$bits" + } + +readconf () { + while read -r line; do + case "$line" in + \#*) + continue + ;; + "source-directory /"*) + for file in ${line#* }/*.conf; do + [ -f "$file" ] || continue; + + readconf $file + done + ;; + source-directory*) + for file in $CONFDIR/${line#* }/*.conf; do + [ -f "$file" ] || continue; + + readconf $file + done + ;; + *) + if [ -n "$CONFIG" ]; then + CONFIG="$CONFIG$NL" + fi + + CONFIG="$CONFIG$line" + esac + done < $1 + } + +reload () { + down $1 + up $1 "$2" + } + +up () { + local address brports cidr dhcp exists gateway loopback manual \ + routes stanza static netmask + + iface=$1 + + while read -r line; do + case "$line" in + "iface $iface "*) + exists=1 + stanza=1 + + case "$line" in + "iface $iface inet dhcp") + dhcp=1 + ;; + "iface $iface inet loopback") + loopback=1 + ;; + "iface $iface inet manual") + manual=1 + ;; + "iface $iface inet static") + static=1 + ;; + *) + exists=0 + stanza=0 + ;; + esac + esac + + if [ -n "$stanza" ]; then + case "$line" in + address*) + address=${line#* } + + case "$address" in + */*) + cidr=${address#*/} + address=${address%/*} + ;; + esac + ;; + netmask*) + netmask=${line#* } + + if [ -z "$cidr" ]; then + cidr=$(mask2cidr $netmask) + fi + ;; + gateway*) + gateway=${line#* } + ;; + route*) + if [ -n "$routes" ]; then + routes="$routes$NL${line#* }" + else + routes="${line#* }" + fi + ;; + bridge_ports*) + brports=${line#* } + ;; + '') + break + ;; + esac + fi + done <<< "$2" + + if [ -z "$exists" ]; then + echo "$iface not defined" + + return 1 + fi + + if [ -n "$brports" ]; then + [ -n "$verbose" ] && echo "Creating bridge interface $iface" + + if [ -n "$noact" ]; then + echo "ip link add $iface type bridge" + else + ip link add $iface type bridge + fi + + for brport in "$brports"; do + [ -n "$verbose" ] && echo "Configuring $brport as slave to $iface" + + if [ -n "$noact" ]; then + echo "ip link set dev $brport master $iface" + else + ip link set dev $brport master $iface + fi + done + fi + + if [ -n "$dhcp" ]; then + [ -n "$verbose" ] && echo "Flushing interface $iface" + + if [ -n "$noact" ]; then + echo "ip address flush dev $iface" + else + ip address flush dev $iface + fi + + [ -n "$verbose" ] && echo "Bringing up interface $iface" + + if [ -n "$noact" ]; then + echo "ip link set dev $iface up" + else + ip link set dev $iface up + fi + + [ -n "$verbose" ] && echo "Starting dhclient for $iface" + + if [ -f /var/run/dhclient.$iface.pid ]; then + if [ -n "$noact" ]; then + echo "dhclient -x -pf /var/run/dhclient.$iface.pid" + else + dhclient -x -pf /var/run/dhclient.$iface.pid + fi + fi + + if [ -n "$noact" ]; then + echo "dhclient -nw -pf /var/run/dhclient.$iface.pid $iface" + else + dhclient -nw -pf /var/run/dhclient.$iface.pid $iface + fi + elif [ -n "$loopback" ]; then + [ -n "$verbose" ] && echo "Flushing interface $iface" + + if [ -n "$noact" ]; then + echo "ip address flush dev $iface" + else + ip address flush dev $iface + fi + + [ -n "$verbose" ] && echo "Bringing up loopback interface $iface" + + if [ -n "$noact" ]; then + echo "ip link set dev $iface up" + else + ip link set dev $iface up + fi + elif [ -n "$static" ]; then + case "$iface" in + *:*) + real=${iface%:*} + + [ -n "$verbose" ] && echo "Configuring $iface with $address/$cidr" + + if [ -n "$noact" ]; then + echo "ip address add $address/$cidr dev $real label $iface" + else + ip address add $address/$cidr dev $real label $iface + fi + ;; + *) + [ -n "$verbose" ] && echo "Flushing interface $iface" + + if [ -n "$noact" ]; then + echo "ip address flush dev $iface" + else + ip address flush dev $iface + fi + + [ -n "$verbose" ] && echo "Bringing up interface $iface" + + if [ -n "$noact" ]; then + echo "ip link set dev $iface up" + else + ip link set dev $iface up + fi + + [ -n "$verbose" ] && echo "Configuring $iface with $address/$cidr" + + if [ -n "$noact" ]; then + echo "ip address add $address/$cidr dev $iface" + else + ip address add $address/$cidr dev $iface + fi + ;; + esac + fi + + if [ -n "$gateway" ]; then + [ -z "$verbose" ] && echo "Setting default route via $gateway" + + if [ -n "$noact" ]; then + echo "ip route add default via $gateway" + else + ip route add default via $gateway + fi + fi + + if [ -n "$routes" ]; then + [ -n "$verbose" ] && echo "Adding static routes" + + for i in 1 2 3 4 5; do + sleep .5 + chkaddr=$(getinet ${iface%:*}) + + [ -n "$chkaddr" ] && break; + done + + IFS=$NL + + for route in $routes; do + [ -n "$verbose" ] && echo "Routing $route" + IFS=$' \t\n' + + if [ -n "$noact" ]; then + echo "ip route add $route dev $iface src $address" + else + ip route add $route dev $iface src $address + fi + done + fi + } + +usage () { + echo "Usage: $self [OPTIONS] [INTERFACES]" + echo "Enable and configure network interfaces as defined in /etc/network.conf" + echo + echo "Either -a or one or more INTERFACES must be provided as arguments" + echo " -a act on 'auto' interfaces" + echo " -h print usage information" + echo " -n display actions without performing them" + echo " -v enable verbose output" + echo " -V display version information" + } + +self=${0#*/} +action=${self#*if} + +if [ "$#" -eq 0 ]; then + usage + + exit 1; +fi + +while getopts ahnvV args; do + case $args in + (a) all=1;; + (h) usage && exit;; + (n) noact=1;; + (v) verbose=1;; + (V) echo "$self v$VERSION" && exit;; + (*) usage && exit 1;; + esac +done + +shift "$((OPTIND - 1))" + +readconf "$CONFIGFILE" + +if [ -n "$all" ]; then + ifaces=$(auto "$CONFIG") +else + ifaces="$@"; +fi + +for iface in $ifaces; do + $action "$iface" "$CONFIG" +done diff --git a/SRC/iftools/ifup.8 b/SRC/iftools/ifup.8 index 77e326a..4d2ae1d 100644 --- a/SRC/iftools/ifup.8 +++ b/SRC/iftools/ifup.8 @@ -5,30 +5,25 @@ ifup \- bring a network interface up ifdown \- take a network interface down .br ifreload \- reload interface configuration -.br -ifquery \- view current state of interfaces .SH SYNOPSIS .B ifup \f | .B ifdown \f | .B ifreload -\f | -.B ifquery \f .SH DESCRIPTION The .BR ifup " and " ifdown -commands may be used to configure (or, respectively, deconfigure) network +commands may be used to configure, or deconfigure network interfaces based on interface definitions in the file .IR /etc/network.conf ". The" .BR ifreload " command will perform an ifdown and ifup in one command." -.BR ifquery " may be used to display the running configuration." .SH OPTIONS A summary of options is included below. .TP -.BR \-a ", " \-\-all -If given to \fBifup\fP, affect all interfaces marked \fBauto\fP. +.BR \-a +If given to \fBifup\fP, all interfaces marked \fBauto\fP are brought online. Interfaces are brought up in the order in which they are defined in .IR /etc/network.conf . @@ -36,17 +31,17 @@ If given to \fBifdown\fP, affect all defined interfaces. Interfaces are brought down in the order in which they are listed in the configuration files. .TP -.BR \-h ", " \-\-help +.BR \-h Show summary of options. .TP -.BR \-n ", " \-\-no\-act -Don't configure any interfaces or run any "up" or "down" commands. +.BR \-n +Take no action, but output commands that would be executed. .TP -.BR \-V ", " \-\-version -Show copyright and version information. +.BR \-v +Show configuration steps as they are taken. .TP -.BR \-v ", " \-\-verbose -Show commands as they are executed. +.BR \-V +Show version information. .SH EXAMPLES .TP .B ifup -a @@ -62,25 +57,17 @@ Bring up interface .TP .B ifdown -a Bring down all interfaces that are currently up. -.TP -.B ifquery eth0 -Print the running configuration of eth0 .SH NOTES .BR ifup , .BR ifdown , -.BR ifreload , and -.BR ifquery +.BR ifreload are actually the same program called by different names. .P The program does not configure network interfaces directly; it runs low level utilities such as .BR ip to do its dirty work. -.P -When invoked a check will be performed to verify that there -are no other instances running. If another instance is -detected the program will exit with an error. .SH FILES .TP .I /etc/network.conf @@ -88,9 +75,6 @@ definitions of network interfaces See .BR network.conf (5) for more information. -.TP -.I /run/network/ifstate -current state of network interfaces .SH AUTHOR iftools was written by Jay Larson . The functionality is loosely based on the ifupdown suite written by Anthony Towns . .SH SEE ALSO diff --git a/SRC/iftools/network.conf.5 b/SRC/iftools/network.conf.5 index ed0c1e6..a277999 100644 --- a/SRC/iftools/network.conf.5 +++ b/SRC/iftools/network.conf.5 @@ -46,8 +46,8 @@ There can be multiple "auto" stanzas. brings the named interfaces up in the order listed. .P Lines beginning with "source-directory" are used to source multiple -files at once. All non-dotted files within the directory are sourced -in lexical order. +files at once. All non-dotted files ending in .conf within the directory +are sourced in lexical order. .P When sourcing directories, if a path doesn't have a leading slash it's considered relative to the directory containing the network.conf