#!/usr/bin/perl -w ##=====================================================================## ## Copyright (C) 2001-2002 Stephen Zarkos. All rights reserved. ## Obsid@Sentry.net ## ## Please see file: COPYRIGHT for further copyright information and ## disclaimer. Or online at http://www.SentryFirewall.com/files/COPYRIGHT ##=====================================================================## ## File: networking.pl ## &networking: Utilizes $prefs{device*} to set up an interface and allow ## configuration to retr files via http or ftp. ## &retr_file: Retrieves file via ftp or http, puts it in /tmp, and returns ## the path/filename of retrieved file if retrieval was successful. $ENV{PATH} = "/bin:/sbin"; umask 022; ##-------------------------------------------------------------------------## ## sub networking() temporarily sets up networking device(s) to configure ## some system parameters over a network. sub networking { ## Mode: ## 1|NET_UP: Setup networking ## 2|NET_DOWN: Take down networking ## Returns: ## 0: Syntax error or some generic failure. ## 1: Success ## 2: Failure initializing device or assigning an IP address. my ($mode) = "$_[0]"; my ($network) = "0"; my ($device,$driver,$ip,$num) = ''; my ($ismodule) = ''; my ($kernel) = `/bin/uname -r`; my (@drivers,@builtin_drivers) = (); ($mode = "1") if ($mode eq 'NET_UP'); ($mode = "2") if ($mode eq 'NET_DOWN'); (return 0) if (($mode ne "1") && ($mode ne "2")); ## Define list of available modules. ## At the moment only 10/100 NICs and a couple gigabit ethernet cards are supported. if ($kernel =~ /^2\.2/) { ## List of modules that are available with the 2.2.x kernel(s) distributed with the ## Sentry CD. @drivers = ('3c501', '3c503', '3c507', '3c505', '3c509', '3c515', 'lance', 'wd', 'smc-ultra', 'smc9194', 'smc-ultra32', 'ni5010', 'ni65', 'ni52', 'rtl8139', 'at1700', 'e2100', 'depca', 'ewrk3', 'eexpress', 'eepro', 'fmv18x', 'hp-plus', 'hp100', 'hp', 'eth16i', 'ne', 'starfire', 'ac3200', 'cs89x0', 'dmfe', 'dgrs', 'lne390', 'ne3210', 'tlan', 'sis900', 'es3210', 'epic100', 'yellowfin', 'acenic', 'sk98lin', 'rtl8139'); ## List of modules that are built into the 2.2.x kernel(s) distributed with the ## Sentry CD. @builtin_drivers = ('3c59x', 'pcnet32', 'de4x5', 'tulip', 'eepro100', 'ne2k-pci', 'via-rhine', '8139too'); $kernel = '2.2'; } elsif ($kernel =~ /^2\.4/) { ## List of modules that are available with the 2.4.x kernels distributed with the ## Sentry CD. @drivers = ('3c501', '3c507', '3c505', '3c503', '3c509', '3c515', 'lance', 'wd', 'smc9194', 'smc-ultra', 'smc-ultra32', 'ni5010', 'ni65', 'ni52', 'at1700', 'depca', 'hp100', 'e2100', 'ewrk3', 'eexpress', 'eepro', 'hp', 'hp-plus', 'eth16i', 'ne', 'starfire', 'ac3200', 'cs89x', 'dgrs', 'dmfe', 'lne390', 'ne3210', 'es3210', 'sis900', 'epic100', 'winbond-840', 'acenic', 'hamachi', 'yellowfin', 'sundance', 'tlan'); ## List of modules that are built into the 2.4.x kernels distributed with the ## Sentry CD. @builtin_drivers = ('3c59x', 'natsemi', 'sunhme', 'via-rhine', '8139too', 'ne2k-pci', 'eepro100', 'tulip', 'pcnet32', 'de4x5'); $kernel = '2.4'; } else { return 0; } ## Unknown kernel version. ## "device" directive stuff. Setup networking. foreach $num (1..10) { next if !(exists($prefs{"device${num}"})); if ($prefs{"device${num}"} eq '') { delete($prefs{"device${num}"}); next; } &do_log("\'device${num}\' directive found, setting up device.") if ($mode eq '1'); &do_log("\'device${num}\' directive found, taking down device.") if ($mode eq '2'); $prefs{"device${num}"} =~ s/[\t\s]+//g; ($device,$driver,$ip) = split(/:/,$prefs{"device${num}"},3); if ($device !~ /^eth\d$/) { &do_log("ERROR: Syntax error in \'device${num}\' directive"); delete($prefs{"device${num}"}); next; } $driver =~ s/\.o$//; $ismodule = ''; foreach (@drivers) { next if ("$driver" ne "$_"); if ($mode eq "1") { if (grep(/$driver/,`/sbin/lsmod`)) { ## Kernel module is already loaded. $ismodule = "1"; last; } ## Get driver from tar file if ($kernel eq '2.2') { system("tar -zx -C /tmp/drivers -f /tmp/drivers/drivers-2.2.tar.gz ${driver}.o 1>/dev/null 2>/dev/null"); } elsif ($kernel eq '2.4') { system("tar -zx -C /tmp/drivers -f /tmp/drivers/drivers-2.4.tar.gz ${driver}.o 1>/dev/null 2>/dev/null"); } if ("$?" > "0") { delete($prefs{"device${num}"}); &do_log("ERROR: Unable to untar driver \'${driver}.o\'"); last; } ## Attempt to insmod driver. last if (!(-f "/tmp/drivers/${driver}.o")); system("insmod -qf /tmp/drivers/${driver}.o 1>/dev/null 2>/dev/null"); if ("$?" > "0") { system("rm -f /tmp/drivers/${driver}.o"); delete($prefs{"device${num}"}); &do_log("ERROR: Unable to insmod driver \'${driver}.o\'"); last; } else { system("rm -f /tmp/drivers/${driver}.o"); &do_log("Module ${driver}.o loaded successfully."); $ismodule = "1"; } last; } elsif ($mode eq "2") { ## Module exists, and may be loaded. Used later to unload driver. $ismodule = "1"; } } ## End foreach loop if ($ismodule eq '') { foreach (@builtin_drivers) { if ("$driver" eq "$_") { $ismodule = "0"; ## Driver found, but built into kernel. last; } } } if ($ismodule eq '') { ## No driver found, either built in or as a module. &do_log("ERROR: Unable to find driver for \'device${num}\'"); delete($prefs{"device${num}"}); next; } ## Silly ip address checks if ($ip !~ /^dhcp/) { my $tmpgw = ''; if ($ip =~ /\|/) { ($ip,$tmpgw) = split(/\|/,$ip,2); if ($tmpgw !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) { &do_log("Syntax error in \'device${num}\' directive."); delete($prefs{"device${num}"}); next; } } if ($ip =~ /\//) { if ($ip =~ /\/\d{1,2}$/) { my($nmask) = ""; ($ip,$nmask) = split(/\//,$ip,2); } else { $ip =~ s/\/.*//; } } if ($ip !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) { &do_log("Syntax error in \'device${num}\' directive."); delete($prefs{"device${num}"}); next; } my($tmpvar) = ''; foreach $tmpvar ($ip,$tmpgw) { my(@tmpip) = split(/\./,$tmpvar,4); foreach (@tmpip) { if (("$_" < "0") || ("$_" > "255")) { &do_log("Syntax error in \'device${num}\' directive."); delete($prefs{"device${num}"}); last; } } last if !(exists($prefs{"device${num}"})); } next if !(exists($prefs{"device${num}"})); if ($mode eq "1") { ## Attempt to set an IP Address. if (($nmask) && ($nmask ne '')) { if (!(grep(/\s${ip}\/${nmask}\s/, `/sbin/ip address show dev ${device}`))) { system("/sbin/ip address add ${ip}/${nmask} dev ${device} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { &do_log("ERROR: Unable to set up ip address for \'device${num}\'"); delete($prefs{"device${num}"}); next; } } } else { if (!(grep(/\s${ip}\/24\s/, `/sbin/ip address show dev ${device}`))) { system("/sbin/ip address add ${ip}/24 dev ${device} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { &do_log("ERROR: Unable to set up ip address for \'device${num}\'"); delete($prefs{"device${num}"}); next; } } } ## Bring $device up system("/sbin/ip link set dev ${device} up 1>/dev/null 2>/dev/null"); if ("$?" > "0") { system("/sbin/ip address delete ${ip} dev ${device} 1>/dev/null 2>/dev/null"); &do_log("ERROR: Unable to bring \'device${num}\' up."); delete($prefs{"device${num}"}); next; } ## Setup a default gateway if one was declared. if (($tmpgw) && ($tmpgw ne '')) { if (!(grep(/default\svia\s${tmpgw}\s/,`/sbin/ip route show`))) { system("/sbin/ip route add default via ${tmpgw} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { &do_log("ERROR: Unable to set up default gateway \'${tmpgw}\'."); system("/sbin/ip address delete ${ip} dev ${device} 1>/dev/null 2>/dev/null"); delete($prefs{"device${num}"}); next; } } } ${network}++; } elsif ($mode eq "2") { ## Remove default gateway. if (($tmpgw) && ($tmpgw ne '')) { system("/sbin/ip route delete default via ${tmpgw} 1>/dev/null 2>/dev/null"); } ## Unbind IP addy. system("/sbin/ip address delete ${ip} dev ${device} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { if ($ismodule eq "1") { system("rmmod ${driver} 1>/dev/null 2>/dev/null"); } delete($prefs{"device${num}"}); next; } ## Take down device. system("/sbin/ip link set dev ${device} down 1>/dev/null 2>/dev/null"); if ($ismodule eq "1") { system("rmmod ${driver} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { &do_log("ERROR: Unable to rmmod ${driver}."); delete($prefs{"device${num}"}); next; } } ${network}++; } } ## End block for setting up IP address(without dhcp). elsif ($ip =~ /^dhcp/) { $ip =~ s/^dhcp[\|]*//; if ($mode eq "1") { ## Attempt to run dhcp to get IP address if (!(-f "/var/run/dhcpcd-${device}.pid")) { if ("$ip" ne '') { system("/sbin/dhcpcd -t 30 -h ${ip} ${device} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { &do_log("ERROR: dhcpcd returned error."); delete($prefs{"device${num}"}); next; } } else { system("/sbin/dhcpcd -t 30 ${device} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { &do_log("ERROR: dhcpcd returned error."); delete($prefs{"device${num}"}); next; } } } ${network}++; } ## Killing dhcpcd elsif ($mode eq '2') { my $pid = ''; if (-f "/var/run/dhcpcd-${device}.pid") { if (open(FH, "; close(FH); chomp($pid); } if (($pid) && ($pid ne '')) { system("/bin/kill -TERM ${pid} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { &do_log("ERROR: An error occurred while attempting to kill dhcpcd."); system("/sbin/ip link set ${device} down 1>/dev/null 2>/dev/null"); if ($ismodule eq "1") { system("rmmod ${driver} 1>/dev/null 2>/dev/null"); } delete($prefs{"device${num}"}); next; } } } if ($ismodule eq "1") { system("rmmod ${driver} 1>/dev/null 2>/dev/null"); if ("$?" > "0") { delete($prefs{"device${num}"}); next; } } ${network}++; } } else { &do_log("ERROR: Syntax error in device${num} directive."); delete($prefs{"device${num}"}); next; } } ## End foreach loop ## Finally, let's just make sure there aren't any undead dhcpcd ## process running around. if ($mode eq '2') { system("/bin/killall -s 9 dhcpcd 1>/dev/null 2>/dev/null"); system("/bin/rm -f /var/run/dhcpcd-*.pid 1>/dev/null 2>/dev/null"); } if ($network > "0") { return 1; } else { return 0; } } ## End sub networking() ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Function to retrieve config files via http/ftp sub retr_file { my ($filename,$location) = ("$_[0]", "$_[1]"); my ($user,$pass) = ''; $filename =~ s/[\s\t]+//g; $location =~ s/[\s\t]+//g; $location =~ s/\/{2,}$/\//; ## Remove any extra '/' characters. ## wget parameters. my ($common_options,$http_options,$ftp_options,$scp_options,$sftp_options) =''; ## HTTP(S)/FTP/scp/sftp Options. if (($filename eq 'xinetd_dir') || ($filename eq 'sysconf_dir')) { $filename = "/tmp/${filename}"; $common_options = "-q -t2 -T 300 --directory-prefix=${filename} --no-host-directories"; $http_options = '--no-parent -r --level=4 -R "robots.txt,index.*,default.*" -A "*" --cookies=off --cache=off'; $ftp_options = '--no-parent -r --level=4 -R "robots.txt,index.*,default.*" -A "*" --cache=off'; $scp_options = '-qp -oStrictHostKeyChecking=no -r'; if ($filename eq '/tmp/sysconf_dir') { $sftp_options = '-oStrictHostKeyChecking=no -b /tmp/sftp-batch'; } else { $sftp_options = '-oStrictHostKeyChecking=no'; } ## We need to give wget an accurate --cut-dirs argument, otherwise it will either ## throw all the files in a single directory, or make directories we don't want to ## mirror the URL location. my $count = "0"; while ($location =~ /\//gi) { ## Count the number of '/' characters. ++$count; } if ($location =~ /\/$/) { $count -= "3"; } else { $count -= "2"; } if ($count ne "0") { $common_options .= " --cut-dirs=${count}"; } mkdir ("$filename", 0755); ## Make /tmp/{sysconf_dir,xinetd_dir} return 0 if ("$?" > "0"); } else { if ($filename !~ /\//) { $filename = "/tmp/${filename}"; } $common_options = "-q -t2 -T 300 -O ${filename}"; $http_options = '--cookies=off --cache=off'; $ftp_options = '--cache=off'; $scp_options = '-qp -oStrictHostKeyChecking=no'; $sftp_options = '-oStrictHostKeyChecking=no'; } ## Export HTTP proxy settings. if (exists($prefs{'http_proxy'})) { if (($prefs{'http_proxy'} =~ /^[hH]{1}[tT]{2}[pP]{1}:\/\//) && ($prefs{'http_proxy'} =~ /:{1}\d+\/?$/)) { $ENV{'http_proxy'} = "$prefs{'http_proxy'}"; $http_options .= ' --proxy=on'; if ((exists($prefs{'proxy-user'})) && (exists($prefs{'proxy-passwd'}))) { $http_options .= " --proxy-user=$prefs{'proxy-user'} --proxy-passwd=$prefs{'proxy-passwd'}"; } } } ## Export FTP proxy settings. if (exists($prefs{'ftp_proxy'})) { if (($prefs{'ftp_proxy'} =~ /^[hH]{1}[tT]{2}[pP]{1}:\/\//) && ($prefs{'ftp_proxy'} =~ /:{1}\d+\/?$/)) { $ENV{'ftp_proxy'} = "$prefs{'ftp_proxy'}"; if ((exists($prefs{'proxy-user'})) && (exists($prefs{'proxy-passwd'}))) { $ftp_options .= " --proxy-user=$prefs{'proxy-user'} --proxy-passwd=$prefs{'proxy-passwd'}"; } } } ## Passive FTP support. if (exists($prefs{'passive-ftp'})) { if (($prefs{'passive-ftp'} eq 'yes') || ($prefs{'passive-ftp'} eq 'on')) { $ftp_options .= ' --passive-ftp'; } } ## Retrieve file via HTTP(s)?. if ($location =~ /^[hH]{1}[tT]{2}[pP]{1}[sS]?:\/\//) { ## FIXME: Potential problems here. If a default file, like index.htm[l]?, exists, then a ## directory listing will not be available, and thus mirroring the directory structure will ## not be possible. This is only an issue with xinetd_dir and sysconf_dir directives. system("/bin/wget ${common_options} ${http_options} ${location} 1>/dev/null 2>/dev/null"); } ## Retrieve file via FTP. elsif ($location =~ /^[fF]{1}[tT]{1}[pP]{1}:\/\//) { system("/bin/wget ${common_options} ${ftp_options} ${location} 1>/dev/null 2>/dev/null"); } ## Retrieve file via SCP. elsif ($location =~ /^[sS]{1}[cC]{1}[pP]{1}:\/\//) { $location =~ s/^[sS]{1}[cC]{1}[pP]{1}:\/\///; (return 0) if ($location !~ /.+:.+\@/); ($user,$location) = split(/\@/, $location, 2); ($user,$pass) = split(/:/, $user, 2); $location =~ s/\//:\//; if (($filename eq 'xinetd_dir') || ($filename eq 'sysconf_dir')) { $location .= '/*'; $location =~ s/\/{2,}/\//g; } (return 0) if (($user eq '') || ($pass eq '')); system("/bin/scp ${scp_options} -opassword=${pass} ${user}\@${location} $filename 1>/dev/null 2>/dev/null"); } ## Retrieve file via SFTP. elsif ($location =~ /^[sS]{1}[fF]{1}[tT]{1}[pP]{1}:\/\//) { $location =~ s/^[sS]{1}[fF]{1}[tT]{1}[pP]{1}:\/\///; (return 0) if ($location !~ /.+:.+\@/); ($user,$location) = split(/\@/, $location, 2); ($user,$pass) = split(/:/, $user, 2); $location =~ s/\//:\//; ## sftp doesn't have a recursive -r option, so when dealing with the sysconf_dir directive, ## we need to manually grab the stuff in the subdirectories... a bit of a pain. if ($filename eq 'sysconf_dir') { if (&mk_batch("$location") == 1) { $location =~ s/:.*//; system("/bin/sftp ${sftp_options} -opassword=${pass} ${user}\@${location} 1>/dev/null 2>/dev/null"); } else { return 0; } } (return 0) if (($user eq '') || ($pass eq '')); if ($filename eq 'xinetd_dir') { $location .= '/*'; $location =~ s/\/{2,}/\//g; } system("/bin/sftp ${sftp_options} -opassword=${pass} ${user}\@${location} $filename 1>/dev/null 2>/dev/null"); } if ("$?" > "0") { if (($filename eq '/tmp/xinetd_dir') || ($filename eq '/tmp/sysconf_dir')) { system('rm', '-rf', "$filename"); } elsif (-f "$filename") { system('rm', '-f', "$filename"); } return 0; } ## Chmod rc files so that they're executable after download. if (("$filename" =~ /\/rc\./) && ("$filename" !~ /\/$/)) { if (!(-x "$filename")) { my $tmp = "$filename"; $tmp =~ s/.+\///; if ($tmp =~ /^rc\./) { chmod (0755, "$filename"); } } } ## Remove proxy settings delete($ENV{'http_proxy'}); delete($ENV{'ftp_proxy'}); return("$filename"); } ## End sub retr_file() ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Function to create a batch file for use with sftp. sub mk_batch { my $dirname = "$_[0]"; (return 0) if ($dirname eq ''); my $basedir = '/tmp/sysconf_dir'; (return 0) if (!(-d "$basedir")); my $batch_file = '/tmp/sftp-batch'; my @dirs = ('', 'apm-scripts', 'cbq', 'console', 'network-scripts', 'networking', 'networking/devices', 'networking/profiles', 'networking/profiles/default'); $dirname =~ s/:.*//; $dirname = "$&"; $dirname =~ s/://g; if (open(FH, ">$batch_file")) { flock(FH,2); foreach (@dirs) { print FH "cd ${dirname}/${_}\n"; print FH "get -P * $basedir/${_}/\n\n"; } print FH "quit\n"; close(FH); } else { &do_log("ERROR: Unable to open file \"$batch_file\""); return 0; } return 1; } ## End sub mk_batch() ##-------------------------------------------------------------------------## return 1; ## _EOF_ ##