Skip to content
Browse files

1.3: new Connection class, keep track of connections for use with net…

…scheme
  • Loading branch information...
1 parent a134377 commit 192f538ca6a7a4da79740568ca8abd7b249b48f2 @akkana committed Mar 25, 2012
Showing with 219 additions and 18 deletions.
  1. +67 −10 netutils.html
  2. +152 −8 netutils.py
View
77 netutils.html
@@ -1,14 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<html><head><title>Python: module netutils</title>
+<html><head><title>Python: module netutils-1.3</title>
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
-<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong>netutils</strong></big></big></font></td
+<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="netutils-1.html"><font color="#ffffff">netutils-1</font></a>.3</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/akkana/bin/netutils.py">/home/akkana/bin/netutils.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/akkana/web/software/netscheme/netutils-1.3.py">/home/akkana/web/software/netscheme/netutils-1.3.py</a></font></td></tr></table>
<p><tt>netutils:&nbsp;a&nbsp;set&nbsp;of&nbsp;networking&nbsp;utilities&nbsp;for&nbsp;Python.<br>
Copyright&nbsp;2010&nbsp;by&nbsp;Akkana&nbsp;Peck&nbsp;&lt;akkana@shallowsky.com&gt;<br>
&nbsp;...&nbsp;share&nbsp;and&nbsp;enjoy&nbsp;under&nbsp;the&nbsp;GPLv2&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;later.<br>
@@ -37,18 +37,26 @@
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="os.html">os</a><br>
</td><td width="25%" valign=top><a href="re.html">re</a><br>
+</td><td width="25%" valign=top><a href="shutil.html">shutil</a><br>
</td><td width="25%" valign=top><a href="subprocess.html">subprocess</a><br>
-</td><td width="25%" valign=top></td></tr></table></td></tr></table><p>
+</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl>
-<dt><font face="helvetica, arial"><a href="netutils.html#AccessPoint">AccessPoint</a>
-</font></dt><dt><font face="helvetica, arial"><a href="netutils.html#NetInterface">NetInterface</a>
-</font></dt><dt><font face="helvetica, arial"><a href="netutils.html#Route">Route</a>
+<dt><font face="helvetica, arial"><a href="netutils-1.3.html#AccessPoint">AccessPoint</a>
+</font></dt><dt><font face="helvetica, arial"><a href="netutils-1.3.html#Connection">Connection</a>
+</font></dt><dd>
+<dl>
+<dt><font face="helvetica, arial"><a href="netutils-1.3.html#DebianConnection">DebianConnection</a>
+</font></dt><dt><font face="helvetica, arial"><a href="netutils-1.3.html#ManualConnection">ManualConnection</a>
+</font></dt></dl>
+</dd>
+<dt><font face="helvetica, arial"><a href="netutils-1.3.html#NetInterface">NetInterface</a>
+</font></dt><dt><font face="helvetica, arial"><a href="netutils-1.3.html#Route">Route</a>
</font></dt></dl>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
@@ -68,6 +76,46 @@
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
+<font color="#000000" face="helvetica, arial"><a name="Connection">class <strong>Connection</strong></a></font></td></tr>
+
+<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
+<td width="100%">Methods defined here:<br>
+<dl><dt><a name="Connection-__init__"><strong>__init__</strong></a>(self, iface<font color="#909090">=None</font>)</dt></dl>
+
+</td></tr></table> <p>
+<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
+<tr bgcolor="#ffc8d8">
+<td colspan=3 valign=bottom>&nbsp;<br>
+<font color="#000000" face="helvetica, arial"><a name="DebianConnection">class <strong>DebianConnection</strong></a>(<a href="netutils-1.3.html#Connection">Connection</a>)</font></td></tr>
+
+<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
+<td width="100%">Methods defined here:<br>
+<dl><dt><a name="DebianConnection-__init__"><strong>__init__</strong></a>(self, iface<font color="#909090">=None</font>)</dt></dl>
+
+<dl><dt><a name="DebianConnection-connect"><strong>connect</strong></a>(self, essid)</dt><dd><tt>Connect&nbsp;to&nbsp;a&nbsp;particular&nbsp;essid&nbsp;using&nbsp;/etc/network/interfaces.<br>
+Pass&nbsp;essid=None&nbsp;to&nbsp;de-associate&nbsp;the&nbsp;interface&nbsp;from&nbsp;any&nbsp;essid.</tt></dd></dl>
+
+<dl><dt><a name="DebianConnection-reset"><strong>reset</strong></a>(self)</dt><dd><tt>Reset&nbsp;everything&nbsp;back&nbsp;to&nbsp;working&nbsp;the&nbsp;way&nbsp;it&nbsp;was&nbsp;before&nbsp;you&nbsp;started</tt></dd></dl>
+
+</td></tr></table> <p>
+<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
+<tr bgcolor="#ffc8d8">
+<td colspan=3 valign=bottom>&nbsp;<br>
+<font color="#000000" face="helvetica, arial"><a name="ManualConnection">class <strong>ManualConnection</strong></a>(<a href="netutils-1.3.html#Connection">Connection</a>)</font></td></tr>
+
+<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
+<td width="100%">Methods defined here:<br>
+<dl><dt><a name="ManualConnection-__init__"><strong>__init__</strong></a>(self, iface<font color="#909090">=None</font>)</dt></dl>
+
+<dl><dt><a name="ManualConnection-connect"><strong>connect</strong></a>(self, essid)</dt><dd><tt>Connect&nbsp;to&nbsp;a&nbsp;particular&nbsp;essid&nbsp;doing&nbsp;all&nbsp;the&nbsp;steps&nbsp;manually.<br>
+Pass&nbsp;essid=None&nbsp;to&nbsp;de-associate&nbsp;the&nbsp;interface&nbsp;from&nbsp;any&nbsp;essid.</tt></dd></dl>
+
+<dl><dt><a name="ManualConnection-reset"><strong>reset</strong></a>(self)</dt></dl>
+
+</td></tr></table> <p>
+<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
+<tr bgcolor="#ffc8d8">
+<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="NetInterface">class <strong>NetInterface</strong></a></font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
@@ -121,13 +169,22 @@
<tr><td bgcolor="#eeaa77"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl><dt><a name="-get_accesspoints"><strong>get_accesspoints</strong></a>()</dt><dd><tt>Return&nbsp;a&nbsp;list&nbsp;of&nbsp;visible&nbsp;wireless&nbsp;accesspoints.</tt></dd></dl>
- <dl><dt><a name="-get_interfaces"><strong>get_interfaces</strong></a>(only_up<font color="#909090">=False</font>)</dt><dd><tt>Returns&nbsp;a&nbsp;list&nbsp;of&nbsp;NetInterfaces&nbsp;for&nbsp;all&nbsp;eth*,&nbsp;wlan*&nbsp;or&nbsp;mlan*<br>
+ <dl><dt><a name="-get_first_wireless_interface"><strong>get_first_wireless_interface</strong></a>()</dt><dd><tt>Returns&nbsp;the&nbsp;first&nbsp;available&nbsp;wireless&nbsp;interface</tt></dd></dl>
+ <dl><dt><a name="-get_interfaces"><strong>get_interfaces</strong></a>(only_up<font color="#909090">=False</font>, name<font color="#909090">=None</font>)</dt><dd><tt>Returns&nbsp;a&nbsp;list&nbsp;of&nbsp;NetInterfaces&nbsp;for&nbsp;all&nbsp;eth*,&nbsp;wlan*&nbsp;or&nbsp;mlan*<br>
interfaces&nbsp;visible&nbsp;from&nbsp;ifconfig.<br>
Omit&nbsp;lo,&nbsp;vpn,&nbsp;ipv6&nbsp;and&nbsp;other&nbsp;non-physical&nbsp;interfaces.<br>
-If&nbsp;only_up&nbsp;is&nbsp;true,&nbsp;use&nbsp;ifconfig&nbsp;instead&nbsp;if&nbsp;ifconfig&nbsp;-a.</tt></dd></dl>
+If&nbsp;only_up&nbsp;is&nbsp;true,&nbsp;use&nbsp;ifconfig&nbsp;instead&nbsp;if&nbsp;ifconfig&nbsp;-a.<br>
+If&nbsp;name&nbsp;is&nbsp;specified,&nbsp;return&nbsp;only&nbsp;the&nbsp;first&nbsp;matching&nbsp;that&nbsp;name.</tt></dd></dl>
<dl><dt><a name="-get_wireless_interfaces"><strong>get_wireless_interfaces</strong></a>()</dt><dd><tt>Returns&nbsp;a&nbsp;list&nbsp;of&nbsp;wireless&nbsp;interfaces&nbsp;available.</tt></dd></dl>
<dl><dt><a name="-ifdown_all"><strong>ifdown_all</strong></a>()</dt><dd><tt>Take&nbsp;all&nbsp;current&nbsp;interfaces&nbsp;down.</tt></dd></dl>
<dl><dt><a name="-kill_by_name"><strong>kill_by_name</strong></a>(namelist)</dt><dd><tt>Kills&nbsp;all&nbsp;running&nbsp;processes&nbsp;that&nbsp;start&nbsp;with&nbsp;any&nbsp;of&nbsp;the<br>
strings&nbsp;in&nbsp;the&nbsp;given&nbsp;name&nbsp;list.</tt></dd></dl>
-</td></tr></table>
+</td></tr></table><p>
+<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
+<tr bgcolor="#55aa55">
+<td colspan=3 valign=bottom>&nbsp;<br>
+<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
+
+<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
+<td width="100%"><strong>__warningregistry__</strong> = {("Parent module 'netutils-1' not found while handling absolute import", &lt;type 'exceptions.RuntimeWarning'&gt;, 28): True}</td></tr></table>
</body></html>
View
160 netutils.py
@@ -5,7 +5,7 @@
# ... share and enjoy under the GPLv2 or (at your option) later.
"""netutils: a set of networking utilities for Python.
-Copyright 2010 by Akkana Peck <akkana@shallowsky.com>
+Copyright 2010, 2011 by Akkana Peck <akkana@shallowsky.com>
... share and enjoy under the GPLv2 or (at your option) later.
Provides the following:
@@ -25,7 +25,7 @@
of the names in namelist. Return a list of actual process names killed.
"""
-import os, subprocess, re
+import os, subprocess, re, shutil
class NetInterface :
"""A network interface, like eth1 or wlan0."""
@@ -71,6 +71,130 @@ def ifconfig_down(self) :
"""Mark the interface DOWN with ifconfig"""
subprocess.call(["ifconfig", self.name, "down"])
+
+class Connection :
+ def __init__(self, iface=None) :
+ if iface :
+ self.iface = iface
+ else :
+ self.iface = get_first_wireless_interface().name
+
+ self.essid = "unknown"
+
+class ManualConnection(Connection) :
+ def __init__(self, iface=None):
+ Connection.__init__(self, iface)
+
+ def connect(self, essid):
+ """Connect to a particular essid doing all the steps manually.
+ Pass essid=None to de-associate the interface from any essid.
+ """
+ netutils.ifdown_all()
+
+ iface.ifconfig_up()
+
+ iwargs = ["iwconfig", iface.name ]
+ if essid :
+ iwargs.append("essid")
+ iwargs.append(essid)
+ #iwargs.append("mode")
+ #iwargs.append("managed")
+
+ iwargs.append("key")
+ iwargs.append("off")
+ iwargs.append("enc")
+ iwargs.append("off")
+
+ subprocess.call(iwargs)
+
+ try :
+ # Debian uses different args for DHCP clients than anyone else
+ if os.access("/sbin/dhcpcd", os.R_OK):
+ subprocess.check_call(["dhcpcd", "-G", "-C", "resolv.conf",
+ iface.name])
+ else:
+ subprocess.check_call(["dhclient", iface.name])
+ except subprocess.CalledProcessError, e :
+ print "DHCP failed, error", e.returncode
+ iface.ifconfig_down()
+
+ # Mark the interface up (and call ifup too, if applicable)
+ subprocess.call(["ifconfig", iface.name, "up"])
+
+ self.essid = essid
+
+ def reset(self):
+ print "Sorry, manual reset isn't defined yet! Please implement me!"
+ self.essid = None
+
+class DebianConnection(Connection) :
+ def __init__(self, iface=None) :
+ Connection.__init__(self, iface)
+ self.interfaces = "/etc/network/interfaces"
+ self.interfaces_bak = "/etc/network/interfaces.bak"
+
+ print "Initialized debian connection, iface = ", self.iface
+
+ # Save off the old /etc/network/interfaces,
+ # since we'll be replacing it:
+ try :
+ shutil.copy2(self.interfaces, self.interfaces_bak)
+ except :
+ print "Couldn't back up interfaces file"
+
+ # Debian doesn't work well with manual networking tools --
+ # DHCP, in particular, works a lot less reliably on Debian than
+ # on other distros unless it's called automatically from the
+ # networking service.
+ def connect(self, essid) :
+ """Connect to a particular essid using /etc/network/interfaces.
+ Pass essid=None to de-associate the interface from any essid.
+ """
+
+ # If we're connected when we start, try to zero out networking first.
+ if self.essid :
+ subprocess.call(["ifconfig", self.iface, "down"])
+ fp = open(self.interfaces, "w")
+ print >>fp, """auto lo
+iface lo inet loopback
+"""
+ fp.close()
+ self.essid = None
+ subprocess.call(["service", "networking", "restart"])
+
+ # Okay, now it's reset, so specify the new network:
+ subprocess.call(["ifconfig", self.iface, "down"])
+ subprocess.call(["ifdown", self.iface])
+ fp = open(self.interfaces, "w")
+ print >>fp, """auto lo
+iface lo inet loopback
+
+auto %s
+iface %s inet dhcp
+wireless-essid %s
+""" % (self.iface, self.iface, essid)
+ fp.close()
+
+ # Mark the interface up (and call ifup too, if applicable).
+ # The difference among all these isn't documented, and in theory
+ # you should be able to call just ifup, but empirically this is
+ # the most reliable sequence:
+ subprocess.call(["ifconfig", self.iface, "up"])
+ subprocess.call(["ifup", self.iface])
+ subprocess.call(["service", "networking", "restart"])
+
+ self.essid = essid
+
+ def reset(self ):
+ """Reset everything back to working the way it was before you started"""
+ subprocess.call(["service", "networking", "stop"])
+ shutil.copy2(self.interfaces_bak, self.interfaces)
+ subprocess.call(["ifconfig", self.iface, "up"])
+ subprocess.call(["ifup", self.iface])
+ subprocess.call(["service", "networking", "start"])
+
+ self.essid = "unknown"
+
class AccessPoint :
""" One Cell or AccessPoint from iwlist output"""
@@ -128,16 +252,18 @@ def __repr__(self) :
def call_route(self, cmd) :
"""Backend routine to call the system route command.
-cmd is either "add" or "delete".
-Users should normally call add() or delete() instead."""
+ cmd is either "add" or "delete".
+ Users should normally call add() or delete() instead."""
args = [ "route", cmd ]
# Syntax seems to be different depending whether dest is "default"
# or not. The man page is clear as mud and explains nothing.
if self.dest == 'default' or self.dest == '0.0.0.0' :
# route add default gw 192.168.1.1
# route del default gw 192.168.160.1
- args.append(self.dest)
+ # Must use "default" rather than "0.0.0.0" --
+ # the numeric version results in "SIOCDELRT: No such process"
+ args.append("default")
if self.gateway :
args.append("gw")
args.append(self.gateway)
@@ -169,7 +295,7 @@ def delete(self) :
@staticmethod
def read_route_table() :
"""Read the system routing table, returning a list of Routes."""
- proc = subprocess.Popen('route', shell=False, stdout=subprocess.PIPE)
+ proc = subprocess.Popen('route -n', shell=True, stdout=subprocess.PIPE)
stdout_str = proc.communicate()[0]
stdout_list = stdout_str.split('\n')
@@ -181,13 +307,16 @@ def read_route_table() :
return rtable
-def get_interfaces(only_up=False) :
+def get_interfaces(only_up=False, name=None) :
"""Returns a list of NetInterfaces for all eth*, wlan* or mlan*
interfaces visible from ifconfig.
Omit lo, vpn, ipv6 and other non-physical interfaces.
If only_up is true, use ifconfig instead if ifconfig -a.
+ If name is specified, return only the first matching that name.
"""
- if only_up :
+ if name :
+ ifcfg = "ifconfig " + name
+ elif only_up :
ifcfg = 'ifconfig'
else :
ifcfg = '/sbin/ifconfig -a'
@@ -254,6 +383,12 @@ def get_interfaces(only_up=False) :
cur_iface.essid = match.group(1)
# print "And it has essid", iface.essid
+ # If name was specified, return only that single interface:
+ if name:
+ if len(ifaces) <= 0 or ifaces[0].name != name:
+ return None
+ return ifaces[0]
+
return ifaces
def get_wireless_interfaces() :
@@ -265,6 +400,15 @@ def get_wireless_interfaces() :
wifaces.append(iface)
return wifaces
+def get_first_wireless_interface():
+ """Returns the first available wireless interface
+ """
+ wifaces = []
+ for iface in get_interfaces() :
+ if iface.wireless :
+ return iface
+ return None
+
def get_accesspoints() :
"""Return a list of visible wireless accesspoints."""

0 comments on commit 192f538

Please sign in to comment.
Something went wrong with that request. Please try again.