Sunday, 20 September 2009

netprofiles0.2 "alpha release"

I'll get straight to the point, here are the tars:
netprofiles0.2 - use this to install the core scripts (it will untar to / unless otherwise told)
netprofiles0.2-NMcaller - This contains the NM caller (no bash script)
MyProfiles - My sample profiles (full,home,public,hidden)
you will also need to add a script to /etc/NetworkManger/dispatcher.d/ such as
#!/bin/sh
pkill chooseprofile.py
/etc/netprofiles/callers/NetworkManager/chooseprofile.py $2
exit 0
or netprofiles0.2-full - Everything including the bash script (it will untar /)


once installed you may want to make a link for set_uuid_profile.py as it is a program to be used by humans.
sudo ln -sv /etc/NetworkManager/callers/NetworkManager/set_uuid_profile.py /usr/bin/set_uuid_netprofile
I'm using and testing it on my computer but I haven't done extensive tests as I don't use all the features and don't know if anybody else is going to use it so consider the software untested.


License:
Do little scripts like this need a license? Is it worth GPLing something that is by its very nature open? I've assumed that its public domain on account of them being small scripts however if they can be licensed then the main script is derived from my /etc/rc so my code is under the same license.

Documentation:
I will add manpages in v0.3 if people start using it.

Code (in order of execution):
/etc/NetworkManager/dispatcher.d/80-profilechanger
#!/bin/sh
pkill chooseprofile.py
/etc/netprofiles/callers/NetworkManager/chooseprofile.py $2
exit 0
/etc/netprofiles/callers/NetworkManager/chooseprofile.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
log =  open("/var/log/netprofiles.log",'a')
profilemap = "/etc/netprofiles/callers/NetworkManager/profilemap"
settings = "/etc/netprofiles/callers/NetworkManager/settings"
executable ="/etc/netprofiles/run-netprofile"
try:
 from sys import exit,argv
 from os import system,EX_OK,EX_DATAERR,EX_USAGE
 from time import sleep
 import dbus
except:
 log.write("ERROR:modules not loaded correctly, dbus,sys,os,time may be missing or python maybe misconfigured\n")
 log.close()
 exit()

def getUuid():
 bus = dbus.SystemBus()
 proxy = bus.get_object("org.freedesktop.NetworkManager","/org/freedesktop/NetworkManager")  #find the active connection
 active_cons = proxy .Get("org.freedesktop.NetworkManager", "ActiveConnections")
 if len(active_cons) == 0: leave("ERROR:profilechanger called when not connected to a network\n",EX_DATAERR)
 active_con = active_cons[0]
 proxy  = bus.get_object("org.freedesktop.NetworkManager", active_con)     #move the proxy to the active connetion
 con = proxy .Get("org.freedesktop.NetworkManager", "Connection")    #get info on connection object
 service = proxy .Get("org.freedesktop.NetworkManager", "ServiceName") 
 proxy = bus.get_object(service,con)        #move the proxy to the real deal
 settings = proxy .GetSettings()         #get a dict of dicts
 consettings = settings['connection']
 uuid = consettings['uuid']
 return uuid

def getProfile(uuid):
 profile = ""
 try:
  f = open(profilemap, 'r')
 except IOError:
  log.write("ERROR:profilemap file could not be opened\n")
 else:
  for line in f:
   if line.startswith("#"): continue #allow comments
   line = line.split("#")[0]
   linelst = line.strip("\n").split(',')
   if uuid == linelst[0]:
    profile = linelst[1]
    break
 
  log.write("LOG:  "+uuid+" judged to be "+profile+"\n")
  f.close()
  
 if profile == "":
  log.write("LOG:  "+uuid+" is an unkown network\n")
  dAction, dProfile, dDelay, uCmd, profile = getSettings()
  if uCmd != "":
   log.write("LOG:  calling "+uCmd+" "+uuid+" "+profile+"\n")
   system(uCmd+" "+uuid+" "+profile)
 
 return profile


def getSettings():
 dAction = "change" #hardcode defaults incase of errors
 dProfile = "offline"
 dDelay = 0
 uProfile = "unkown"
 uCmd = ""
 
 try:
  f = open(settings,'r')
 except IOError:
  log.write("ERROR:settings file could not be opened\n")
 else:
  for line in f:
   if line.startswith("#"): continue #allow comments
   line = line.split("#")[0]
   linelst = line.strip("\n").split(' ',1)
   if len(linelst)>1:
    if linelst[0] == "onDisconnect": dAction = str(linelst[1])
    elif linelst[0] == "disconnectProfile": dProfile = str(linelst[1])
    elif linelst[0] == "disconnectDelay": dDelay = float(linelst[1])
    elif linelst[0] == "unkownProfile": uProfile = str(linelst[1])
    elif linelst[0] == "uCmd": uCmd = str(linelst[1])
  f.close() 
 return dAction, dProfile, dDelay, uCmd, uProfile

def run():
 if len(argv) != 2:
  leave("ERROR:"+argv[0]+" called with "+str(len(argv)-1)+" arguments but takes exactly 1\n",EX_USAGE)
 if argv[1] == "up":
  uuid = getUuid()
  profile = getProfile(uuid)
 elif argv[1] == "down":
  dAction, profile, dDelay, uCmd, uProfile = getSettings()
  if dAction == "change":
   sleep(dDelay)
  else:
   leave("LOG:  no action taken on network shutdown\n",EX_OK)
 
 system(executable+" "+profile)
 leave("LOG:  Switching to "+profile+"\n",EX_OK)
 
def leave(message="",code=EX_OK):
 log.write(message)
 log.close()
 exit(code)
run()
/etc/netprofiles/run-netprofile
#! /bin/bash
#
# netrc         This file is responsible for starting/stopping net services when the netprofile changes.
# Authors:
#  Juan Canham <juan.canham@googlemail.co.uk>
#               Miquel van Smoorenburg, (of RC not netrc DO NOT CONTACT HIM FOR SUPPORT)
# set -m

# check a file to be a correct runlevel script 
check_runlevel ()
{
 # Check if the file exists at all.
 [ -x "$1" ] || return 1
 is_ignored_file "$1" && return 1
 return 0
}

. /etc/init.d/functions

export CONSOLETYPE
UPSTART=
[ -x /sbin/initctl ] && UPSTART=yes

# Get first argument. Set new netprofile to this argument. 
[ -n $1 ] && netprofile=$1
profiledir=/etc/netprofiles/profiles/$netprofile
export netprofile

# Set language, vc settings once to avoid doing it for every init script
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
  . /etc/profile.d/lang.sh
  export LANGSH_SOURCED=1
fi

#run early scripts
for i in $profiledir/scripts/[0-2]* ; do
 [ -x $i ] && . $i $1
done

# First, run the KILL scripts.
for i in $profiledir/rc/[K,R]* ; do #kill then restart
 check_runlevel "$i" || continue
 # Check if the subsystem is already up.
 subsys=${i#$profiledir/rc/[K,R]??}
 [ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] || continue
 # Bring the subsystem down.
 [ -n "$UPSTART" ] && initctl emit --quiet "stopping $subsys"
 $i stop
 [ -n "$UPSTART" ] && initctl emit --quiet "stopped $subsys"
done

# move configs (external python script for now)
[ -d $profiledir/etc ] && /etc/netprofiles/linkswap.py $profiledir/etc

for i in iptables ip6tables arptables ; do
 [ -f $profiledir/$i  ] && $i-restore < $profiledir/$i
done

# run additional scripts
for i in $profiledir/scripts/[3-6]* ; do
 [ -x $i ] && . $i $1
done

# Iterate over the restart/start scripts
for n in {0..99}; do
 for i in $profiledir/rc/[S,R]$n* ; do #start then restart in sync
  check_runlevel "$i" || continue
  
  # Check if the subsystem is already up.
  subsys=${i#$profiledir/rc/[S,R]??} # figureout this line
  [ -f /var/lock/subsys/$subsys ] && continue  
  [ -f /var/lock/subsys/$subsys.init ] && continue
    
  # Bring the subsystem up.
  [ -n "$UPSTART" ] && initctl emit --quiet "starting $subsys"
  $i start
  [ -n "$UPSTART" ] && initctl emit --quiet "started $subsys"
 done
done

#run late scripts
for i in $profiledir/scripts/[7-9]* ; do
 [ -x $i ] && . $i $1
done

echo $netprofile > /var/run/netprofile
exit 0
/etc/netprofiles/linkswap.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import datetime
from sys import argv

newdir=argv[1]
offdir="/etc/netprofiles/profile/offline/etc"

def changelinks(top,ndir,fnames):
 rdir = "/"+ndir.strip(top)+"/"
 odir = "/etc"+rdir
 for fname in fnames:
  if os.path.isdir(ndir+fname): continue
  if not os.path.islink(odir+fname):
   if not exists(offdir+rdir): os.makedirs(offdir+rdir)
   if not lexists(offdir+rdir+fname):
    os.rename(odir+fname,offdir+rdir+fname)
    os.link(offdir+rdir+fname,odir+fname)
   else: #TODO: do a diff to save all this work
    i=0
    while lexists(offdir+rdir+fname+"-"+datetime.date.today().strftime("%Y%m%d")+"-"+i):
     i +=1
    os.rename(odir+fname,offdir+rdir+fname+"-"+datetime.date.today().strftime("%Y%m%d")+"-"+i)
    os.link(offdir+rdir+fname+"-"+datetime.date.today().strftime("%Y%m%d")+"-"+i,odir+fname)
  
  if islink(odir+fname): os.link(odir+fname,ndir+fname) #should i be messing with hardlinks?

os.path.walk(newdir,changelinks,newdir)
the default config file
onDisconnect change
disconnectProfile public
disconnectDelay 15
uProfile public
uCmd
my profiles (as on fedora 11)
sshd
rpcbind
rpcsvcgssd
rpcgssdsc
rpcidmapd
winbind
nmb
smb
vsftpd
avahi-deamon
nfs
nfslock
netfs
ntpd
portreserve
start
75
13
31
17
17
27
65
65
50
98
80
17
25
58
11
stop
25
87
69
83
83
73
35
35
50
2
20
83
75
42
88
full
on
on
on
on
on
restart
restart
restart
restart
on
on
on
on
on
on
home
off
on
on
on
on
restart
restart
restart
restart
on
on
on
on
on
on
public
off
off
off
off
off
off
off
off
off
off
off
off
off
on
off
hidden
off
off
off
off
off
off
off
off
off
off
off
off
off
off
off

unfortunately as I couldn't find what a default Ubuntu or fedora install looks like without messing around with liveCDs, the offline profile is empty

Access:
I'm not sure on the best way to give access to the code, if people start using it I will look into git/svn hosting or hosting it locally.

No comments:

Post a Comment