607 lines
22 KiB
Python
607 lines
22 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2009-2010 TUBITAK/UEKAE
|
|
# Licensed under the GNU General Public License, version 2.
|
|
# See the file http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
|
#
|
|
#
|
|
#
|
|
# A migration script to transform COMAR based network profiles into NetworkManager based network profiles.
|
|
#
|
|
# The main purpose of the script is help Pardus 2009 users to be able to use their network profiles in Pardus 2011
|
|
# without any effort when they upgrade their system.
|
|
#
|
|
# A few words about how stuff works. COMAR based network manager keeps profile settings under /etc/network with two
|
|
# files: net_tools which includes ethernet profile settings and wireless_tools which includes wireless profile settings.
|
|
# On the other hand, NetworkManager keeps each profile settings in an individual file under /etc/NetworkManager/system-connections.
|
|
#
|
|
# This script simply reads your old profile files and try to create a new profile file compatible with NetworkManager for each profile.
|
|
#
|
|
#
|
|
|
|
|
|
import os
|
|
import ConfigParser
|
|
|
|
|
|
default_nameservers = []
|
|
default_resolv_conf_file = "/etc/resolv.default.conf"
|
|
lan_config_file = "/etc/network/net_tools"
|
|
wlan_config_file = "/etc/network/wireless_tools"
|
|
migration_sign = "/etc/network/.migrated"
|
|
NetworkManager_conf_dir = "/etc/NetworkManager/system-connections"
|
|
|
|
def is_migrated_before():
|
|
"""Make this tool run once; so after migration, touch a file named '.migrated'
|
|
under old network manager profiles dir. Check it first and then try to migrate profiles.
|
|
"""
|
|
|
|
global migration_sign
|
|
if os.path.exists(migration_sign):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_default_nameservers():
|
|
"""Read once default name servers in resolve.default.conf, if 'name_mode' in
|
|
given profile was set to default, supply these values in the new profile file
|
|
"""
|
|
global default_nameservers
|
|
if len(default_nameservers) == 0:
|
|
if os.path.exists(default_resolv_conf_file):
|
|
with open(default_resolv_conf_file) as f:
|
|
nameservers_file = f.readlines()
|
|
|
|
for line in nameservers_file:
|
|
if not line.startswith("#") and line.startswith("nameserver"):
|
|
ns = line.split()[-1]
|
|
default_nameservers.append(ns)
|
|
|
|
#If we can't find default.resolv.conf, supply default Pardus DNS servers
|
|
else:
|
|
default_nameservers = ["193.140.100.210", "193.140.100.215", "193.140.100.220"]
|
|
|
|
return default_nameservers
|
|
|
|
|
|
class PardusNetworkProfile:
|
|
"""Represents COMAR based network profiles that we have been using in Pardus' network
|
|
manager. We have two types of network profiles specified: wired or wireless
|
|
"""
|
|
|
|
def __init__(self, name, connection_type, settings):
|
|
|
|
self.profile_name = name
|
|
self.connection_type = connection_type
|
|
self.device = "none"
|
|
self.net_mode = "none"
|
|
self.name_mode = "none"
|
|
self.state = "none"
|
|
self.name_server = "none"
|
|
self.net_address = "none"
|
|
self.net_mask = "none"
|
|
self.net_gateway = "none"
|
|
self.remote = "none"
|
|
self.auth = "none"
|
|
self.auth_password = "none"
|
|
|
|
self.set_attributes(settings)
|
|
|
|
def set_attributes(self, settings):
|
|
"""We receive profile settings as dictionary type in 'settings'
|
|
Map each key-value pairs for each object.
|
|
"""
|
|
|
|
for key, value in settings.items():
|
|
self.__dict__[key] = value
|
|
|
|
def get_profile_name(self):
|
|
return self.profile_name
|
|
|
|
def get_connection_type(self):
|
|
return self.connection_type
|
|
|
|
def get_device(self):
|
|
return self.device
|
|
|
|
def get_net_mode(self):
|
|
return self.net_mode
|
|
|
|
def get_name_mode(self):
|
|
return self.name_mode
|
|
|
|
def get_state(self):
|
|
return self.state
|
|
|
|
def get_name_server(self):
|
|
return self.name_server
|
|
|
|
def get_net_address(self):
|
|
return self.net_address
|
|
|
|
def get_net_mask(self):
|
|
return self.net_mask
|
|
|
|
def get_net_gateway(self):
|
|
return self.net_gateway
|
|
|
|
def get_remote(self):
|
|
return self.remote
|
|
|
|
def get_auth(self):
|
|
return self.auth
|
|
|
|
def get_auth_password(self):
|
|
return self.auth_password
|
|
|
|
|
|
class NetworkManagerProfile:
|
|
"""Represents network profiles used in NetworkManager. In NetworkManager,
|
|
settings are kept in a seperate file for each profile.
|
|
"""
|
|
|
|
def __init__(self, name, pardus_profile):
|
|
"""Each section is kept in corresponding class attribute"""
|
|
|
|
self.cfg = ConfigParser.ConfigParser()
|
|
self.connection = Connection(pardus_profile)
|
|
self.ipv4 = IpV4(pardus_profile)
|
|
self.ipv6 = IpV6(pardus_profile)
|
|
self._802_3_ethernet = self.set_802_3_ethernet(pardus_profile)
|
|
self._802_11_wireless = self.set_802_11_wireless(pardus_profile)
|
|
self._802_11_wireless_security = self.set_802_11_wireless_security(pardus_profile)
|
|
|
|
self.create_config()
|
|
|
|
def set_802_3_ethernet(self, pardus_profile):
|
|
"""If this is a wired (802-3-ethernet) profile, set _802_3_ethernet
|
|
attribute.
|
|
"""
|
|
|
|
if pardus_profile.connection_type == "802-3-ethernet":
|
|
return _802_3_Ethernet(pardus_profile)
|
|
else:
|
|
return "none"
|
|
|
|
def set_802_11_wireless(self, pardus_profile):
|
|
"""If this is a wireless (802-11-wirelesss) profile, set
|
|
_802_11_wireless attribute."""
|
|
if pardus_profile.connection_type == "802-11-wireless":
|
|
return _802_11_Wireless(pardus_profile)
|
|
else:
|
|
return "none"
|
|
|
|
def set_802_11_wireless_security(self, pardus_profile):
|
|
"""If the wireless connection has any security restrictions, create a
|
|
802-11-wireless-security section with corresponding values.
|
|
"""
|
|
|
|
if pardus_profile.get_connection_type() == "802-11-wireless": #Check if it is a wlan profile
|
|
if pardus_profile.get_auth() == "none":
|
|
self._802_11_wireless.security = "none"
|
|
return "none"
|
|
else:
|
|
self._802_11_wireless.security = "802-11-wireless-security"
|
|
return _802_11_Wireless_Security(pardus_profile)
|
|
else:
|
|
return "none"
|
|
|
|
def create_config(self):
|
|
"""Create sections and options in the prfoile's config file by calling
|
|
each options corresponding method.
|
|
"""
|
|
|
|
#FIXME: Try to do it over loops ie. self[attr].set_config()
|
|
for attr, value in self.__dict__.items():
|
|
if attr == "connection":
|
|
self.connection.set_config(self.cfg)
|
|
if attr == "ipv4":
|
|
self.ipv4.set_config(self.cfg)
|
|
if attr == "ipv6":
|
|
self.ipv6.set_config(self.cfg)
|
|
if attr == "_802_3_ethernet" and not value == "none":
|
|
self._802_3_ethernet.set_config(self.cfg)
|
|
if attr == "_802_11_wireless" and not value == "none":
|
|
self._802_11_wireless.set_config(self.cfg)
|
|
if attr == "_802_11_wireless_security" and not value == "none":
|
|
self._802_11_wireless_security.set_config(self.cfg)
|
|
|
|
def write_config(self):
|
|
"""Write settings to profile file"""
|
|
|
|
#Before writing to file we must convert underscores to dashes, moreover _id must be written as id, and _type as type
|
|
|
|
if not os.path.exists(NetworkManager_conf_dir):
|
|
os.makedirs(NetworkManager_conf_dir, mode=0755)
|
|
|
|
profile_path = os.path.join("%s" % NetworkManager_conf_dir, self.connection._id)
|
|
with open(profile_path, "wb") as configfile:
|
|
self.cfg.write(configfile)
|
|
|
|
def set_ownership(self):
|
|
"""NetworkManager is smart enough to understand whether a configuration file is valid
|
|
by checking its permissions"""
|
|
|
|
os.chmod(os.path.join("%s" % NetworkManager_conf_dir, self.connection._id), 0600)
|
|
|
|
|
|
class Connection:
|
|
"""Instances of Connection class represent essential properties of a network connection to identify itself."""
|
|
|
|
def __init__(self, pardus_profile):
|
|
self.name = "connection"
|
|
self._id = pardus_profile.get_profile_name()
|
|
self.uuid = self.set_uuid(device = pardus_profile.get_device())
|
|
self._type = pardus_profile.get_connection_type()
|
|
self.autoconnect = self.set_autoconnect(pardus_profile)
|
|
self.timestamp = "none"
|
|
self.read_only = "false"
|
|
|
|
def set_autoconnect(self, profile):
|
|
"""Set profile activation at startup"""
|
|
|
|
if str(profile.get_state()) == "down":
|
|
return "false"
|
|
else:
|
|
return "none" #NM set this 'true' as default if we dont set anything
|
|
|
|
def set_uuid(self, device):
|
|
"""Generate random type UUID"""
|
|
import uuid
|
|
|
|
return str(uuid.uuid4())
|
|
|
|
def set_config(self, cfg):
|
|
"""One single config file will be used to write settings"""
|
|
|
|
cfg.add_section(self.name)
|
|
for attr, value in self.__dict__.items():
|
|
if value not in ["false", "none"] and attr != "name":
|
|
#Before creating config file _id must be id, and _type must be type
|
|
if attr == "_id" or attr == "_type" : attr = attr.split("_")[-1]
|
|
#There isnt any underscore in config options, replace them with dashes if found any
|
|
attr = attr.replace("_", "-")
|
|
cfg.set(self.name, attr, value)
|
|
|
|
|
|
class IpV4:
|
|
"""Instances of IpV4 class represent IPv4 based properties of a connection."""
|
|
|
|
def __init__(self, pardus_profile):
|
|
self.name = "ipv4"
|
|
self.dns_search = "none"
|
|
self.routes = "none"
|
|
self.ignore_auto_routes = "false"
|
|
self.ignore_auto_dns = "false"
|
|
self.dhcp_client_id = "none"
|
|
self.dhcp_send_hostname = "false"
|
|
self.dhcp_hostname = "none"
|
|
self.never_default = "false"
|
|
self.method = pardus_profile.get_net_mode() # auto or manual, same as in NM
|
|
self.addresses1 = self.set_addresses(pardus_profile) # NM uses array of IPv4 address structures. We have only one for each iface
|
|
self.dns = self.set_dns(pardus_profile)
|
|
|
|
def set_dns(self, pardus_profile):
|
|
"""Decide whether to use default, custom or auto (DHCP assigned) nameservers"""
|
|
|
|
if pardus_profile.get_name_mode() == "default":
|
|
default_nameservers = ";".join( get_default_nameservers())
|
|
default_nameservers = default_nameservers + ";" # Make sure addresses end with ';'
|
|
self.ignore_auto_dns = "true"
|
|
return str(default_nameservers)
|
|
elif pardus_profile.get_name_mode() == "custom":
|
|
name_server = str(pardus_profile.get_name_server())
|
|
name_server = name_server + ";"
|
|
self.ignore_auto_dns = "true"
|
|
return str(name_server)
|
|
else:
|
|
# Nothing done in auto option
|
|
return "none"
|
|
|
|
def set_addresses(self, pardus_profile):
|
|
"""Set network addresses from given settings"""
|
|
|
|
addresses = []
|
|
if self.method == "manual":
|
|
net_mask = self.calculate_prefix(pardus_profile.get_net_mask())
|
|
addresses.append(str(pardus_profile.get_net_address()))
|
|
addresses.append(str(net_mask))
|
|
addresses.append(str(pardus_profile.get_net_gateway()))
|
|
addresses = ";".join(addresses)
|
|
addresses = addresses + ";" # Make sure addresses end with ';'
|
|
return addresses
|
|
else:
|
|
return "none"
|
|
|
|
def decimal2binary(self, n):
|
|
"""Convert decimal octet value to binary format"""
|
|
|
|
octet = ["0", "0", "0", "0", "0", "0", "0", "0"]
|
|
index = 0
|
|
if n < 0 or n > 255:
|
|
raise ValueError, "Octet value must be between [0-255]"
|
|
if n == 0:
|
|
return "".join(octet)
|
|
while n > 0:
|
|
octet[index] = str((n % 2))
|
|
index += 1
|
|
n = n >> 1
|
|
octet.reverse()
|
|
return "".join(octet)
|
|
|
|
def calculate_prefix(self, net_mask):
|
|
"""Convert netmask value to CIDR prefix type which is between [1-32] as told in NM spec
|
|
See http://mail.gnome.org/archives/networkmanager-list/2008-August/msg00076.html"""
|
|
|
|
octets = net_mask.split(".")
|
|
octet_in_binary = []
|
|
netmask_value = 0
|
|
for octet in octets:
|
|
ret = self.decimal2binary(int(octet))
|
|
octet_in_binary.append(ret)
|
|
for i in "".join(octet_in_binary):
|
|
if int(i) == 1 : netmask_value += 1
|
|
return netmask_value
|
|
|
|
def set_config(self, cfg):
|
|
"""One single config file will be used to write settings"""
|
|
|
|
cfg.add_section(self.name)
|
|
for attr, value in self.__dict__.items():
|
|
if value not in ["false", "none"] and attr != "name":
|
|
attr = attr.replace("_", "-")
|
|
cfg.set(self.name, attr, value)
|
|
|
|
|
|
class IpV6:
|
|
"""Instances of IpV6 class represent IPv6 based properties of a connection."""
|
|
|
|
def __init__(self, pardus_profile):
|
|
self.name = "ipv6"
|
|
self.method = "none"
|
|
self.dns = "none"
|
|
self.dns_search = "none"
|
|
self.addresses = "none"
|
|
self.routes = "none"
|
|
self.ignore_auto_routes = "false"
|
|
self.ignore_auto_dns = "false"
|
|
self.dhcp_client_id = "none"
|
|
self.dhcp_send_hostname = "none"
|
|
self.dhcp_hostname = "none"
|
|
self.never_default = "false"
|
|
|
|
self.set_method()
|
|
|
|
def set_method(self):
|
|
"""Ignoring by default for nowadays"""
|
|
self.method = "ignore"
|
|
|
|
def set_config(self, cfg):
|
|
"""One single config file will be used to write settings"""
|
|
|
|
cfg.add_section(self.name)
|
|
for attr, value in self.__dict__.items():
|
|
if value not in ["false", "none"] and attr != "name":
|
|
attr = attr.replace("_", "-")
|
|
cfg.set(self.name, attr, value)
|
|
|
|
class _802_3_Ethernet:
|
|
"""Instances of _802_3_Ethernet class represent options related with ethernet device."""
|
|
|
|
def __init__(self, pardus_profile):
|
|
self.name = "802-3-ethernet"
|
|
self.port = "none"
|
|
self.speed = "none" #0
|
|
self.duplex = "full"
|
|
self.auto_negotiate = "false"
|
|
self.mac_address = self.set_mac_address(pardus_profile.get_device())
|
|
self.mtu = "none" #0
|
|
|
|
def set_mac_address(self, iface):
|
|
"""Return MAC addresses of given interface on the machine"""
|
|
if os.path.exists("/sys/class/net/%s" % iface):
|
|
return open("/sys/class/net/%s/address" % iface).read().strip()
|
|
return "none"
|
|
|
|
def set_config(self, cfg):
|
|
"""One single config file will be used to write settings"""
|
|
|
|
cfg.add_section(self.name)
|
|
for attr, value in self.__dict__.items():
|
|
if value not in ["false", "none"] and attr != "name":
|
|
attr = attr.replace("_", "-")
|
|
cfg.set(self.name, attr, value)
|
|
|
|
|
|
class _802_11_Wireless:
|
|
"""Instances of _802_11_Wireless class represent options related with wireless device."""
|
|
|
|
def __init__(self, pardus_profile):
|
|
self.name = "802-11-wireless"
|
|
self.ssid = self.set_ssid(pardus_profile)
|
|
self.band = "none"
|
|
self.channel = "0"
|
|
self.bssid = "none"
|
|
self.rate = "0"
|
|
self.tx_power = "0"
|
|
self.mtu = "0"
|
|
self.seen_bssids = "none"
|
|
self.security = "none"
|
|
self.mode = self.set_mode(pardus_profile)
|
|
self.mac_address = self.set_mac_address(pardus_profile.get_device())
|
|
|
|
def set_mac_address(self, iface):
|
|
"""Return MAC addresses of given interface on the machine"""
|
|
if os.path.exists("/sys/class/net/%s" % iface):
|
|
return open("/sys/class/net/%s/address" % iface).read().strip()
|
|
return "none"
|
|
|
|
def set_mode(self, pardus_profile):
|
|
"""One of 'infrastructure' or 'adhoc'. If blank, infrastructure is assumed"""
|
|
|
|
#TODO: How to determine mode (adhoc or infrastructure) from old profile settings
|
|
return "infrastructure"
|
|
|
|
def set_ssid(self, pardus_profile):
|
|
"""Set ssid value"""
|
|
|
|
if pardus_profile.connection_type == "802-11-wireless":
|
|
return str(pardus_profile.get_remote())
|
|
else:
|
|
return "none"
|
|
|
|
def set_config(self, cfg):
|
|
"""One single config file will be used to write settings"""
|
|
|
|
cfg.add_section(self.name)
|
|
for attr, value in self.__dict__.items():
|
|
if value not in ["false", "none", "0"] and attr != "name":
|
|
attr = attr.replace("_", "-")
|
|
cfg.set(self.name, attr, value)
|
|
|
|
|
|
class _802_11_Wireless_Security:
|
|
"""Instances of _802_11_Wireless_Security class represent authentication properties and operations
|
|
used in order to be included in networks requiring them.
|
|
"""
|
|
|
|
def __init__(self, pardus_profile):
|
|
self.name = "802-11-wireless-security"
|
|
self.key_mgmt = "none"
|
|
self.wep_tx_keyidx = "0"
|
|
self.auth_alg = "none"
|
|
self.proto = "none"
|
|
self.pairwise = "none"
|
|
self.group = "none"
|
|
self.leap_username = "none"
|
|
self.wep_key0 = "none"
|
|
self.wep_key1 = "none"
|
|
self.wep_key2 = "none"
|
|
self.wep_key3 = "none"
|
|
self.psk = "none"
|
|
self.leap_password = "none"
|
|
self.wep_key_type = "0"
|
|
|
|
self.set_up_wireless_security(pardus_profile)
|
|
|
|
def set_up_wireless_security(self, pardus_profile):
|
|
"""WEP, WPA or none type security based operations"""
|
|
|
|
if pardus_profile.get_auth() in ["wep", "wepascii"]:
|
|
self.set_wep(pardus_profile)
|
|
elif pardus_profile.get_auth() == "wpa-psk":
|
|
self.set_wpa(pardus_profile)
|
|
else:
|
|
return
|
|
|
|
def set_wpa(self, pardus_profile):
|
|
"""Set up WPA based networks"""
|
|
|
|
self.key_mgmt = "wpa-psk"
|
|
self.psk = str(pardus_profile.get_auth_password())
|
|
|
|
def set_wep(self, pardus_profile):
|
|
"""Set up WEP based networks"""
|
|
|
|
self.auth_alg = "open" #TODO: or 'shared' ??
|
|
self.key_mgmt = "None" # Which stands for WEP based key management
|
|
self.wep_key0 = str(pardus_profile.get_auth_password()) # Default index
|
|
self.wep_key_type = "1" # Interpret WEP keys as hex or ascii keys
|
|
|
|
|
|
def set_config(self, cfg):
|
|
"""One single config file will be used to write settings"""
|
|
|
|
cfg.add_section(self.name)
|
|
for attr, value in self.__dict__.items():
|
|
if value not in ["false", "none", "0"] and attr != "name":
|
|
attr = attr.replace("_", "-")
|
|
|
|
# key-mgmt=none is a mandatory assignment for WEP based
|
|
# configurations. As we set all class members' default value
|
|
# to 'none', and then filter to set config file with non-none
|
|
# values, key-mgmt is set to 'None' intentionally to pass that
|
|
# filtering, and its value is set later on by lowercasing to
|
|
# hack around this situation.
|
|
if attr == "key-mgmt":
|
|
value = value.lower()
|
|
cfg.set(self.name, attr, value)
|
|
|
|
|
|
class Migrator:
|
|
"""Read COMAR based network profiles we have been using in Pardus' network manager and
|
|
transform them into NetworkManager profile type.
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
self.pardus_profiles = []
|
|
self.network_manager_profiles = []
|
|
self.lan_config_path = lan_config_file
|
|
self.wlan_config_path = wlan_config_file
|
|
self.read_pardus_profiles()
|
|
|
|
def read_pardus_profiles(self):
|
|
"""Read wired/wireless profile settings, create PardusNetworkProfile
|
|
object for each one, and store them in a list.
|
|
"""
|
|
|
|
self.lan_config = ConfigParser.ConfigParser()
|
|
self.lan_config.read(self.lan_config_path)
|
|
connection_type = "802-3-ethernet"
|
|
for section in self.lan_config.sections():
|
|
lan_settings = {}
|
|
for option in self.lan_config.options(section):
|
|
if option == "device":
|
|
#To strip device name from long device string
|
|
lan_settings[option] = self.lan_config.get(section, option).split("_")[-1]
|
|
else:
|
|
lan_settings[option] = self.lan_config.get(section, option)
|
|
p = PardusNetworkProfile(section, connection_type, lan_settings)
|
|
self.pardus_profiles.append(p)
|
|
|
|
self.wlan_config = ConfigParser.ConfigParser()
|
|
self.wlan_config.read(self.wlan_config_path)
|
|
connection_type = "802-11-wireless"
|
|
for section in self.wlan_config.sections():
|
|
wlan_settings = {}
|
|
for option in self.wlan_config.options(section):
|
|
if option == "device":
|
|
wlan_settings[option] = self.wlan_config.get(section, option).split("_")[-1]
|
|
else:
|
|
wlan_settings[option] = self.wlan_config.get(section, option)
|
|
p = PardusNetworkProfile(section, connection_type, wlan_settings)
|
|
self.pardus_profiles.append(p)
|
|
|
|
def transform_profiles(self):
|
|
"""Convert Pardus' network profiles to NetworkManager profiles"""
|
|
|
|
if len(self.pardus_profiles) > 0: # Make sure we have some profiles to migrate
|
|
for profile in self.pardus_profiles:
|
|
network_manager_profile = NetworkManagerProfile(profile.get_profile_name, profile)
|
|
self.network_manager_profiles.append(network_manager_profile)
|
|
|
|
def write_network_manager_profiles(self):
|
|
"""Create profile file for each NetworkManager profile and change ownerships to 0600"""
|
|
|
|
if len(self.network_manager_profiles) > 0: # Make sure we have some profiles to migrate
|
|
for profile in self.network_manager_profiles:
|
|
profile.write_config()
|
|
profile.set_ownership()
|
|
with open(migration_sign, "w") as f:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
print "DEBUG: Checking whether network profiles migrated..."
|
|
if not is_migrated_before():
|
|
m = Migrator()
|
|
m.transform_profiles()
|
|
m.write_network_manager_profiles()
|
|
print "DEBUG: Network profiles migration completed successfully!"
|
|
else:
|
|
print "DEBUG: Network profiles migration seems already done before. Nothing done this time!"
|
|
|