Codebase list python-pyric / 188e709
New upstream version 0.1.6 Raphaël Hertzog 5 years ago
28 changed file(s) with 971 addition(s) and 573 deletion(s). Raw diff Collapse all Expand all
4444 *.egg-info/
4545 .installed.cfg
4646 *.egg
47 PyRIC.egg-info
4847
4948 # PyCharm
5049 .idea
123123 - stainfo
124124 - devset
125125 - phylist
126 - openconnect (doesn't currently work)
127 - phyadd (renamed from original devadd, iw phy <phy> interface add ...)
128 - devadd (iw dev <dev> interface add ....)
126129 o updated nested netlink attribute handling - my understanding of it was incomplete
127130 - There are still occasional errors
128131 - nested attributes are parsed as 'far' as possible
129 o reupdated nested netlink attribute handling - this time it really works
132 o reupdated nested netlink attribute handling - this time it really works :)
130133 - nested attributes are now parsed correctly, any errors are a result of
131134 incorrect packing on the other side or packet corruption and the entire
132135 unparsed attribute will be returned.
134137 t = (index,attribute) which (TODO #41) eases the burden on the calling
135138 function
136139 - fixed 're'nesting of nested attributes
137 o parsing wiphy bands (issue #7) is now fully functional and no longer relies
138 on a hacked fix
140 - parsing wiphy bands (issue #7) is now fully functional and no longer relies
141 on a hacked fix
139142 o devstds now uses phyinfo to determine standards Card supports
140143 o completely 'remodeled' functions in pyw to take advantage of new parsing
141144 from libnl (have left some of the error checking in place as a backup until
143146 o fixed error on devadd during restoration in examples/pentest.py
144147 o fixed output error, incorrect labeling
145148 o fixed output error ASW max tx power
146 o added phylist w.r.t issue #17
149 o added phylist w.r.t issue #17
150 o fixed devfreqs, devchs after updating phyinfo
151 o add support for python3 (keeping compability with python2.7)
152 - urllib2 vs urllib
153 - replaced map with list comprehensions
154 - replaced xrange with range
155 - python 3.5 compatible. python 3.0 is compatible except for examples and
156 pyw.unittest.pyw (see corresponding files for reasons)
157 - python 2.7 is the preferred (for me at least) 'medium' and compatibly issues
158 with python 3 have been rectified at the expense of python 3 and not python 2
159 o fixed incorrect frequencies in unii_5_C2F in utils/channels
160 o updated pyw.unittest for python 3.5 and for added functions
161 o added by band to channels and freqs in utils/channels.py
162
163 v 0.1.6 Continue with STA functionality
164 o Issue #21 resolved. openconnect (renamed to connect) now works. (had to fix
165 how the ssid was being passed. as a string with a affixed null byte, it would
166 fail but as unspec, it succeeded)
167 - issue 1: wpa_supplicant must be turned off
168 - issue 2: caller/user must configure dhcp request or inet themselves
169 - issue 3: only works on open networks
170 o Issue #24 (TODO #50) resolved. getcard which is the entry point for any
171 nl80211 functionality uses devinfo to retrieve the Card tuple. devinfo will
172 now report No Such device as two seperate errors one identifying when there
173 is no device currently present on the machine and one identifying when the
174 specified dev's driver does not support nl80211
175 o fixed TypeError resulting from raising pyric.error incorrectly
176 o phyadd accepts either a card or a phy
177 o added freqget
178 o Note: w.r.t https://wraithwireless.wordpress.com/2016/07/24/linux-kernel-bug/
179 have tested further, phyadd,devadd will work (i.e. not rename the card)
180 under the following conditions a) the type is not managed or b) there is no
181 other device currently associated with the new card's phy. Have also determined
182 that integrated cards are also suspect to this bug?
183 o made pyric error messages less ambiguous
3838 activities, or otherwise in violation of any applicable law, regulation or legal
3939 agreement.
4040
41 See <http://www.gnu.org/licenses/> for a copy of the GNU General Public License.
41 See <http://www.gnu.org/licenses/> for a copy of the GNU General Public License.
0 # setup paramaters for PyRIC via PyPi
0 # setup paramaters for PyRIC via PyPi/pip install
11 include LICENSE CHANGES README.md TODO
22
33 # Include subdirectories
0 # PyRIC 0.1.5: Python Radio Interface Controller
0 # PyRIC 0.1.6: Python Radio Interface Controller
11 ## Linux wireless library for the Python Wireless Developer and Pentester
22 ![](docs/logo.png?raw=true)
33
44 [![License: GPLv3](https://img.shields.io/pypi/l/PyRIC.svg)](https://github.com/wraith-wireless/PyRIC/blob/master/LICENSE)
55 [![PyPI Version](https://img.shields.io/pypi/v/PyRIC.svg)](https://pypi.python.org/pypi/PyRIC)
6 [![Downloads per month on PyPI](https://img.shields.io/pypi/dm/PyRIC.svg)](https://pypi.python.org/pypi/PyRIC)
76 ![Supported Python Versions](https://img.shields.io/pypi/pyversions/PyRIC.svg)
87 ![Software status](https://img.shields.io/pypi/status/PyRIC.svg)
98 [![Documentation Status](https://readthedocs.org/projects/pyric/badge/?version=latest)](http://pyric.readthedocs.io/en/latest/?badge=latest)
3231 handling the complex operations of Netlink seamlessy while maintaining a minimum
3332 of "code walking" to understand, modify and extend. But, why stop there? Since
3433 it's initial inception, PyRIC has grown. PyRIC puts iw, ifconfig, rfkill,
35 udevadm, airmon-ng and macchanger.
34 udevadm, airmon-ng and macchanger in your hands (or your program).
3635
3736 ### a. Additions to iw
3837 Several "extensions" have been added to iw:
4039 their own netlink (or ioctl socket) to pyw functions;
4140 * One-time request for the nl80211 family id: pyw stores the family id in a
4241 global variable
43 * Consolidating different "reference" values to wireless NICs in one class
42 * Consolidate different "reference" values to wireless NICs in one class
4443 (Cards are tuples t=(dev,phy #,ifindex)
4544
4645 These are minimal changes but they can improve the performance of any progams
6160 halved.
6261
6362 ### b. Current State
63 PyRIC is in the process of porting compatibility to Python 3. At present, it will
64 work on Python 2.7 and Python 3.5. It will also work on Python 3.0 except you
65 will have to manually enter your devices in the examples (as argparse is not
66 supported) and you will not be able to run pyw.unittest.py.
67
6468 ATT, PyRIC provides the following:
6569 * enumerate interfaces and wireless interfaces
6670 * identify a cards driver, chipset and manufacturer
158162 those impatient types:
159163
160164 ```python
161 import pyric # pyric errors
162 from pyric import pyw # iw functionality
165 import pyric # pyric errors
166 import pyric.pyw as pyw # iw functionality
163167 ```
164168
165169 will import the basic requirements and unless otherwise stated is assumed for the
227231 Card(phy=0,dev='wlan0',ifindex=2)
228232 ```
229233
230 There are other methods to get a Card object: pyw.devinfo, in addition to
231 information, will return a Card object, pyw.devadd returns a card object for the
232 newly created virtual interface and pyw.ifaces returns a lists of Cards for every
233 interface sharing the same phy.
234 There are other methods to get a Card object:
235 * pyw.devinfo, in addition to information, will return a Card object,
236 * pyw.devadd and pyw.phyadd return a card object for the newly created virtual
237 interface, and
238 * pyw.ifaces returns a lists of Cards for every interface sharing the same phy.
239
240 It is also important to note while most functions require a Card object, some
241 do not and some will take a Card or a specific identifier. Read the user
242 guide or code for additional information.
234243
235244 Before continuing you may find that a Card can become invalid. For example, I
236245 have an older system where the USB tends to fall out. You can confirm that your
314323
315324 For a brief description of coverage class and retry limits,
316325 see http://www.computerhope.com/unix/iwconfig.htm. For a description of the RTS
317 and Fragmentation thresholds see http://resources.infosecinstitute.com/rts-threshold-configuration-improved-wireless-network-performance/
326 and Fragmentation thresholds see http://resources.infosecinstitute.com/rts-threshold-configuration-improved-wireless-network-performance/.
327 The IEEE 802.11-2012 also covers these.
318328
319329 #### iv. Getting Info On Your Card
320330
414424 Card(phy=0,dev=mon0,ifindex=4)
415425 >>> pyw.winterfaces()
416426 ['mon0', 'wlan0']
417 >>> for iface in pyw.ifaces(w0): # delete all interfaces
418 ... print iface
419 ... if not iface[0].dev == m0.dev: # that are not our monitor
420 ... pyw.devdel(iface[0]) # on the this phy
427 >>> for card,_ in pyw.ifaces(w0): # delete all interfaces
428 ... print card
429 ... if not card.dev == m0.dev: # that are not our monitor
430 ... pyw.devdel(card) # on the this phy
421431 ...
422432 (Card(phy=0,dev=mon0,ifindex=4), 'monitor')
423433 (Card(phy=0,dev=wlan0,ifindex=3), 'managed')
463473 >>> pyw.chset(w1, 1, None)
464474 ```
465475
466 The above commands execute the same internal commands as does airmon-ng.
467 To verify, open a command prompt and execute the following:
476 The above commands replicate the behaviour of airmon-ng. To verify, open a
477 command prompt and execute the following:
468478
469479 ```bash
470480 ?> iw dev wlan0 info # replace wlan0 with your nic
512522
513523 ```python
514524 import pyric
515 from pyric import pyw
516 from pyric.lib import libnl as nl
525 import pyric.pyw as pyw
526 import pyric.lib.libnl as nl
517527
518528 def pymon(card, start=True, ch=None):
519529 """
528538 if pyw.modeget(card) == 'monitor':
529539 raise RuntimeError("Card is already in monitor mode")
530540 newcard = pyw.devset(card, card.dev + 'mon')
531 pyw.modeset(newcard, 'monitor')
532 if ch: pyw.chset(w1, ch, None)
541 pyw.modeset(newcard, 'monitor')
533542 pyw.up(newcard)
543 if ch: pyw.chset(w1, ch, None)
534544 else:
535545 if pyw.modeget(card) == 'managed':
536546 raise RuntimeError("Card is not in monitor mode")
537 newcard = pyw.devset(card, card.dev[:-3)
547 newcard = pyw.devset(card, card.dev[:-3])
538548 pyw.modeset(newcard, 'managed')
539549 pyw.up(newcard)
540550 return newcard
541551 ```
542552
553 ##### o Virtual Interfaces and Issues in Kernel 4.x
554 After recently upgrading my distro, my kernel was upgraded from 3.x to 4.x. I
555 noticed that in some situations, adding a virtual interface (VIF) did not have
556 the desired effect. Namely, new VIFs did not have the dev name I had specified.
557 Furthermore, regardless of the naming convention I was currently using (old
558 school like wlan0, eth0 etc or the newer predictable names i.e. wlp3s0) the
559 new VIF would have a predictable name and the MAC address would be one up from
560 that of the actual cards MAC address. For more details, check out my blog
561 at https://wraithwireless.wordpress.com/2016/07/24/linux-kernel-bug/. This is
562 an issue at the kernel and nl80211 level and not a PyRIC bug.
563
564 This situtation will only occur if you are attempting to (a) create a VIF with
565 the same dev name as the original, (b) in managed mode and (c) there are currently
566 other VIFs sharing the same phy.
567
568 ```python
569 >>> pyw.winterfaces()
570 ['alfa0']
571 >>> card = pyw.getcard('alfa0')
572 >>> card
573 Card(phy=1,dev=alfa0,ifindex=5)
574 >>> mcard
575 Card(phy=1,dev=mon0,ifindex=6)
576 >>> pyw.devdel(card)
577 >>> pyw.winterfaces()
578 ['mon0']
579 >>> pyw.devadd(mcard,'alfa0','managed')
580 Card(phy=1,dev=alfa0,ifindex=7)
581 >>> pyw.winterfaces()
582 ['mon0', 'wlx00c0ca59afa7']
583 >>> pyw.devdel(pyw.getcard('wlx00c0ca59afa7'))
584 >>> pyw.winterfaces()
585 ['wlan0mon', 'mon0']
586 >>> pyw.phyadd(mcard,'alfa0','managed')
587 Card(phy=1,dev=alfa0,ifindex=8)
588 >>> pyw.winterfaces()
589 ['wlan0mon', 'mon0', 'wlx00c0ca59afa7']
590 ```
591
592 All three of the above most be True for this to occur. So, for example:
593
594 ```python
595 >>> pyw.winterfaces()
596 ['mon0']
597 >>> pyw.devadd(mcard,'alfa0','monitor')
598 Card(phy=1,dev=alfa0,ifindex=10)
599 >>> pyw.winterfaces()
600 ['mon0', 'alfa0']
601 ```
602
603 works because case (b) is false.
604
605 Some things to note:
606 * it does not matter if you are using devadd (creating a VIF via the ifindex) or
607 phyadd (creating a VIF via the physical index)
608 * nl80211 believes that new VIF has the name you specified so I believe this is
609 something related to the kernel itself or possibly udev. If you look at the source
610 code for phyadd or devadd, the returned card uses the indicators returned by the
611 kernel.
612
613 I had considered several options of rectifying this for PyRIC but, doing so would
614 require either mutliple checks on kernel version or breaking backward compatibility
615 for users with kernel 3.x and possibly breaking forward compatibility (if this
616 issue does get fixed at some future kernel version). Besides, being aware of
617 the state that must be true for this to happen, users can easily workaround it.
618
619 One way, as we saw earlier, is to create a VIF in monitor mode and then set it
620 to managed.
621
622 ```python
623 >>> pyw.winterfaces()
624 ['mon0']
625 >>> pyw.devadd(mcard,'alfa0','monitor')
626 Card(phy=1,dev=alfa0,ifindex=10)
627 >>> pyw.winterfaces()
628 ['mon0', 'alfa0']
629 >>> pyw.devdel(pyw.getcard('mon0'))
630 >>> card = pyw.getcard('alfa0')
631 >>> pyw.down(card)
632 >>> pyw.modeset(card,'managed')
633 >>> pyw.up
634 <function up at 0x7f76339c99b0>
635 >>> pyw.up()
636 Traceback (most recent call last):
637 File "<stdin>", line 1, in <module>
638 TypeError: up() takes at least 1 argument (0 given)
639 >>> pyw.up(card)
640 >>> pyw.winterfaces()
641 ['wlan0mon', 'alfa0']
642 >>> pyw.devinfo(card)
643 {'wdev': 4294967302, 'RF': None, 'CF': None, 'mac': '00:c0:ca:59:af:a6',
644 'mode': 'managed', 'CHW': None, 'card': Card(phy=1,dev=alfa0,ifindex=10)}
645 ```
646
647 But, I think this is sloppy. The better way is to use phyadd. Recall that
648 phyadd accepts either a Card or the phy and that even though a card is deleted,
649 some of its reference values are still valid. In the case of deleting a card,
650 the phy is still present. So, you could use a phy or a Card that was previously
651 deleted because the phy is still valid.
652
653 ```python
654 >>> pyw.winterfaces()
655 ['mon0']
656 >>> phy = mcard.phy
657 >>> pyw.devdel(mcard)
658 >>> pyw.winterfaces()
659 []
660 >>> card = pyw.phyadd(phy,'alfa0','managed')
661 >>> card
662 Card(phy=1,dev=alfa0,ifindex=12)
663 >>> pyw.winterfaces()
664 ['alfa0']
665 ```
666
667 This works, but remember you have to delete all interfaces with the same phy
668 as the one you are creating before creating it.
669
543670 #### vi. STA Related Functions
544 I have recently begun adding STA functionality to PyRIC. These are not
545 necessarily required for a pentester, although the ability to disconnect
546 a Card may come in handy. The difficulty is that iw only provides connect
547 functionality through Open or WEP enabled APs which means that I am
548 attempting to determine which commands and attributes are required. If all
549 else fails I will look to wpa_supplicant for more information. ATT two
550 two functions related to STA->AP exist: a) determine if the Card is connected
551 and b) disconnect the Card
671 I have recently begun adding STA functionality to PyRIC. These are not necessarily
672 required for a pentester, although the ability to disconnect a Card may come in
673 handy. The difficulty is that iw only provides connect functionality through Open
674 or WEP enabled APs which means that I am attempting to determine which commands
675 and attributes are required. If all else fails I will look to wpa_supplicant for
676 more information. Additionally, iw will not connect if wpa_supplicant is running.
552677
553678 ```python
554679 >>> pyw.isconnected(w0)
637762 off soft blocks.
638763
639764 ``` python
640 from pyric.utils import rfkill
765 import pyric.utils.rfkill as rfkill
641766
642767 rfkill.rfkill_list() # list rfkill devices
643768 => {'tpacpi_bluetooth_sw': {'soft': True, 'hard': False, 'type': 'bluetooth', 'idx': 1},
691816 - \_\_init\_\_.py initialize distrubution PyRIC module
692817 - examples example folder
693818 + pentest.py create wireless pentest environment example
694 + device_details.py display device information
819 + info.py display device information
695820 - tests (-) test folder
696821 + pyw.unittest.py unit test for pyw functions
697822 - docs User Guide resources
698823 + nlsend.png (-) image for user guide
699824 + nlsock.png (-) image for user guide
825 + logo.png (-) pyric logo
700826 + PyRIC.tex (-) User tex file
701827 + PyRIC.bib (-) User Guide bibliography
702828 + PyRIC.pdf User Guide
705831 - MANIFEST.in used by setup.py
706832 - README.md this file
707833 - LICENSE GPLv3 License
834 - CHANGES revision file
708835 - TODO todos for PyRIC
709836 - pyric package directory
710837 + \_\_init\_\_.py initialize pyric module
729856 - nl80211_h.py nl80211 constants
730857 - nl80211_c.py nl80211 attribute policies
731858 - rfkill_h.py rfkill header file
732 - ieee80211_h.py ieee80211.h port (subset of)
859 - wlan.py ieee80211.h port (subset of)
733860 + lib library subpackages
734861 * \_\_init\_\_.py initialize lib subpackage
735862 * libnl.py netlink helper functions
736863 * libio.py sockios helper functions
737864 + nlhelp netlinke documentation/help
865 * \_\_init\_\_.py initialize nlhelp subpackage
738866 * nsearch.py nl80211 search
739867 * commands.help nl80211 commands help data
740868 * attributes.help nl80211 attributes help data
+13
-32
TODO less more
11 o ethtool. uses ioctl but does not follow same pattern as ifconfig seems
22 to use
33 - ethtool -i <dev> gives driver information including firmware-version
4 - ethtool -S <dev> gives some statistics on rx/tx
5 and udevadm (does what hardware.py does)
4 and udevadm (does what hardware.py does)
65 11) tried NL80211_CMD_GET_WIPHY, setting _WIPHY_TX_POWER_LEVEL but did
76 not return the current power level - currently cannot find anything in nl80211.h
87 that could be used to get tx power
1514 o slackware
1615 o dd-wrt/OpenWRT
1716 21) look at NL80211_CMD_START_AP - no need to try and recreate the wheel by
18 replicate hostap but could be useful
19 22) txset
20 o NOTE: the following is consistent with what iw gives us
21 o when using dBm
22 - get Operation not supported for setting tx power (see pyw.txset)
23 - have tried using the ifindex and phy. Both methods are accepted, returning
24 only Errno 95.
25 o when using mBm
26 - no errors reported but tx power is not changed
27 o Is the operation not supported by my cards? or is it not supported by the
28 kernel?
29 26) need to parse dumps NLM_F_DUMP, for now we're good with link etc, so long
30 as the card is connected but it may come up eventually
31 29) figure out how to parse the information element in pyw.link - there's some
32 good shit in it including sometimes the router os and type
33 31) add VHT processing to sta_info bitrate
34 35) iw connect (on open) returns status of successful connect but card is
35 not connected -> move to wpa_supplicant to see how they do it
36 36) do we need to write a find nested attribute? so we don't need to go iterate
37 a list of attributes to find one
38 39) parsing wiphy_bands
39 o _HT_MCS_SET: a 16-bit attr containing the MCS set as defined in 802.11n (find this)
40 o _HT_CAPA: as in the HT information IE
41 42) is there a simple way to set the format strings as constants keeping in
42 mind that things like strings require a length in the format string
43 45) find out if some the 'flags' for bands are actually supported such as
44 HT40+ which should be disabled for channel 11
45 46) max-tx for bands is showing 15 when iwconfig shows 30
46 47) in link, NL80211_BSS_BEACON_IES vs NL80211_BSS_INFORMATION_ELEMENT
47 BEACON_IES may not always be present
17 replicating hostap but could be useful
18 26) need to parse dumps (NLM_F_DUMP), for now we're good with link etc, so long
19 as the card is connected but it may come up eventually especially if we want
20 to add scan results
21 29) figure out how to parse the information element in pyw.link - sometimes
22 the router os and type are included
23 o in link, NL80211_BSS_BEACON_IES vs NL80211_BSS_INFORMATION_ELEMENT
24 BEACON_IES may not always be present but appears to contain more
25 31) add VHT processing to sta_info bitrate
26 39) parsing wiphy_bands (should we add the below?)
27 o _HT_MCS_SET: a 16-bit attr containing the MCS set as defined in 802.11n
28 o _HT_CAPA: as in the HT information IE
00 # PyRIC root Distribution directory
11 # Do not import from this directory i.e from PyRIC import foobar
2 # use pip ('sudo pip install PyRIC') or download latest tarbal to
3 # install. Then execute from pyric import foobar
2 # To install
3 # use pip ('sudo pip install PyRIC')
4 # or download latest tarbal and untar.
5 # excute either sudo python setup.py or rund from the PyRIC/pyric directory
Binary diff not shown
1818 %
1919 % __name__ = 'User Guide'
2020 %__license__ = 'GPLv3'
21 %__version__ = '0.0.4'
22 %__date__ = 'July 2016'
21 %__version__ = '0.0.6'
22 %__date__ = 'August 2016'
2323 %__author__ = 'Dale Patterson'
2424 %__maintainer__ = 'Dale Patterson'
2525 %__email__ = '[email protected]'
7272 basicstyle=\footnotesize
7373 }
7474
75 \title{\includegraphics[scale=1]{logo}\\ PyRIC v0.1.5: User Manual}
75 \title{\includegraphics[scale=1]{logo}\\ PyRIC v0.1.6: User Manual}
7676 \author{Dale V. Patterson\\ [email protected]}
7777
7878 \begin{document}
8686 have increased dramatically in recent years. However, these tools still rely on
8787 Linux command lines tools to setup and prepare and restore the system for use.
8888 Until now. Why use subprocess.Popen, regular expressions and str.find to interact
89 with your wireless cards? PyRIC is:
89 with your wireless cards? PyRIC puts iw, ifconfig, rfkill, udevadm, airmon-ng and
90 macchanger in your hands (or your program). \\
91
92 PyRIC is designed with Python 2.7 in mind but has now been made compatible with
93 Python 3.5. It will also work on Python 3.0 but you will have to hard code the
94 command line options in the two examples as Python 3.0 does not include the module
95 argparse
96
97 PyRIC is:
9098 \begin{enumerate}
9199 \item \textbf{Pythonic}: No ctypes, SWIG etc. PyRIC redefines C header files as
92100 Python and uses sockets to communicate with kernel.
111119 While users can utilize libnl.py to communicate directly with the kernel, the
112120 true utility of PyRIC is pyw.py. Like iw, pyw provides an interface/buffer
113121 between the caller and the kernel, handling all message construction, parsing
114 and transfer transparently and without requiring any Netlink knowledge or
122 and data transfer transparently and without requiring any Netlink knowledge or
115123 experience. \\
116124
117 PyRIC does more though: it implements rfkill, allowing users to list, block and
118 unblock devices and implements a subset of ifconfig providing users the ability
119 to turn cards on/off and set mac and ip addresses. \\
120
121 At this time, PyRIC (through pyw, rfkill and device) can:
125 At this time, PyRIC can:
122126 \begin{itemize}
123127 \item enumerate interfaces and wireless interfaces,
128 \item identify a cards driver, chipset and manufacturer,
129 \item get/set hardware address,
130 \item get/set ip4 address, netmask and or broadcast,
131 \item turn card on/off,
132 \item get supported standards, commands or modes,
133 \item get if info,
134 \item get dev info,
135 \item get phy info,
136 \item get link info,
137 \item get STA (connected AP) info,
124138 \item get/set regulatory domain,
125 \item get/set hw address,
126 \item get/set ip4, netmask and broadcast address
127 \item identify a radio's chipset and driver,
128 \item turn device on/off,
129 \item get supported standards,
130 \item get supported commands,
131 \item get supported modes,
132 \item get dev/phy info on device,
133139 \item get/set mode,
134 \item add/delete interfaces, and
135 \item block/unblock devices through rfkill.
136 \end{itemize}
137 And, through libnl.py users can extend the above functionality by creating
138 additional commands.\\
140 \item get/set coverage class, RTS threshold, Fragmentation threshold and retry
141 limits,
142 \item add/delete interfaces,
143 \item determine if a card is connected,
144 \item get link info for a connected card,
145 \item enumerate ISM and UNII channels,
146 \item block/unblock rfkill devices.
147 \end{itemize}
148 And, through libnl.py and libio.py, users can extend the above functionality by
149 creating additional commands.
139150
140151 \subsection{Background}
141152 PyRIC arose out of a need in Wraith (https://github.com/wraith-wireless/wraith)
184195 A Card is merely a wrapper around a tuple t = (phy index,device name,ifindex).
185196 Since the underlying Netlink calls sometimes require the physical index, sometimes
186197 the device name, and sometimes the ifindex, pyw functions\footnote{Not all functions
187 accept a Card, devinfo() will accept either a Card or a dev and devadd will accept
188 either a Card or a physical index} take a Card object which doesn't require callers
189 to know which identifier to use for each function. There are four primary methods
190 to creating a Card:
198 accept only a Card, devinfo() accepts either a Card or a dev, devadd accepts either a
199 Card or a ifindex and phyadd accepts only a physical index} take a Card object which
200 doesn't require callers to know which identifier to use for each function. There are
201 four primary methods to creating a Card:
191202 \begin{enumerate}
192203 \item \textbf{pyw.getcard} returns a Card object from a given dev,
193204 \item \textbf{pyw.devinfo} returns the dict info where info['card'] is the Card
194 object. This function will take either a card or a dev
195 \item \textbf{pyw.devadd} returns a new Card object,
205 object. (This function will take either a card or a ifindex),
206 \item \textbf{pyw.devadd} returns a new Card object (this function will only take
207 a phy),
196208 \item \textbf{pyw.ifaces} returns a list of tuples t = (Card,mode) sharing the
197209 same phy as a given dev.
198210 \end{enumerate}
316328 language=Python]
317329 1: import pyric # pyric error (and ecode EUNDEF)
318330 2: from pyric import pyw # for iw functionality
319 3: import pyric.utils.hardware as hw # for chipset/driver
320 4: from pyric.utils.channels import rf2ch # rf to channel conversion
321 5:
322 6: dev = 'wlan0'
323 7: ifaces = pyw.interfaces()
324 8: wifaces = pyw.winterfaces()
325 9: if dev not in ifaces:
326 10: print "Device {0} is not valid, use one of {1}".format(dev,ifaces)
327 11: return
328 12: elif dev not in wifaces:
329 13: print "Device {0} is not wireless, use one of {1}".format(dev,wifaces)
330 14:
331 15: print "Regulatory Domain currently: ", pyw.regget()
332 16: dinfo = pyw.devinfo(dev)
333 17: card = dinfo['card']
334 18: pinfo = pyw.phyinfo(card)
335 19: driver = hw.ifdriver(card.dev)
336 20: chipset = hw.ifchipset(driver)
337 21:
338 22: pyw.down(card)
339 23: pyw.macset(card,'00:03:93:57:54:46')
340 24:
341 25: msg = "Using {0} currently in mode: {1}\n".format(card,dinfo['mode'])
342 26: msg += "\tDriver: {0} Chipset: {1}\n".format(driver,chipset)
343 27: if dinfo['mode'] == 'managed':
344 28: msg += "\ton channel {0} width {1}\n".format(rf2ch(dinfo['RF']),
345 29: dinfo['CHW'])
346 30: msg += "\tSupports modes {0}\n".format(pinfo['modes'])
347 31: msg += "\tSupports commands {0}".format(pinfo['commands'])
348 32: msg += "\thw addr {0}".format(pyw.macget(card))
349 33: print msg
350 34:
351 35: pdev = 'pent0'
352 36: for iface in pyw.ifaces(card):
353 37: pyw.devdel(iface[0])
354 38: pcard = pyw.devadd(card, pdev, 'monitor')
355 39: pyw.up(pcard)
356 40: pyw.chset(pcard,6,None)
357 41:
358 42: # DO STUFF HERE
359 43:
360 44: pyw.devdel(pcard)
361 45:
362 46: card = pyw.devadd(card,card.dev,dinfo['mode'])
363 47: pyw.macset(card,dinfo['mac'])
364 48: pyw.up(card)
331 3: from pyric.utils.channels import rf2ch # rf to channel conversion
332 4:
333 5: dev = 'wlan0'
334 6: dinfo = pyw.devinfo(dev)
335 7: card = dinfo['card']
336 8:
337 9: pyw.down(card)
338 10: pyw.macset(card,'00:03:93:57:54:46')
339 11:
340 12: pdev = 'pent0'
341 13: pcard = pyw.devadd(card, pdev, 'monitor')
342 14: for iface in pyw.ifaces(card):
343 15: if iface[0].dev != pcard.dev:
344 16: pyw.devdel(iface[0])
345 17: pyw.up(pcard)
346 18:
347 19: pyw.chset(pcard,6,None)
348 20:
349 21: # DO stuff here
350 22:
351 23: card = pyw.devadd(pcard,card.dev,dinfo['mode'])
352 24: pyw.devdel(pcard)
353 25: pyw.macset(card,dinfo['mac'])
354 26: pyw.up(card)
365355 \end{lstlisting}
366356
367 Listing \ref{lst:pentest} attempts to show most of the available pyw functions
368 in use and is the basic shell used in another project, Wraith\cite{wraith}, to
369 instantiate a wireless (802.11) sensor - (for a full listing of all pyw functions
370 see Appendix \ref{sec:pywapi}) - with scanning capabilities. Lines 1 and 2 should
371 always be included as they import the pyric error and pyw functions. Line 3
372 imports hardware which provides the ifchipset and ifdriver functions and Line 4
373 imports the rf2ch conversion function. \\
374
375 In lines 6 through 13, the device wlan0 is confirmed wireless and lines 16 through
376 20 a Card object for 'wlan0' is created and details about the interface are printed.
377 Next, the mac address of wlan0 is changed on lines 23. Note, the device is brought
378 down first. \\
379
380 More information on the device is printed in lines 25 through 33. Starting on
381 line 35, a device named 'pent0' is created in monitor mode. First in lines 36
382 and 37, all interfaces on the same phy are deleted \footnote{we have found that
383 it is better to delete all interfaces on the same phy ensuring that external
384 processes don't interfere with the new device} before creating the new device,
385 bringing the card up and setting it to channel 6 NOHT.\\
386
387 Restoring the device starts on line 45, where the virtual interface is deleted,
388 the previous interface is restored and the mac address is reset.
357 Listing \ref{lst:pentest} shows basic pyw functions and is the basic shell used in
358 another project, Wraith\cite{wraith}, to instantiate a wireless (802.11) sensor -
359 (for a full listing of all pyw functions see Appendix \ref{sec:pywapi}) - with
360 scanning capabilities. \\
361
362 Lines 1 and 2 should always be included as they import the pyric error and pyw
363 functions. Line 3 imports the rf2ch conversion function. \\
364
365 In lines 5 through 10, a Card is created from the device wlan0. The info dict is save
366 IOT to restore later. Next, the mac address of wlan0 is changed. Note, the device has
367 to be brought down first. \\
368
369 Starting on line 12, a device named 'pent0' is created in monitor mode. First, a new
370 Card, pcard is create in monitor mode. Then, all interfaces on the same phy are
371 deleted \footnote{we have found that it is better to delete all interfaces on the
372 same phy ensuring that external processes don't interfere with the new device}. The
373 new Card is brought up and set to channel 6 NOHT.\\
374
375 Restoring the device starts on line 23, where the virtual interface is deleted,
376 the previous interface is restored, the mac address is reset and the old Card is
377 brought up. \\
378
379 An extended version of Listing \ref{lst:pentest} can be found in the examples
380 directory.
389381
390382 \subsubsection{One-time vs Persistent Sockets}
391383 The example in Listing \ref{lst:pentest} uses one-time sockets (netlink and
713705 \item \textbf{pyw.getcard} returns a Card object from a given dev
714706 \item \textbf{pyw.devinfo} returns the dict info where info['card'] is the Card
715707 object. This function will take either a card or a dev
708 \item \textbf{pyw.devadd} returns a new Card object
716709 \item \textbf{pyw.devadd} returns a new Card object
717710 \item \textbf{pyw.ifaces} returns a list of tuples t = (Card,mode) sharing the
718711 same phy as a given device to do so. It is also recommended to periodically
760753 \item retryshortget(card,[nlsock]) (iw phy card.<phy> info | grep 'retry short')
761754 type:netlink get card's retry short limit
762755 \item retryshortset(card,lim,[nlsock]) (iw phy card.<phy> set retry short <lim>)
763 type:netlink set card's retry short limit
756 type:netlink set card's retry short limit. NOTE: although 255 is specified as the
757 max limit for this and the long retry, kernel v4 will not allow it.
764758 \item retrylongget(card,[nlsock]) (iw phy card.<phy> info | grep 'retry long')
765759 type:netlink get card's retry long limit
766760 \item retrylongset(card,lim,[nlsock]) (iw phy card.<phy> set retry long <lim>)
806800 netlink,sets the tx power to pwr (in dBm) with level setting lvl
807801 \item txget(card,[iosock]): (iwconfig card.<dev> | grep Tx-Power card), type:
808802 ioctl, get card's transmission power
809 \item chget(card,[nlsock]): (iw dev <card.dev> info | grep channelS), type:
810 netlink, get card's current channel (only works for cards in mode managed)
803 \item chget(card,[nlsock]): (iw dev <card.dev> info | grep channel), type:
804 netlink, get card's current channel
811805 \item chset(card,ch,chw,[nlsock]): iw phy <card.phy> set channel <ch> <chw>),
812806 type: netlink, set card's current channel to ch with width chw
807 \item freqget(card,[nlsock]): (iw dev <card.dev> info | grep channel), type:
808 netlink, get card's current frequency
813809 \item freqset(card,rf,chw,[nlsock]): iw phy <card.phy> set freq <rf> <chw>),
814810 type: netlink, set card's current frequency to rf with width chw
815811 \item devmodes(card,[iosock]): (iw phy card.<phy>), type: netlink, get modes
819815 \item modeget(card[nlsock]): (iw dev card.<dev> info | grep mode), type: netlink,
820816 get card's mode
821817 \item devset(card,ndev,[nlsock]): (N/A) sets the dev (name) of card to ndev
822 \item devadd(card,vnic,mode,[flags],[nlsock]): (iw phy card.<phy> interface add
823 <vnic> type <mode> flags <flags>), type: netlink, creates a new virtual interface
824 on card's phy with dev vdev, in mode and using flags. Note: flags are only supported
825 in when creating a monitor mode
818 \item phyadd(phy,vnic,mode,[flags],[nlsock]): (iw phy <phy> interface add <vnic>
819 type <mode> flags <flags>)\footnote{There is a bug in some kernel v4.4.0-x
820 where the given dev name is ignored and a system chosen one is used instead. See
821 https://wraithwireless.wordpress.com. Whenever possible, use devadd to create
822 interfaces instead.}, type: netlink, creates a new virtual interface with dev vdev,
823 in mode and using flags. Note: flags are only supported when creating a monitor mode
824 \item devadd(card (or ifindex),vnic,mode,[flags],[nlsock]): (iw phy card.<dev>
825 interface add <vnic> type <mode> flags <flags>), type: netlink, creates a new virtual
826 interface with dev vdev, in mode and using flags. Note: flags are only supported
827 when creating a monitor mode. This function accepts either a Card object or a
828 ifindex.
826829 \item devdel(card,[nlsock]): (iw card.<dev> del), type: netlink, deletes card
827830 \begin{itemize}
828831 \item isconnected(card, [nlsock]): (iw dev card.<dev> info | grep channel), type:
829832 netlink, determines if card is connected
833 \item connect(card, ssid, bssid, rf, [nlsock]): (iw dev card.<dev> connect <ssid>
834 <rf> <bssid>) connects to AP SSID with BSSID
830835 \item disconnect(card, [nlsock]): (iw dev card.<dev> disconnect), type: netlink,
831836 disconnects card from AP
832837 \item link(card, [nlsock]): (iw dev card.<dev> link), type: netlink, displays
11161121 \end{enumerate}
11171122
11181123 \section{Copyright and License}\label{sec:copy}
1119 PYRIC: Python Radio Interface Controller v0.1.5\\
1124 PYRIC: Python Radio Interface Controller v0.1.6\\
11201125
11211126 Copyright (C) 2016 Dale V. Patterson ([email protected])\\
11221127
44
55 """
66
7 import argparse as ap
8 import sys
7 from __future__ import print_function # python 2to3 compability
8 import argparse as ap # cli arg parsing
9 import sys # cli exiting
910 import pyric # pyric error (and ecode EUNDEF)
10 from pyric import pyw # for iw functionality
11 import pyric.pyw as pyw # for iw functionality
1112 from pyric.utils.channels import rf2ch # rf to channel conversion
1213
1314 def execute(dev,itype):
1415 # ensure dev is a wireless interfaces
1516 wifaces = pyw.winterfaces()
1617 if dev not in wifaces:
17 print "Device {0} is not wireless, use one of {1}".format(dev,wifaces)
18 print("Device {0} is not wireless, use one of {1}".format(dev,wifaces))
1819
1920 # get info dicts
2021 dinfo = pyw.devinfo(dev)
3031 msg += "\tInet: {0} Bcast: {1} Mask: {2}\n".format(iinfo['inet'],
3132 iinfo['bcast'],
3233 iinfo['mask'])
33 print msg
34 print(msg)
3435
3536 if itype == 'all' or itype == 'dev':
3637 msg = "Device {0}\n".format(card.dev)
4546 dinfo['RF'],
4647 dinfo['CHW'],
4748 dinfo['CF'])
48 print msg
49 print(msg)
4950
5051 if itype == 'all' or itype == 'phy':
5152 msg = "Wiphy phy{0}\n".format(card.phy)
7778 msg += " (disabled)\n"
7879 else:
7980 msg += "\n"
80 print msg
81 print(msg)
8182
8283 if __name__ == '__main__':
8384 # create arg parser and parse command line args
84 print "Wireless Device Info Display using PyRIC v{0}".format(pyric.__version__)
85 print("Wireless Device Info Display using PyRIC v{0}".format(pyric.version))
8586 argp = ap.ArgumentParser(description="Wireless Device Data")
8687 argp.add_argument('-d','--dev',help="Wireless Device")
8788 argp.add_argument('-t','--type',help="Info type one of {all|if|dev|phy}")
8889 args = argp.parse_args()
90 usage = "usage: python info.py -d <dev> [-t one of {all|if|dev|phy}]"
8991 try:
9092 dname = args.dev
9193 infotype = args.type
9294 if dname is None:
93 print "usage: python info.py -d <dev> [-t one of {all|if|dev|phy}]"
95 print(usage)
9496 sys.exit(0)
9597 if infotype is None: infotype = 'all'
9698 if infotype not in ['all','if','dev','phy']:
97 print "usage: python info.py -d <dev> [-t one of {all|if|dev|phy}]"
99 print(usage)
98100 sys.exit(0)
99101 execute(dname,infotype)
100102 except pyric.error as e:
101 print e
103 print(e)
44
55 """
66
7 import argparse as ap
8 import time
7 from __future__ import print_function # python 2to3 compability
8 import argparse as ap # cli arg. parsing
9 import time # sleeping
10 import sys # cli exiting
911 import pyric # pyric error (and ecode EUNDEF)
10 from pyric import pyw # for iw functionality
12 import pyric.pyw as pyw # for iw functionality
1113 import pyric.utils.hardware as hw # for chipset/driver
1214 from pyric.utils.channels import rf2ch # rf to channel conversion
1315
1416 def execute(dev):
15 print 'Setting up...'
17 print('Setting up...')
1618 # ensure dev is a wireless interfaces
1719 ifaces = pyw.interfaces()
1820 wifaces = pyw.winterfaces()
1921 if dev not in ifaces:
20 print "Device {0} is not valid, use one of {1}".format(dev,ifaces)
22 print("Device {0} is not valid, use one of {1}".format(dev,ifaces))
2123 return
2224 elif dev not in wifaces:
23 print "Device {0} is not wireless, use one of {1}".format(dev,wifaces)
25 print("Device {0} is not wireless, use one of {1}".format(dev,wifaces))
2426
2527 # get a Card & info for dev
26 print "Regulatory Domain currently: ", pyw.regget()
28 print("Regulatory Domain currently: ", pyw.regget())
2729 dinfo = pyw.devinfo(dev)
2830 card = dinfo['card']
2931 pinfo = pyw.phyinfo(card)
4345 msg += "\tSupports modes {0}\n".format(pinfo['modes'])
4446 msg += "\tSupports commands {0}".format(pinfo['commands'])
4547 msg += "\thw addr {0}".format(pyw.macget(card))
46 print msg
48 print(msg)
4749
4850 # prepare a virtual interface named pent0 in monitor mode
4951 # delete all ifaces on the phy to avoid interference
50 print 'Preparing pent0 for monitor mode'
52 # bring the card up when down
53 print('Preparing pent0 for monitor mode')
5154 pdev = 'pent0'
55 pcard = pyw.devadd(card, pdev, 'monitor')
5256 for iface in pyw.ifaces(card):
53 print "deleting {0} in mode {1}".format(iface[0],iface[1])
57 if iface[0].dev != pcard.dev:
58 print("deleting {0} in mode {1}".format(iface[0],iface[1]))
5459 pyw.devdel(iface[0])
60 pyw.up(pcard)
61 print("Using", pcard)
5562
56 # not we use the card that was deleted here. We can do this because
57 # devadd uses the physical index so even though the ifindex and dev are
58 # no longer valid, the physical index still is
59 pcard = pyw.devadd(card, pdev, 'monitor')
60 pyw.up(pcard)
61 print "Using", pcard
62
63 print "Setting channel to 6 NOHT"
63 print("Setting channel to 6 NOHT")
6464 pyw.chset(pcard,6,None)
6565 msg = "Virtual interface {0} in monitor mode on ch 6".format(pcard)
66 print msg + ", using hwaddr: {0}".format(pyw.macget(pcard))
66 print(msg + ", using hwaddr: {0}".format(pyw.macget(pcard)))
6767
6868 # DO stuff here
6969 try:
70 print 'Now ready to do stuff'
71 print 'For example, run wireshark to verify card is seeing all packets'
72 print 'Hit Ctrl-C to quit and restore'
70 print('Now ready to do stuff')
71 print('For example, run wireshark to verify card is seeing all packets')
72 print('Hit Ctrl-C to quit and restore')
7373 while True: time.sleep(1)
7474 except KeyboardInterrupt:
7575 pass
7676
7777 # restore original
78 print "Restoring..."
79 print "deleting ", pcard
78 print('Restoring', card, 'mode =', dinfo['mode'], 'mac =', dinfo['mac'])
79 card = pyw.devadd(pcard,card.dev,dinfo['mode'])
80 print('Deleting', pcard)
8081 pyw.devdel(pcard)
81
82 print 'Restoring', card, 'mode =', dinfo['mode'], 'mac =', dinfo['mac']
83 card = pyw.devadd(card,card.dev,dinfo['mode'])
8482 pyw.macset(card,dinfo['mac'])
8583 pyw.up(card)
86 print "card ", card, " restored"
84 print("card ", card, " restored")
8785
8886 if __name__ == '__main__':
8987 # create arg parser and parse command line args
90 print "Wireless Pentest Environment using PyRIC v{0}".format(pyric.version)
88 print("Wireless Pentest Environment using PyRIC v{0}".format(pyric.version))
9189 argp = ap.ArgumentParser(description="Wireless Pentest")
9290 argp.add_argument('-d','--dev',help="Pentesting Wireless Device")
9391 args = argp.parse_args()
9492 try:
9593 dname = args.dev
9694 if dname is None:
97 print "usage: python pentest.py -d <dev>"
95 print("usage: python pentest.py -d <dev>")
96 sys.exit(0)
9897 else:
9998 execute(dname)
10099 except pyric.error as e:
101 print e
100 print(e)
1818 contributors may be used to endorse or promote products derived from this
1919 software without specific prior written permission.
2020
21 Defines the Pyric error class and constants for some errors. All pyric errors
22 will follow the 2-tuple form of EnvironmentError
21 Defines the PyRIC error class and constants for some errors. All pyric errors
22 will follow the 2-tuple form of EnvironmentError. Also defines constansts for
23 PyPI packaging.
24
25 WARNING: DO NOT import *
2326
2427 Requires:
2528 linux (3.x or 4.x kernel)
2629 Python 2.7
2730
28 pyric 0.1.5
31 pyric 0.1.5 through 0.1.6
2932 desc: wireless nic library: wireless radio identification, manipulation, enumeration
33 concentrate on STA/AP related functionality
3034 includes: /nlhelp /lib /net /utils pyw.py
3135 changes:
3236 See CHANGES in top-level directory
33
34
35 WARNING: DO NOT import *
36
3737 """
3838
3939 __name__ = 'pyric'
4040 __license__ = 'GPLv3'
41 __version__ = '0.1.5'
42 __date__ = 'June 2016'
41 __version__ = '0.1.6'
42 __date__ = 'August 2016'
4343 __author__ = 'Dale Patterson'
4444 __maintainer__ = 'Dale Patterson'
4545 __email__ = '[email protected]'
4646 __status__ = 'Production'
4747
48 # define pyric exceptions
49 # all exceptions are tuples t=(error code,error message)
50 # we use error codes defined in errno, adding -1 to define the undefined error
51 # EUNDEF. I don't like importing all from errno but it provides conformity in
52 # error handling i.e modules using pyric.error do not need to call pyric.EUNDEF
53 # and errno.EINVAL but can call pyric.EUNDEF and pyric.EINVAL
54 EUNDEF = -1 # undefined error
55 from errno import * # make all errno errors pyric errors
56 errorcode['EUNDEF'] = -1 # add ours to errorcode dicts
57 class error(EnvironmentError): pass
58 # BELOW IS STILL A WORK IN PRGORESS
48 """
49 define pyric exceptions
50 all exceptions are tuples t=(error code,error message)
51 we use error codes defined in errno, using EUNDEF = -1 to define an undefined
52 error I don't like importing all from errno but it provides conformity in
53 error handling i.e modules using pyric.error do not need to call pyric.EUNDEF
54 and errno.EINVAL but can call pyric.EUNDEF and pyric.EINVAL
55 """
56 EUNDEF = -1 # undefined error
57 from errno import * # make all errno errors pyric errors
58 errorcode[EUNDEF] = "EUNDEF" # add ours to errorcode dicts
59 class error(EnvironmentError):
60 def __init__(self,errno,errmsg=None):
61 if not errmsg: errmsg = strerror(errno)
62 EnvironmentError.__init__(self,errno,errmsg)
63
5964 def strerror(errno):
6065 import os
6166 if errno < 0: return "Undefined error"
6267 elif errno == EPERM: return "Superuser privileges required"
6368 elif errno == EINVAL: return "Invalid parameter"
69 elif errno == EBUSY:
70 msg = "{0}. Make sure Card is up and no other devices share the same phy"
71 return msg.format(os.strerror(EBUSY))
72 elif errno == ENFILE: return "There are no available netlink sockets"
6473 else:
6574 return os.strerror(errno)
6675
6776 # for setup.py use
6877 # redefine version for easier access
6978 version = __version__
79
7080 # define long description
7181 long_desc = """
72 # PyRIC 0.1.4: Python Radio Interface Controller
82 # PyRIC 0.1.6: Python Radio Interface Controller
7383 ## Linux wireless library for the Python Wireless Developer and Pentester
7484
7585 ## DESCRIPTION:
90100 tools. Never worry about newer iw versions and having to rewrite your parsers.
91101 5. Easy: If you can use iw, you can use PyRIC.
92102
93 At it's heart, PyRIC is a Python port of (a subset of) iw and by extension, a
94 Python port of Netlink w.r.t nl80211 functionality. The original goal of PyRIC
95 was to provide a simple interface to the underlying nl80211 kernel support,
96 handling the complex operations of Netlink seamlessy while maintaining a minimum
97 of "code walking" to understand, modify and extend. But, why stop there? Since
98 it's initial inception, PyRIC has grown to include ioctl support to replicate
99 features of ifconfig such as getting or setting the mac address and has recently
100 implemented rkill support to soft block or unblock wireless cards.
101
102103 ## CURRENT STATE
103104 ATT, PyRIC pyw provides the following:
104105 * enumerate interfaces and wireless interfaces
118119 * add/delete interfaces
119120 * enumerate ISM and UNII channels
120121 * block/unblock rfkill devices
122 * check 'connectivity', disconnect from AP
121123
122124 In utils, several helpers can be found that can be used to:
123125 * enumerate channels and frequencies and convert between the two
125127 * fetch and parse the IEEE oui text file
126128 * further rfkill operations to include listing all rfkill devices
127129
128 For a full listing of every function offered by pyw and helpers see the user
129 guide PyRIC.pdf.
130
131 PyRIC also provides limited help functionality concerning nl80211 commands/attributes
132 for those who wish to add additional commands. However, it pulls directly from
133 the comments nl80211 header file and may be vague.
134
135 ## WHAT IS PyRIC?
136 To avoid confusion, PyRIC is the system as a whole, including all header files
137 and "libraries" that are required to communicate with the kernel. pyw is a
138 interface to these libraries providing specific funtions.
139
140 What it does - defines programmatic access to a subset of iw, ifconfig and rkill.
141 In short, PyRIC provides Python wireless pentesters the ability to work with
142 wireless cards directly from Python without having to use command line tools
143 through Popen.
144 """
130 At it's heart, PyRIC is a Python port of (a subset of) iw and by extension, a
131 Python port of Netlink w.r.t nl80211 functionality. The original goal of PyRIC
132 was to provide a simple interface to the underlying nl80211 kernel support,
133 handling the complex operations of Netlink seamlessy while maintaining a minimum
134 of "code walking" to understand, modify and extend. But, why stop there? Since
135 it's initial inception, PyRIC has grown. PyRIC puts iw, ifconfig, rfkill, udevadm,
136 airmon-ng and macchanger in your hands (or your program).
137 """
6363 return ioctl(iosock.fileno(),flag,ifreq)
6464 except (AttributeError,struct.error) as e:
6565 # either sock is not valid or a bad value passed to ifreq
66 if e.message.find('fileno'): raise error(errno.ENOTSOCK,"bad socket")
66 if e.message.find('fileno'): raise error(errno.ENOTSOCK,"Bad socket")
6767 else: raise error(errno.EINVAL,e)
6868 except IOError as e:
6969 # generally device cannot be found sort but can also be
4747 import pyric.net.netlink_h as nlh
4848 import pyric.net.genetlink_h as genlh
4949 from pyric.net.policy import nla_datatype
50 import sys
51 _PY3_ = sys.version_info.major == 3
5052
5153 class error(EnvironmentError): pass
5254
235237 :returns: a GENLMsg received from the socket
236238 """
237239 try:
238 # pull off the message and following ack message NOTE: nlmsg_fromstream
239 # will throw an exception if msg is an ack/nack catch it and test for ack.
240 # If it was an ack, return the success code otherwise, reraise it. If it
241 # wasn't an ack/nack, return the message
240 # we can expect two types of messages 1) an instant success message
241 # or 2) a data message. If it's a data message, we need to catch
242 # the ack
242243 msg = nlmsg_fromstream(sock.recv())
243244 try:
245 # catch the follow on ack
244246 _ = nlmsg_fromstream(sock.recv())
245247 except error as e:
248 # on success, just return the orginal message
246249 if e.errno == nlh.NLE_SUCCESS: pass
247250 else: raise
248 if sock.seq != msg.seq: raise error(errno.EBADMSG,"seq. # out of order")
251 if sock.seq != msg.seq: raise error(errno.EBADMSG,"Seq. # out of order")
249252 return msg
250253 except socket.timeout:
251 raise error(-1,"socket timed out")
252 except socket.error as e:
253 raise error(errno.ENOTSOCK,e)
254 raise error(-1,"Socket timed out")
255 #except socket.error as e: # this became in issue in python 3
256 # raise error(errno.ENOTSOCK,e)
254257 except error as e:
255258 if e.errno == nlh.NLE_SUCCESS: return nlh.NLE_SUCCESS
256259 raise # rethrow
350353
351354 @nltype.setter
352355 def nltype(self,v):
353 if v < 0: raise error(errno.ERANGE,"nltype {0} is invalid".format(v))
356 if v < 0: raise error(errno.ERANGE,"Netlink type {0} is invalid".format(v))
354357 self['type'] = v
355358
356359 @property
364367
365368 @seq.setter
366369 def seq(self,v):
367 if v < 1: raise error(errno.ERANGE,"invalid seq. number")
370 if v < 1: raise error(errno.ERANGE,"Invalid seq. number")
368371 self['seq'] = v
369372
370373 @property
372375
373376 @pid.setter
374377 def pid(self,v):
375 if v < 1: raise error(errno.ERANGE,"invalid port id")
378 if v < 1: raise error(errno.ERANGE,"Invalid port id")
376379 self['pid'] = v
377380
378381 @property
380383
381384 @cmd.setter
382385 def cmd(self,v):
383 if v < 0: raise error(errno.ERANGE,"invalid cmd")
386 if v < 0: raise error(errno.ERANGE,"Invalid cmd")
384387 self['cmd'] = v
385388
386389 @property
397400 for a,v,d in self['attrs']:
398401 try:
399402 payload += _attrpack_(a,v,d)
400 except struct.error as e:
401 if d == nlh.NLA_NESTED: pass # we need to fix here
403 except (TypeError,AttributeError,struct.error) as e:
404 #if d == nlh.NLA_NESTED: pass # we need to fix here
402405 raise error(-1,"Packing {0} {1}: {2}".format(a,v,e))
403406 return nlh.nlmsghdr(len(payload),self.nltype,self.flags,self.seq,self.pid) + payload
404407
440443 raise error(abs(e),strerror(abs(e)))
441444 c,_,_ = struct.unpack_from(genlh.genl_genlmsghdr,stream,nlh.NLMSGHDRLEN)
442445 except struct.error as e:
443 raise error(-1,"error parsing headers: {0}".format(e))
446 raise error(-1,"Error parsing headers: {0}".format(e))
444447
445448 # create a new message with hdr values then parse the attributes
446449 msg = nlmsg_new(t,c,s,p,fs)
474477 # Note: we use unpack_from which will ignore the null bytes in numeric
475478 # datatypes & for strings, strip trailing null bytes
476479 # dt == nlh.NLA_UNSPEC: ignore
480 if _PY3_ and (dt == nlh.NLA_STRING or dt == nlh.NLA_UNSPEC):
481 # python 3 returns a bytes object, convert to string
482 try:
483 a = a.decode('ascii')
484 except UnicodeDecodeError:
485 pass # Fuck You Python 3
477486 if dt == nlh.NLA_STRING: a = _nla_strip_(a)
478487 elif dt == nlh.NLA_U8: a = struct.unpack_from("B",a,0)[0]
479488 elif dt == nlh.NLA_U16: a = struct.unpack_from("H",a,0)[0]
565574 elif etype == nlh.NLA_U32: fmt = "I"
566575 elif etype == nlh.NLA_U64: fmt = "Q"
567576 else:
568 raise error(errno.EINVAL,"set elements are not valid datatype")
577 raise error(errno.EINVAL,"Set elements are not valid datatype")
569578 esize = struct.calcsize(fmt)
570579
571580 ss = []
578587 ss.append(s)
579588 idx += esize
580589 except struct.error:
581 raise error(errno.EINVAL,"set elements failed to unpack")
590 raise error(errno.EINVAL,"Set elements failed to unpack")
582591 return ss
583592
584593 def nla_put(msg,v,a,d):
589598 :param a: attribute type
590599 :param d: attribute datatype
591600 """
592 if d > nlh.NLA_TYPE_MAX: raise error(errno.ERANGE,"value type is invalid")
601 if d > nlh.NLA_TYPE_MAX: raise error(errno.ERANGE,"Value type is invalid")
593602 msg['attrs'].append((a,v,d))
594603
595604 # nla_put_* append data of specified datatype
616625 :param a: attribute type
617626 :param d: attribute datatype
618627 """
619 if d > nlh.NLA_TYPE_MAX: raise error(errno.ERANGE,"invalid datatype")
628 if d > nlh.NLA_TYPE_MAX: raise error(errno.ERANGE,"Invalid datatype")
620629 msg['attrs'][i] = (a,v,d)
621630
622631 def nla_pop(msg,i):
685694 elif d == nlh.NLA_U16: attr = struct.pack("H",v)
686695 elif d == nlh.NLA_U32: attr = struct.pack("I",v)
687696 elif d == nlh.NLA_U64: attr = struct.pack("Q",v)
688 elif d == nlh.NLA_STRING: attr = struct.pack("{0}sx".format(len(v)),v)
697 elif d == nlh.NLA_STRING:
698 if _PY3_: v = bytes(v,'ascii')
699 attr = struct.pack("{0}sx".format(len(v)),v)
689700 elif d == nlh.NLA_FLAG: attr = '' # a 0 sized attribute
690701 elif d == nlh.NLA_MSECS: attr = struct.pack("Q",v)
691702 elif d == nlh.NLA_NESTED:
692703 # assumes a single layer of nesting
693704 for nested in v:
694 # prepend the packed index to the already packed attribute
695 # the align it
705 # prepend packed index to the already packed attribute & align it
696706 nattr = struct.pack('H',nested[0]) + nested[1]
697707 nattr += struct.pack("{0}x".format(nlh.NLMSG_ALIGNBY(len(nattr))))
698708 attr += nattr
699 #for nested in v:
700 # nlen = len(v) + 2
701 # nattr = struct.pack('xBx', nlen) + nested
702 # nattr += struct.pack("{0}x".format(nlh.NLMSG_ALIGNBY(len(nattr))))
703 # attr += nattr
704709 else:
705710 fmt = "" # appease PyCharm
706711 if d == nlh.NLA_SET_U8: fmt = "B"
3131
3232 """
3333
34 #__name__ = 'genetlink_h.py'
34 __name__ = 'genetlink_h'
3535 __license__ = 'GPLv3'
3636 __version__ = '0.0.1'
3737 __date__ = 'March 2016'
5757 __status__ = 'Production'
5858
5959 import struct
60 import pyric.net.sockios_h as sioc
60 import pyric.net.sockios_h as sioch
61 import sys
62 _PY3_ = sys.version_info.major == 3
6163
6264 IFNAMSIZ = 16
6365 IFALIASZ = 256
151153 IF_LINK_MODE_DEFAULT = 0
152154 IF_LINK_MODE_DORMANT = 1 # limit upward transition to dormant
153155
154 #struct sockaddr {
155 # sa_family_t sa_family; /* address family, AF_xxx */
156 # char sa_data[14]; /* 14 bytes of protocol address */
157 #};
158 # NOTE:
159 # 1) for our purposes, we use only 6 characters, 6 octets for a hw addr and 4
160 # octets for an ip4 addr.
161 # 2) For whatever reason, all ioctl calls accept and return ip4 addresses
162 # prefixed by two null bytes
163
156 """
157 struct sockaddr {
158 sa_family_t sa_family; /* address family, AF_xxx */
159 char sa_data[14]; /* 14 bytes of protocol address */
160 };
161 NOTE:
162 1) for our purposes, we use only 6 characters, 6 octets for a hw addr and 4
163 octets for an ip4 addr.
164 2) For whatever reason, all ioctl calls accept and return ip4 addresses
165 prefixed by two null bytes
166 """
164167 AF_UNSPEC = 0 # from socket.h sa_family unspecified
165168 ARPHRD_ETHER = 1 # from net/if_arp.h sa_family ethernet a.k.a AF_LOCAL
166169 ARPHRD_IEEE80211 = 801 # net/if_arp.h sa_family IEEE 802.11
188191 raise AttributeError("sa_family {0} not supported".format(sa_family))
189192 return struct.pack(sa_addr,*vs)
190193
191 #### Interface request structure used for socket
192 # ioctl's. All interface ioctl's must have parameter
193 # definitions which begin with ifr_name. The
194 # remainder may be interface specific.
195 #
196 #struct ifreq {
197 #
198 # union
199 # {
200 # char ifrn_name[IFNAMSIZ]; # if name, e.g. "en0"
201 # } ifr_ifrn;
202 #
203 # union {
204 # struct sockaddr ifru_addr;
205 # struct sockaddr ifru_dstaddr;
206 # struct sockaddr ifru_broadaddr;
207 # struct sockaddr ifru_netmask;
208 # struct sockaddr ifru_hwaddr;
209 # short ifru_flags;
210 # int ifru_ivalue;
211 # int ifru_mtu;
212 # struct ifmap ifru_map;
213 # char ifru_slave[IFNAMSIZ]; # Just fits the size
214 # char ifru_newname[IFNAMSIZ];
215 # void * ifru_data;
216 # struct if_settings ifru_settings;
217 # } ifr_ifru;
218 #};
219 #
220 # from wireless.h we build
221 #struct iw_param
222 #{
223 # __s32 value; /* The value of the parameter itself */
224 # __u8 fixed; /* Hardware should not use auto select */
225 # __u8 disabled; /* Disable the feature */
226 # __u16 flags; /* Various specifc flags (if any) */
227 # to get the txpower and verify the presense of wireless extensions
228 #};
229
230 ifr_name = '{0}s'.format(IFNAMSIZ) # formats for ifreq struct
194 """
195 Interface request structure used for socket ioctl's. All interface ioctl's must
196 have parameter definitions which begin with ifr_name. The remainder may be
197 interface specific.
198
199 struct ifreq {
200
201 union
202 {
203 char ifrn_name[IFNAMSIZ]; # if name, e.g. "en0"
204 } ifr_ifrn;
205
206 union {
207 struct sockaddr ifru_addr;
208 struct sockaddr ifru_dstaddr;
209 struct sockaddr ifru_broadaddr;
210 struct sockaddr ifru_netmask;
211 struct sockaddr ifru_hwaddr;
212 short ifru_flags;
213 int ifru_ivalue;
214 int ifru_mtu;
215 struct ifmap ifru_map;
216 char ifru_slave[IFNAMSIZ]; # Just fits the size
217 char ifru_newname[IFNAMSIZ];
218 void * ifru_data;
219 struct if_settings ifru_settings;
220 } ifr_ifru;
221 };
222
223 from wireless.h we build
224 struct iw_param
225 {
226 __s32 value; /* The value of the parameter itself */
227 __u8 fixed; /* Hardware should not use auto select */
228 __u8 disabled; /* Disable the feature */
229 __u16 flags; /* Various specifc flags (if any) */
230 to get the txpower and verify the presense of wireless extensions
231 };
232 """
233 ifr_name = '{0}s'.format(IFNAMSIZ) # formats for ifreq struct
231234 ifr_flags = 'h'
232235 ifr_ifindex = 'i'
233236 ifr_iwname = '{0}s'.format(256-IFNAMSIZ) # dirty hack to get an unknown string back
254257 NOTE: ifreq will return AttributeError for any caught exception
255258 """
256259 # pack the nic
260 if _PY3_: ifrn = bytes(ifrn,'ascii')
257261 try:
258262 # NOTE: don't need to keep the name to 16 chars as struct does it for us
259263 ifr = struct.pack(ifr_name,ifrn)
262266
263267 try:
264268 if not ifru: pass # only pass the device name
265 elif ifru == sioc.SIOCGIFHWADDR: # get hwaddr
269 elif ifru == sioch.SIOCGIFHWADDR: # get hwaddr
266270 ifr += sockaddr(ARPHRD_ETHER,None)
267 elif ifru == sioc.SIOCSIFHWADDR: # set hwaddr
271 elif ifru == sioch.SIOCSIFHWADDR: # set hwaddr
268272 ifr += sockaddr(ARPHRD_ETHER,param[0])
269 elif ifru == sioc.SIOCGIFADDR or \
270 ifru == sioc.SIOCGIFNETMASK or \
271 ifru == sioc.SIOCGIFBRDADDR: # get ip4, netmask or broadcast address
273 elif ifru == sioch.SIOCGIFADDR or \
274 ifru == sioch.SIOCGIFNETMASK or \
275 ifru == sioch.SIOCGIFBRDADDR: # get ip4, netmask or broadcast address
272276 ifr += sockaddr(AF_INET,None)
273 elif ifru == sioc.SIOCSIFADDR or \
274 ifru == sioc.SIOCSIFNETMASK or \
275 ifru == sioc.SIOCSIFBRDADDR: # set ip4, netmask or broadcast address
277 elif ifru == sioch.SIOCSIFADDR or \
278 ifru == sioch.SIOCSIFNETMASK or \
279 ifru == sioch.SIOCSIFBRDADDR: # set ip4, netmask or broadcast address
276280 ifr += sockaddr(AF_INET,param[0])
277 elif ifru == sioc.SIOCGIFFLAGS: # get flags
281 elif ifru == sioch.SIOCGIFFLAGS: # get flags
278282 ifr += struct.pack('{0}x'.format(IFFLAGLEN))
279 elif ifru == sioc.SIOCSIFFLAGS: # set flags
283 elif ifru == sioch.SIOCSIFFLAGS: # set flags
280284 ifr += struct.pack(ifr_flags,param[0])
281 elif ifru == sioc.SIOCGIFINDEX: # get if index
285 elif ifru == sioch.SIOCGIFINDEX: # get if index
282286 ifr += struct.pack('{0}x'.format(IFIFINDEXLEN))
283 elif ifru == sioc.SIOCGIWNAME: # get iw name
287 elif ifru == sioch.SIOCGIWNAME: # get iw name
284288 ifr += struct.pack('{0}x'.format(IWNAMELEN))
285 elif ifru == sioc.SIOCGIWTXPOW: # get tx pwr
289 elif ifru == sioch.SIOCGIWTXPOW: # get tx pwr
286290 ifr += struct.pack('{0}x'.format(IWTXPWRLEN))
287291 else:
288292 raise AttributeError("ifru {0} not supported".format(ifru))
3333
3434 """
3535
36 # NOTE: get the below error when calling import netlink_h
37 #RuntimeWarning: Parent module 'netlink_h' not found while handling absolute import
38 # import struct
39 # unless I comment out the name
40 #__name__ = 'netlink_h.py'
36 __name__ = 'netlink_h'
4137 __license__ = 'GPLv3'
4238 __version__ = '0.0.3'
4339 __date__ = 'March 2016'
331327
332328 # defined error codes
333329 # only use success and failure -> using errno for other error numbers
334 NLE = ['Success','Unspecified failure']
335330 NLE_SUCCESS = 0
336331 NLE_FAILURE = 1
1818 contributors may be used to endorse or promote products derived from this
1919 software without specific prior written permission.
2020
21 Definition of constants et all found in IEEE Std 802.11-2012
21 Definition of constants et al found in IEEE Std 802.11-2012
2222
2323 Std will refer to IEEE Std 802.11-2012
2424
4949 try:
5050 # first three lines are comments, 4th line is empty
5151 cin = open(cmdpath,'r')
52 for _ in xrange(4): _in = cin.readline()
52 for _ in range(4): _in = cin.readline()
5353 commands = json.loads(cin.readline())
5454 cmdlookup = json.loads(cin.readline())
5555 except:
6464 try:
6565 # first three lines are comments, 3th line is empty
6666 ain = open(attrpath,'r')
67 for _ in xrange(4): _in = ain.readline()
67 for _ in range(4): _in = ain.readline()
6868 attributes = json.loads(ain.readline())
6969 attrlookup = json.loads(ain.readline())
7070 except:
00 #!/usr/bin/env python
11
2 """ pyw.py: python iw
2 """ pyw.py: Linux wireless library for the Python Wireless Developer and Pentester
33
44 Copyright (C) 2016 Dale V. Patterson ([email protected])
55
6262 devadd which will accept a Card or a phy
6363 2) All functions allow pyric errors to pass through. Callers must catch these
6464 if they desire
65
6665 """
6766
6867 __name__ = 'pyw'
6968 __license__ = 'GPLv3'
70 __version__ = '0.1.8'
71 __date__ = 'July 2016'
69 __version__ = '0.1.9'
70 __date__ = 'August 2016'
7271 __author__ = 'Dale Patterson'
7372 __maintainer__ = 'Dale Patterson'
7473 __email__ = '[email protected]'
7574 __status__ = 'Production'
7675
7776 import struct # ioctl unpacking
77 import re # check addr validity
7878 import pyric # pyric exception
79 import re # check addr validity
8079 from pyric.nlhelp.nlsearch import cmdbynum # get command name
81 from pyric.utils import channels # channel related
82 from pyric.utils import rfkill # block/unblock
80 import pyric.utils.channels as channels # channel related
81 import pyric.utils.rfkill as rfkill # block/unblock
8382 import pyric.utils.hardware as hw # device related
84 from pyric.utils import ouifetch # get oui dict
83 import pyric.utils.ouifetch as ouifetch # get oui dict
8584 import pyric.net.netlink_h as nlh # netlink definition
8685 import pyric.net.genetlink_h as genlh # genetlink definition
8786 import pyric.net.wireless.nl80211_h as nl80211h # nl80211 definition
88 from pyric.net.wireless import wlan # IEEE 802.11 Std definition
87 import pyric.lib.libnl as nl # netlink (library) functions
88 import pyric.net.wireless.wlan as wlan # IEEE 802.11 Std definition
8989 import pyric.net.sockios_h as sioch # sockios constants
9090 import pyric.net.if_h as ifh # ifreq structure
91 import pyric.lib.libnl as nl # netlink functions
92 import pyric.lib.libio as io # ioctl functions
91 import pyric.lib.libio as io # ioctl (library) functions
9392
9493 _FAM80211ID_ = None
9594
159158 return _iostub_(iswireless, dev)
160159
161160 try:
162 # if the call succeeds, found to be wireless
161 # if the call succeeds, dev is found to be wireless
163162 _ = io.io_transfer(iosock, sioch.SIOCGIWNAME, ifh.ifreq(dev))
164163 return True
165164 except AttributeError as e:
167166 except io.error as e:
168167 # ENODEV or ENOTSUPP means not wireless, reraise any others
169168 if e.errno == pyric.ENODEV or e.errno == pyric.EOPNOTSUPP: return False
170 else: raise pyric.error(e.errno, e.strerror)
169 else: raise pyric.error(e.errno)
171170
172171 def phylist():
173172 """ :returns: a list of tuples t = (physical indexe, physical name) """
174173 # we could walk the directory /sys/class/ieee80211 as well but we'll
175174 # let rfkill do it (just in case the above path differs across distros or
176 # in future upgrades
175 # in future upgrades)
177176 phys = []
178177 rfdevs = rfkill.rfkill_list()
179178 for rfk in rfdevs:
209208 :param rd: regulatory domain code
210209 :param argv: netlink socket at argv[0] (or empty)
211210 """
212 if len(rd) != 2:
213 raise pyric.error(pyric.EINVAL, "Invalid reg. domain {0}".format(rd))
211 if len(rd) != 2: raise pyric.error(pyric.EINVAL, "Invalid reg. domain")
212
214213 try:
215214 nlsock = argv[0]
216215 except IndexError:
242241 def __new__(cls, p, d, i):
243242 return super(Card, cls).__new__(cls, tuple((p, d, i)))
244243 def __repr__(self):
245 return "Card(phy={0},dev={1},ifindex={2})".format(self.phy,
246 self.dev,
247 self.idx)
244 return "Card(phy={0},dev={1},ifindex={2})".format(self.phy,self.dev,self.idx)
248245 @property
249246 def phy(self): return self[0]
250247 @property
256253 """
257254 get the Card object from device name
258255 :param dev: device name
256 :param argv: netlink socket at argv[0] or empty
259257 :returns: a Card with device name dev
260258 """
261259 try:
323321 :param argv: ioctl socket at argv[0] (or empty)
324322 :returns: mac address after operation
325323 """
326 if not _validmac_(mac): raise pyric.error(pyric.EINVAL, "Invalid mac address")
324 if not _validmac_(mac): raise pyric.error(pyric.EINVAL, "Invalid mac address")
327325
328326 try:
329327 iosock = argv[0]
637635 idx = rfkill.getidx(card.phy)
638636 return rfkill.soft_blocked(idx), rfkill.hard_blocked(idx)
639637 except AttributeError:
640 raise pyric.error(pyric.ENODEV, "Card is no longer regsitered")
638 raise pyric.error(pyric.ENODEV, "Card is no longer registered")
641639
642640 def block(card):
643641 """
659657 idx = rfkill.getidx(card.phy)
660658 rfkill.rfkill_unblock(idx)
661659 except AttributeError:
662 raise pyric.error(pyric.ENODEV, "Card no longer registered")
660 raise pyric.error(pyric.ENODEV, "Card is no longer registered")
663661
664662 ################################################################################
665663 #### RADIO PROPERTIES ####
716714 except AttributeError:
717715 raise pyric.error(pyric.EINVAL, "Invalid Card")
718716 except ValueError:
719 raise pyric.error(pyric.EINVAL, "Invalid parameter on")
717 raise pyric.error(pyric.EINVAL, "Invalid parameter {0} for on".format(on))
720718 except nl.error as e:
721719 raise pyric.error(e.errno, e.strerror)
722720
736734
737735 def covclassset(card, cc, *argv):
738736 """
739 REQUIRES ROOT PRIVILEGES
737 REQUIRES ROOT PRIVILEGES/DOES NOT WORK ON ALL SYSTEMS
740738 sets the coverage class. The coverage class IAW IEEE Std 802.11-2012 is
741739 defined as the Air propagation time & together with max tx power control
742740 the BSS diamter
748746 if cc < wlan.COV_CLASS_MIN or cc > wlan.COV_CLASS_MAX:
749747 # this can work 'incorrectly' on non-int values but these will
750748 # be caught later during conversion
751 msg = "Cov class must be integer {0}-{1}".format(wlan.COV_CLASS_MIN,
752 wlan.COV_CLASS_MAX)
753 raise pyric.error(pyric.EINVAL, msg)
749 emsg = "Cov class must be integer {0}-{1}".format(wlan.COV_CLASS_MIN,
750 wlan.COV_CLASS_MAX)
751 raise pyric.error(pyric.EINVAL, emsg)
754752
755753 try:
756754 nlsock = argv[0]
768766 except AttributeError:
769767 raise pyric.error(pyric.EINVAL, "Invalid Card")
770768 except ValueError:
771 raise pyric.error(pyric.EINVAL, "Invalid value for Cov. Class")
769 raise pyric.error(pyric.EINVAL, "Invalid value {0} for Cov. Class".format(cc))
772770 except nl.error as e:
773771 raise pyric.error(e.errno, e.strerror)
774772
793791 :param card: Card object
794792 :param lim: max # of short retries 1 - 255
795793 :param argv: netlink socket at argv[0] (or empty)
796 sets card's shorty retry
794 NOTE: after moving to kernel 4, the kernel does not allow setting up to
795 the max
797796 """
798797 if lim < wlan.RETRY_MIN or lim > wlan.RETRY_MAX:
799798 # this can work 'incorrectly' on non-int values but these will
800799 # be caught later during conversion
801 msg = "Retry short must be integer {0}-{1}".format(wlan.RETRY_MIN,
802 wlan.RETRY_MAX)
803 raise pyric.error(pyric.EINVAL, msg)
800 emsg = "Retry short must be integer {0}-{1}".format(wlan.RETRY_MIN,
801 wlan.RETRY_MAX)
802 raise pyric.error(pyric.EINVAL, emsg)
804803
805804 try:
806805 nlsock = argv[0]
818817 except AttributeError:
819818 raise pyric.error(pyric.EINVAL, "Invalid Card")
820819 except ValueError:
821 raise pyric.error(pyric.EINVAL, "Invalid parameter value for lim")
820 raise pyric.error(pyric.EINVAL, "Invalid value {0} for lim".format(lim))
822821 except nl.error as e:
823822 raise pyric.error(e.errno, e.strerror)
824823
843842 :param card: Card object
844843 :param lim: max # of short retries 1 - 255
845844 :param argv: netlink socket at argv[0] (or empty)
846 sets card's long retry
845 NOTE: after moving to kernel 4, the kernel does not allow setting up to
846 the max
847847 """
848848 if lim < wlan.RETRY_MIN or lim > wlan.RETRY_MAX:
849849 # this can work 'incorrectly' on non-int values but these will
850850 # be caught later during conversion
851 msg = "Retry long must be integer {0}-{1}".format(wlan.RETRY_MIN,
852 wlan.RETRY_MAX)
853 raise pyric.error(pyric.EINVAL, msg)
851 emsg = "Retry long must be integer {0}-{1}".format(wlan.RETRY_MIN,
852 wlan.RETRY_MAX)
853 raise pyric.error(pyric.EINVAL, emsg)
854854
855855 try:
856856 nlsock = argv[0]
868868 except AttributeError:
869869 raise pyric.error(pyric.EINVAL, "Invalid Card")
870870 except ValueError:
871 raise pyric.error(pyric.EINVAL, "Invalid parameter value for lim")
871 raise pyric.error(pyric.EINVAL, "Invalid value {0} for lim".format(lim))
872872 except nl.error as e:
873873 raise pyric.error(e.errno, e.strerror)
874874
899899 if thresh == 'off': thresh = wlan.RTS_THRESH_OFF
900900 elif thresh == wlan.RTS_THRESH_OFF: pass
901901 elif thresh < wlan.RTS_THRESH_MIN or thresh > wlan.RTS_THRESH_MAX:
902 msg = "Thresh must be 'off' or integer {0}-{1}".format(wlan.RTS_THRESH_MIN,
903 wlan.RTS_THRESH_MAX)
904 raise pyric.error(pyric.EINVAL, msg)
902 emsg = "Thresh must be 'off' or integer {0}-{1}".format(wlan.RTS_THRESH_MIN,
903 wlan.RTS_THRESH_MAX)
904 raise pyric.error(pyric.EINVAL, emsg)
905905
906906 try:
907907 nlsock = argv[0]
919919 except AttributeError:
920920 raise pyric.error(pyric.EINVAL, "Invalid Card")
921921 except ValueError:
922 raise pyric.error(pyric.EINVAL, "Invalid parameter value for thresh")
922 raise pyric.error(pyric.EINVAL, "Invalid value {0} for thresh".format(thresh))
923923 except nl.error as e:
924924 raise pyric.error(e.errno, e.strerror)
925925
950950 if thresh == 'off': thresh = wlan.FRAG_THRESH_OFF
951951 elif thresh == wlan.FRAG_THRESH_OFF: pass
952952 elif thresh < wlan.FRAG_THRESH_MIN or thresh > wlan.FRAG_THRESH_MAX:
953 msg = "Thresh must be 'off' or integer {0}-{1}".format(wlan.FRAG_THRESH_MIN,
954 wlan.FRAG_THRESH_MAX)
955 raise pyric.error(pyric.EINVAL, msg)
953 emsg = "Thresh must be 'off' or integer {0}-{1}".format(wlan.FRAG_THRESH_MIN,
954 wlan.FRAG_THRESH_MAX)
955 raise pyric.error(pyric.EINVAL, emsg)
956956
957957 try:
958958 nlsock = argv[0]
988988 except IndexError:
989989 return _nlstub_(devfreqs, card)
990990
991 return phyinfo(card, nlsock)['freqs']
991 rfs = []
992 pinfo = phyinfo(card, nlsock)
993 for band in pinfo['bands']:
994 rfs.extend(pinfo['bands'][band]['rfs'])
995 rfs = sorted(rfs)
996 return rfs
992997
993998 def devchs(card, *argv):
994999 """
10021007 except IndexError:
10031008 return _nlstub_(devchs, card)
10041009
1005 return map(channels.rf2ch, phyinfo(card, nlsock)['freqs'])
1010 return [channels.rf2ch(rf) for rf in devfreqs(card,nlsock)]
10061011
10071012 def devstds(card, *argv):
10081013 """
11131118 except IndexError:
11141119 return _nlstub_(devinfo, card)
11151120
1116 # if we have a Card, pull out dev name, ifindex itherwise get ifindex
1117 try:
1118 dev = card.dev
1119 idx = card.idx
1120 except AttributeError:
1121 dev = card
1122 idx = _ifindex_(dev)
1123
1124 try:
1121 dev = None # appease pycharm
1122 try:
1123 # if we have a Card, pull out ifindex. otherwise get ifindex from dev
1124 try:
1125 dev = card.dev
1126 idx = card.idx
1127 except AttributeError:
1128 dev = card
1129 idx = _ifindex_(dev)
1130
1131 # using the ifindex, get the phy and details about the Card
11251132 msg = nl.nlmsg_new(nltype=_familyid_(nlsock),
11261133 cmd=nl80211h.NL80211_CMD_GET_INTERFACE,
11271134 flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
11281135 nl.nla_put_u32(msg, idx, nl80211h.NL80211_ATTR_IFINDEX)
11291136 nl.nl_sendmsg(nlsock, msg)
11301137 rmsg = nl.nl_recvmsg(nlsock)
1138 except io.error as e:
1139 # if we get a errno -19, it means ifindex failed & there is no device dev
1140 raise pyric.error(e.errno, e.strerror)
11311141 except nl.error as e:
1142 # if we get a errno -19, it is mostly likely because the card does
1143 # not support nl80211. However check to ensure the card hasn't been
1144 # unplugged.
1145 if e.errno == pyric.ENODEV:
1146 try:
1147 _ = _ifindex_(dev)
1148 except io.error as e:
1149 raise pyric.error(e.errno, "{0}. Check Card".format(e.strerror))
1150 raise pyric.error(pyric.EPROTONOSUPPORT, "Device does not support nl80211")
11321151 raise pyric.error(e.errno, e.strerror)
11331152
11341153 # pull out attributes
12771296 _ = nl.nl_recvmsg(nlsock)
12781297 except ValueError:
12791298 # converting to mBm
1280 raise pyric.error(pyric.EINVAL, "Invalid txpwr {0}".format(lvl))
1299 raise pyric.error(pyric.EINVAL, "Invalid value {0} for txpwr".format(lvl))
12811300 except AttributeError:
12821301 raise pyric.error(pyric.EINVAL, "Invalid Card")
12831302 except nl.error as e:
13341353 :param ch: channel number
13351354 :param chw: channel width oneof {[None|'HT20'|'HT40-'|'HT40+'}
13361355 :param argv: netlink socket at argv[0] (or empty)
1337 :returns: True on success
13381356 NOTE:
1339 o Can throw a device busy for several reason. Most likely due to
1340 the network manager etc.
1341 o On my system at least (Ubuntu), creating a new dev in monitor mode and
1342 deleting all other existing managed interfaces allows for the new virtual
1343 device's channels to be changed w/out interference from network manager
1344 """
1345 if ch not in channels.channels():
1346 raise pyric.error(pyric.EINVAL, "Invalid channel")
1347
1357 Can throw a device busy for several reason. 1) Card is down, 2) Another
1358 device is sharing the phy and wpa_supplicant/Network Manage is using it
1359 """
13481360 try:
13491361 nlsock = argv[0]
13501362 except IndexError:
13511363 return _nlstub_(chset, card, ch, chw)
13521364
13531365 return freqset(card, channels.ch2rf(ch), chw, nlsock)
1366
1367 def freqget(card, *argv):
1368 """
1369 gets the current frequency for device (iw dev <card.dev> info | grep channel)
1370 :param card: Card object
1371 :param argv: netlink socket at argv[0] (or empty)
1372 NOTE: will only work if dev is associated w/ AP or device is in monitor mode
1373 and has had [ch|freq]set previously
1374 """
1375 try:
1376 nlsock = argv[0]
1377 except IndexError:
1378 return _nlstub_(chget, card)
1379
1380 return devinfo(card, nlsock)['RF']
13541381
13551382 def freqset(card, rf, chw=None, *argv):
13561383 """
13601387 :param rf: frequency
13611388 :param chw: channel width oneof {[None|'HT20'|'HT40-'|'HT40+'}
13621389 :param argv: netlink socket at argv[0] (or empty)
1363 """
1364 if rf not in channels.freqs(): raise pyric.error(pyric.EINVAL, "Invalid RF")
1365 if chw in channels.CHTYPES: chw = channels.CHTYPES.index(chw)
1366 else: raise pyric.error(pyric.EINVAL, "Invalid channel width")
1367
1390 NOTE:
1391 Can throw a device busy for several reason. 1) Card is down, 2) Another
1392 device is sharing the phy and wpa_supplicant/Network Manage is using it
1393 """
13681394 try:
13691395 nlsock = argv[0]
13701396 except IndexError:
13711397 return _nlstub_(freqset, card, rf, chw)
13721398
13731399 try:
1400 chw = channels.CHTYPES.index(chw)
13741401 msg = nl.nlmsg_new(nltype=_familyid_(nlsock),
13751402 cmd=nl80211h.NL80211_CMD_SET_WIPHY,
13761403 flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
13791406 nl.nla_put_u32(msg, chw, nl80211h.NL80211_ATTR_WIPHY_CHANNEL_TYPE)
13801407 nl.nl_sendmsg(nlsock, msg)
13811408 _ = nl.nl_recvmsg(nlsock)
1409 except ValueError:
1410 raise pyric.error(pyric.EINVAL, "Invalid channel width")
13821411 except AttributeError:
13831412 raise pyric.error(pyric.EINVAL, "Invalid Card")
13841413 except nl.error as e:
1414 if e.errno == pyric.EBUSY: raise pyric.error(e.errno,pyric.strerror(e.errno))
13851415 raise pyric.error(e.errno, e.strerror)
13861416
13871417 #### INTERFACE & MODE RELATED ####
14831513 set a new dev.
14841514 o this is not a true set name: it adds a new card with ndev as the dev then
14851515 deletes the current card, returning the new card
1486 - in effect, it will appear as if the card as a new name but, it will also
1516 - in effect, it will appear as if the card has a new name but, it will also
14871517 have a new ifindex
14881518 """
14891519 try:
15081538 def devadd(card, vdev, mode, flags=None, *argv):
15091539 """
15101540 REQUIRES ROOT PRIVILEGES
1541 adds a virtual interface on device having type mode (iw dev <card.dev>
1542 interface add <vnic> type <mode>
1543 :param card: Card object or ifindex
1544 :param vdev: device name of new interface
1545 :param mode: 'name' of mode to operate in (must be one of in {'unspecified'|
1546 'ibss'|'managed'|'AP'|'AP VLAN'|'wds'|'monitor'|'mesh'|'p2p'}
1547 :param flags: list of monitor flags (can only be used if creating monitor
1548 mode) oneof {'invalid'|'fcsfail'|'plcpfail'|'control'|'other bss'
1549 |'cook'|'active'}
1550 :param argv: netlink socket at argv[0] (or empty)
1551 :returns: the new Card
1552 NOTE: the new Card will be 'down'
1553 """
1554 if iswireless(vdev): raise pyric.error(pyric.ENOTUNIQ,"{0} already exists".format(vdev))
1555 if mode not in IFTYPES: raise pyric.error(pyric.EINVAL, 'Invalid mode')
1556 if flags:
1557 if mode != 'monitor':
1558 raise pyric.error(pyric.EINVAL, 'Can only set flags in monitor mode')
1559 for flag in flags:
1560 if flag not in MNTRFLAGS:
1561 raise pyric.error(pyric.EINVAL, 'Invalid flag: {0}'.format(flag))
1562 else: flags = []
1563
1564 try:
1565 nlsock = argv[0]
1566 except IndexError:
1567 return _nlstub_(devadd, card, vdev, mode, flags)
1568
1569 # if we have a Card, pull out ifindex
1570 try:
1571 idx = card.idx
1572 except AttributeError:
1573 idx = card
1574
1575 try:
1576 msg = nl.nlmsg_new(nltype=_familyid_(nlsock),
1577 cmd=nl80211h.NL80211_CMD_NEW_INTERFACE,
1578 flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
1579 nl.nla_put_u32(msg, idx, nl80211h.NL80211_ATTR_IFINDEX)
1580 nl.nla_put_string(msg, vdev, nl80211h.NL80211_ATTR_IFNAME)
1581 nl.nla_put_u32(msg, IFTYPES.index(mode), nl80211h.NL80211_ATTR_IFTYPE)
1582 for flag in flags:
1583 nl.nla_put_u32(msg,
1584 MNTRFLAGS.index(flag),
1585 nl80211h.NL80211_ATTR_MNTR_FLAGS)
1586 nl.nl_sendmsg(nlsock, msg)
1587 rmsg = nl.nl_recvmsg(nlsock) # success returns new device attributes
1588 except AttributeError as e:
1589 raise pyric.error(pyric.EINVAL, e)
1590 except nl.error as e:
1591 raise pyric.error(e.errno, e.strerror)
1592
1593 # return the new Card with info from the results msg
1594 return Card(nl.nla_find(rmsg, nl80211h.NL80211_ATTR_WIPHY),
1595 nl.nla_find(rmsg, nl80211h.NL80211_ATTR_IFNAME),
1596 nl.nla_find(rmsg, nl80211h.NL80211_ATTR_IFINDEX))
1597
1598 def devdel(card, *argv):
1599 """
1600 REQUIRES ROOT PRIVILEGES
1601 deletes the device (dev <card.dev> del
1602 :param card: Card object
1603 :param argv: netlink socket at argv[0] (or empty)
1604 NOTE: the original card is no longer valid (i.e. the phy will still be present
1605 but the device name and ifindex are no longer 'present' in the system
1606 """
1607 try:
1608 nlsock = argv[0]
1609 except IndexError:
1610 return _nlstub_(devdel, card)
1611
1612 try:
1613 msg = nl.nlmsg_new(nltype=_familyid_(nlsock),
1614 cmd=nl80211h.NL80211_CMD_DEL_INTERFACE,
1615 flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
1616 nl.nla_put_u32(msg, card.idx, nl80211h.NL80211_ATTR_IFINDEX)
1617 nl.nl_sendmsg(nlsock, msg)
1618 _ = nl.nl_recvmsg(nlsock)
1619 except AttributeError:
1620 raise pyric.error(pyric.EINVAL, "Invalid Card")
1621 except nl.error as e:
1622 raise pyric.error(e.errno, e.strerror)
1623
1624 def phyadd(card, vdev, mode, flags=None, *argv):
1625 """
1626 REQUIRES ROOT PRIVILEGES
15111627 adds a virtual interface on device having type mode (iw phy <card.phy>
15121628 interface add <vnic> type <mode>
15131629 :param card: Card object or physical index
15191635 |'cook'|'active'}
15201636 :param argv: netlink socket at argv[0] (or empty)
15211637 :returns: the new Card
1638 NOTE: the new Card will be 'down'
15221639 """
15231640 if mode not in IFTYPES: raise pyric.error(pyric.EINVAL, 'Invalid mode')
15241641 if flags:
15321649 try:
15331650 nlsock = argv[0]
15341651 except IndexError:
1535 return _nlstub_(devadd, card, vdev, mode, flags)
1536
1537 # if we have a Card, pull out phy index
1652 return _nlstub_(phyadd, card, vdev, mode, flags)
1653
1654 # if we have a Card, pull out phy
15381655 try:
15391656 phy = card.phy
15401657 except AttributeError:
15581675 except nl.error as e:
15591676 raise pyric.error(e.errno, e.strerror)
15601677
1561 return Card(card.phy, vdev, nl.nla_find(rmsg, nl80211h.NL80211_ATTR_IFINDEX))
1562
1563 def devdel(card, *argv):
1564 """
1565 REQUIRES ROOT PRIVILEGES
1566 deletes the device (dev <card.dev> del
1567 :param card: Card object
1568 :param argv: netlink socket at argv[0] (or empty)
1569 NOTE: the original card is no longer valid (i.e. the phy will still be present
1570 but the device name and ifindex are no longer 'present' in the system
1571 """
1572 try:
1573 nlsock = argv[0]
1574 except IndexError:
1575 return _nlstub_(devdel, card)
1576
1577 try:
1578 msg = nl.nlmsg_new(nltype=_familyid_(nlsock),
1579 cmd=nl80211h.NL80211_CMD_DEL_INTERFACE,
1580 flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
1581 nl.nla_put_u32(msg, card.idx, nl80211h.NL80211_ATTR_IFINDEX)
1582 nl.nl_sendmsg(nlsock, msg)
1583 _ = nl.nl_recvmsg(nlsock)
1584 except AttributeError:
1585 raise pyric.error(pyric.EINVAL, "Invalid Card")
1586 except nl.error as e:
1587 raise pyric.error(e.errno, e.strerror)
1678 # get card & determine if we got a card with the specified name
1679 return Card(nl.nla_find(rmsg, nl80211h.NL80211_ATTR_WIPHY),
1680 nl.nla_find(rmsg, nl80211h.NL80211_ATTR_IFNAME),
1681 nl.nla_find(rmsg, nl80211h.NL80211_ATTR_IFINDEX))
15881682
15891683 ################################################################################
15901684 #### STA FUNCTIONS ####
16041698 # dirty hack - using the precence of an RF to determine connected-ness
16051699 return devinfo(card, nlsock)['RF'] is not None
16061700
1701 def connect(card, ssid, bssid=None, rf=None, *argv):
1702 """
1703 REQUIRES ROOT PRIVILEGES & WPA_SUPPLICANT MUST BE DISABLED
1704 connects to (Open) AP
1705 :param card: Card object
1706 :param ssid: the SSID, network name
1707 :param bssid: the AP's BSSID
1708 :param rf: the frequency of the AP
1709 :param argv: netlink socket at argv[0] (or empty)
1710 :returns: True on successful connect, False otherwise
1711 NOTE: although connected, traffic will not be route, card will not have
1712 an IP assigned
1713 """
1714 try:
1715 nlsock = argv[0]
1716 except IndexError:
1717 return _nlstub_(connect, card, ssid, bssid, rf)
1718
1719 try:
1720 msg = nl.nlmsg_new(nltype=_familyid_(nlsock),
1721 cmd=nl80211h.NL80211_CMD_CONNECT, # step 1
1722 flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
1723 nl.nla_put_u32(msg, card.idx, nl80211h.NL80211_ATTR_IFINDEX)
1724 nl.nla_put_unspec(msg, ssid, nl80211h.NL80211_ATTR_SSID)
1725 nl.nla_put_unspec(msg, _mac2hex_(bssid), nl80211h.NL80211_ATTR_MAC)
1726 nl.nl_sendmsg(nlsock, msg)
1727 if not nl.nl_recvmsg(nlsock) == nlh.NLE_SUCCESS: return False
1728
1729 except AttributeError:
1730 raise pyric.error(pyric.EINVAL, "Invalid Card")
1731 except nl.error as e:
1732 raise pyric.error(e.errno, e.strerror)
1733 return True
1734
16071735 def disconnect(card, *argv):
16081736 """
16091737 REQUIRES ROOT PRIVILEGES
16101738 disconnect the card from an AP
16111739 :param card: Card object
16121740 :param argv: netlink socket at argv[0] (or empty)
1613 NOTE: does not return error if card is not connected
1741 NOTE: does not return error if card is not connected. May not work if
1742 wpa_supplicant is running
16141743 """
16151744 try:
16161745 nlsock = argv[0]
16971826 if idx == nl80211h.NL80211_BSS_SIGNAL_MBM:
16981827 info['rss'] = struct.unpack_from('i', attr, 0)[0] / 100
16991828 if idx == nl80211h.NL80211_BSS_INFORMATION_ELEMENTS:
1700 # hacking the proprietary info element attribute: (it should
1701 # be a nested attribute itself, but I have currently no way of
1702 # knowing what the individual indexes would mean
1703 # "\x06\x00\x00<l>SSID.....
1704 # '\x06\x00' is the ie index & the ssid is the first element
1705 # (from what I've seen). This is not nested. Not sure if the
1706 # length is the first two bytes or just the second Get the length of the ssid which is the 3rd,4th byte, then unpack
1707 # the string starting at the fifth byte up to the length
1829 """
1830 hack the proprietary info element attribute: (it should
1831 be a nested attribute itself, but I have currently no way of
1832 knowing what the individual indexes would mean
1833 \x06\x00\x00<l>SSID.....
1834 '\x06\x00' is the ie index & the ssid is the first element
1835 (from what I've seen). This is not nested. Not sure if the
1836 length is the first two bytes or just the second Get the length
1837 of the ssid which is the 3rd,4th byte, then unpack the string
1838 starting at the fifth byte up to the specified length
1839 """
17081840 try:
17091841 l = struct.unpack_from('>H', attr, 0)[0] # have to change the format
17101842 info['ssid'] = struct.unpack_from('{0}s'.format(l), attr, 2)[0]
17971929 'tx-bitrate':{}, 'rx-bitrate':{}}
17981930
17991931 _, bs, d = nl.nla_find(rmsg, nl80211h.NL80211_ATTR_STA_INFO, False)
1932 if d == nlh.NLA_ERROR: return info
18001933 for sidx, sattr in bs: # sidx indexes the enum nl80211_sta_info
18011934 try:
18021935 if sidx == nl80211h.NL80211_STA_INFO_RX_BYTES:
18301963
18311964
18321965 def _hex2ip4_(v):
1833 """ :returns: a '.' separated ip4 address from byte stream v """
1834 return '.'.join([str(ord(c)) for c in v])
1966 """
1967 :param v: packed by string
1968 :returns: a '.' separated ip4 address from byte stream v
1969 """
1970 try:
1971 return '.'.join([str(ord(c)) for c in v])
1972 except TypeError:
1973 # python 3 c is already numeric
1974 return '.'.join([str(c) for c in v])
18351975
18361976 def _hex2mac_(v):
18371977 """
18381978 :param v: packed bytestream of form \xd8\xc7\xc8\x00\x11\x22
18391979 :returns: a ':' separated mac address from byte stream v
18401980 """
1841 return ":".join(['{0:02x}'.format(ord(c)) for c in v])
1981 try:
1982 return ":".join(['{0:02x}'.format(ord(c)) for c in v])
1983 except TypeError:
1984 # it appears that in Python 3.5 c is already numeric
1985 return ":".join(['{0:02x}'.format(c) for c in v])
18421986
18431987 def _mac2hex_(v):
18441988 """
21062250 :returns: list of supported commands as strings
21072251 """
21082252 cs = []
2109 for _,cmd in command: # rather than index, commands use a counter, ignore it
2253 for _,cmd in command: # rather than an index, commands use a counter, ignore it
21102254 try:
2111
2112 # <- 2 -><- 4 ->
2113 # ignore count, use numeric command to lookup string version in form
2114 # @NL80211_CMD_<CMD> and strip "@NL80211_CMD_". NOTE: some numeric
2115 # commands may have multiple string synonyms, in that case, take the
2116 # first one. Finally, make it lowercase
2255 # use numeric command to lookup string version in form
2256 # @NL80211_CMD_<CMD>
2257 # and strip "@NL80211_CMD_". NOTE: some commands may have multiple
2258 # string synonyms, in that case, take the first one. Finally, make
2259 # it lowercase
21172260 cmd = cmdbynum(struct.unpack_from('I', cmd, 0)[0])
21182261 if type(cmd) is type([]): cmd = cmd[0]
21192262 cs.append(cmd[13:].lower()) # skip NL80211_CMD_
22022345 raise pyric.error(pyric.EINVAL, e)
22032346 except struct.error as e:
22042347 raise pyric.error(pyric.EUNDEF, "Error parsing results: {0}".format(e))
2205 except io.error as e:
2206 raise pyric.error(e.errno, e.strerror)
22072348
22082349 def _familyid_(nlsock):
22092350 """
22962437 nl.nla_put_u32(msg, channels.ch2rf(ch), nl80211h.NL80211_ATTR_WIPHY_FREQ)
22972438 nl.nla_put_u32(msg, channels.CHTYPES.index(chw), nl80211h.NL80211_ATTR_WIPHY_CHANNEL_TYPE)
22982439 nl.nl_sendmsg(nlsock, msg)
2299 _ = nl.nl_recvmsg(nlsock)
2440 _ = nl.nl_recvmsg(nlsock)
2020
2121 utils 0.0.1
2222 desc: utilities
23 includes: hardware 0.0.5 ouifetch 0.0.1 channels 0.0.1 rfkill 0.0.1
23 includes: hardware 0.0.5 ouifetch 0.0.2 channels 0.0.1 rfkill 0.0.1
2424 changes:
2525 o added mac address related to hardware.py
2626 o randhw does not force an ouis dict, if not present, randomly generates the
3737 import pyric.net.wireless.nl80211_h as nl80211h
3838
3939 # redefined widths (allowed in nl80211h)
40 CHTYPES = nl80211h.NL80211_CHAN_TYPES
41 CHWIDTHS = nl80211h.NL80211_CHAN_WIDTHS
40 CHTYPES = nl80211h.NL80211_CHAN_TYPES # widths nl80211 supports i.e HT40-
41 CHWIDTHS = nl80211h.NL80211_CHAN_WIDTHS # actual widths
4242
4343 # ISM Bands (ieee80211.h-> BAND_ID_2G)
4444 ISM_24_C2F={1:2412,2:2417,3:2422,4:2427,5:2432,6:2437,7:2442,
4747 2447:8,2417:2,2452:9,2422:3,2457:10,2427:4,2462:11}
4848
4949 # UNII 5 Bands (ieee80211.h-> BAND_ID_5G)
50 # confirm that ch 34, ch 54, 58, 62, 102, 106, 110, 114 118, 122, 126, 138, 144, 151,
51 # 155, 159,
5052 UNII_5_C2F={34:5170,36:5180,38:5190,40:5200,42:5210,44:5220,46:5230,48:5240,50:5250,
51 52:5260,54:5270,56:5280,58:5280,60:5300,62:5310,64:5320,100:5500,
53 52:5260,54:5270,56:5280,58:5290,60:5300,62:5310,64:5320,100:5500,
5254 102:5510,104:5520,106:5530,108:5540,110:5550,112:5560,114:5570,116:5580,
5355 118:5590,120:5600,122:5610,124:5620,126:5630,128:5640,132:5660,136:5680,
5456 138:5690,140:5700,142:5710,144:5720,149:5745,151:5755,153:5765,155:5775,
5557 157:5785,159:5795,161:5805,165:5825}
5658 UNII_5_F2C={5250:50,5765:153,5510:102,5640:128,5260:52,5775:155,5520:104,5270:54,
57 5785:157,5530:106,5660:132,5280:58,5795:159,5540:108,5805:161,5550:110,
58 5680:136,5170:34,5300:60,5560:112,5690:138,5180:36,5310:62,5825:165,
59 5570:114,5700:140,5190:38,5320:64,5580:116,5710:142,5200:40,5590:118,
60 5720:144,5210:42,5600:120,5220:44,5610:122,5230:46,5745:149,5620:124,
61 5240:48,5755:151,5500:100,5630:126}
59 5785:157,5530:106,5660:132,5280:56,5795:159,5540:108,5290:58,5805:161,
60 5550:110,5680:136,5170:34,5300:60,5560:112,5690:138,5180:36,5310:62,
61 5825:165,5570:114,5700:140,5190:38,5320:64,5580:116,5710:142,5200:40,
62 5590:118,5720:144,5210:42,5600:120,5220:44,5610:122,5230:46,5745:149,
63 5620:124,5240:48,5755:151,5500:100,5630:126}
6264
6365 # UNII 4 Bands (ieee80211.h-> BAND_ID_5G)
6466 UNII_4_C2F={183:4915,184:4920,185:4925,187:4935,188:4940,189:4945,192:4960,196:4980}
6971 #134 3672.5 134 3670.0 135 3677.5 136 3682.5 136 3680.0
7072 #137 3687.5 137 3685.0 138 3689.5 138 3690.0
7173
72 def channels():
73 """ :returns:list of all channels """
74 return sorted(ISM_24_C2F.keys() + UNII_5_C2F.keys() + UNII_4_C2F.keys())
74 def channels(band=None):
75 """
76 returns list of channels
77 :param band: one of {None=all|'ISM'=2.4GHz|'UNII'=4.9/5GHz|'UNII5'=5GHz,
78 'UNII4'=4GHz}
79 :returns:list of channels
80 """
81 if band == 'ISM': return ISM_24_C2F.keys()
82 elif band == 'UNII': return UNII_5_C2F.keys() + UNII_4_C2F.keys()
83 elif band == 'UNII4': return UNII_4_C2F.keys()
84 elif band == 'UNII5': return UNII_5_C2F.keys()
85 try:
86 return sorted(ISM_24_C2F.keys() + UNII_5_C2F.keys() + UNII_4_C2F.keys())
87 except TypeError:
88 # python 3 doesn't like the above (uses dict_keys obj instead of list)
89 return sorted(list(ISM_24_C2F.keys()) + list(UNII_5_C2F.keys()) + list(UNII_4_C2F.keys()))
7590
76 def freqs():
77 """ :returns:list of frequencies """
91 def freqs(band=None):
92 """
93 returns list of channels
94 :param band: one of {None=all|'ISM'=2.4GHz|'UNII'=4.9/5GHz|'UNII5'=5GHz,
95 'UNII4'=4GHz}
96 :returns:list of frequencies
97 """
98 if band == 'ISM': return sorted(ISM_24_F2C.keys())
99 elif band == 'UNII': return sorted(UNII_5_F2C.keys() + UNII_4_F2C.keys())
100 elif band == 'UNII4': return sorted(UNII_4_F2C.keys())
101 elif band == 'UNII5': return sorted(UNII_5_F2C.keys())
78102 return sorted(ISM_24_F2C.keys() + UNII_5_F2C.keys()+ UNII_4_F2C.keys())
79103
80104 def ch2rf(c):
97121 if f in ISM_24_F2C: return ISM_24_F2C[f]
98122 if f in UNII_5_F2C: return UNII_5_F2C[f]
99123 if f in UNII_4_F2C: return UNII_4_F2C[f]
100 return None
124 return None
7171 :returns: random hw address
7272 """
7373 if ouis is None or ouis == []:
74 o = ":".join(['{0:02x}'.format(random.randint(0,255)) for _ in xrange(3)])
74 o = ":".join(['{0:02x}'.format(random.randint(0,255)) for _ in range(3)])
7575 else:
7676 o = random.choice(ouis.keys())
77 u = ":".join(['{0:02x}'.format(random.randint(0,255)) for _ in xrange(3)])
77 u = ":".join(['{0:02x}'.format(random.randint(0,255)) for _ in range(3)])
7878 return o + ':' + u
7979
8080 def ifcard(dev):
2222 Fetchs and stores oui data from IEEE
2323
2424 """
25 from __future__ import print_function # python 2to3 compability
2526
26 #__name__ = 'ouifetch'
27 __name__ = 'ouifetch'
2728 __license__ = 'GPLv3'
28 __version__ = '0.0.1'
29 __date__ = 'August 2014'
29 __version__ = '0.0.2'
30 __date__ = 'July 2016'
3031 __author__ = 'Dale Patterson'
3132 __maintainer__ = 'Dale Patterson'
3233 __email__ = '[email protected]'
3334 __status__ = 'Production'
3435
35 import urllib2,os,sys,datetime,time
36 #import argparse as ap
36 try:
37 # load urllib related for python 2
38 from urllib2 import Request as url_request
39 from urllib2 import urlopen as url_open
40 from urllib2 import URLError as url_error
41 except ImportError:
42 from urllib.request import Request as url_request
43 from urllib.request import urlopen as url_open
44 from urllib import error as url_error
45 import os,sys,datetime,time
3746 import pyric
3847
3948 OUIURL = 'http://standards-oui.ieee.org/oui.txt'
7483 # determine if data path is legit
7584 if opath is None: opath = OUIPATH
7685 if not os.path.isdir(os.path.dirname(opath)):
77 print "Path to data is incorrect {0}".format(opath)
86 print("Path to data is incorrect {0}".format(opath))
7887 sys.exit(1)
7988
8089 # fetch oui file from ieee
8190 fout = None
8291
8392 # set up url request
84 req = urllib2.Request(OUIURL)
93 req = url_request(OUIURL)
8594 req.add_header('User-Agent',"PyRIC +https://github.com/wraith-wireless/PyRIC/")
8695 try:
8796 # retrieve the oui file and parse out generated date
88 if verbose: print 'Fetching ', OUIURL
89 res = urllib2.urlopen(req)
90 if verbose: print "Parsing OUI file"
97 if verbose: print('Fetching ', OUIURL)
98 res = url_open(req)
99 if verbose: print("Parsing OUI file")
91100
92 if verbose: print "Opening data file {0} for writing".format(opath)
101 if verbose: print("Opening data file {0} for writing".format(opath))
93102 fout = open(opath,'w')
94103 gen = datetime.datetime.utcnow().isoformat() # use current time as the first line
95104 fout.write(gen+'\n')
109118 # write to file & update count
110119 fout.write('{0}\t{1}\n'.format(oui,manuf))
111120 cnt += 1
112 if verbose: print "{0}:\t{1}\t{2}".format(cnt,oui,manuf)
113 print "Wrote {0} OUIs in {1:.3} secs".format(cnt,time.time()-t)
114 except urllib2.URLError as e:
115 print "Error fetching oui file: {0}".format(e)
121 if verbose: print("{0}:\t{1}\t{2}".format(cnt,oui,manuf))
122 print("Wrote {0} OUIs in {1:.3} secs".format(cnt,time.time()-t))
123 except url_error as e:
124 print("Error fetching oui file: {0}".format(e))
116125 except IOError as e:
117 print "Error opening output file {0}".format(e)
126 print("Error opening output file {0}".format(e))
118127 except Exception as e:
119 print "Error parsing oui file: {0}".format(e)
128 print("Error parsing oui file: {0}".format(e))
120129 finally:
121130 if fout: fout.close()
122131
4444 import pyric
4545 import errno
4646 import pyric.net.wireless.rfkill_h as rfkh
47 import sys
48 _PY3_ = sys.version_info.major == 3
4749
4850 RFKILL_STATE = [False,True] # Unblocked = 0, Blocked = 1
4951
6971 fcntl.fcntl(fin.fileno(),fcntl.F_SETFL,flags|os.O_NONBLOCK)
7072 while True:
7173 try:
72 idx,t,op,s,h = struct.unpack(rfkh.rfk_rfkill_event,
73 fin.read(rfkh.RFKILLEVENTLEN))
74 stream = fin.read(rfkh.RFKILLEVENTLEN)
75 if _PY3_:
76 # noinspection PyArgumentList
77 stream = bytes(stream,'ascii')
78 if len(stream) < rfkh.RFKILLEVENTLEN: raise IOError('python 3')
79 idx,t,op,s,h = struct.unpack(rfkh.rfk_rfkill_event,stream)
7480 if op == rfkh.RFKILL_OP_ADD:
7581 rfks[getname(idx)] = {'idx':idx,
7682 'type':rfkh.RFKILL_TYPES[t],
9197 fout = None
9298 try:
9399 rfke = rfkh.rfkill_event(idx,rfkh.RFKILL_TYPE_ALL,rfkh.RFKILL_OP_CHANGE,1,0)
100 if _PY3_: rfke = rfke.decode('ascii')
94101 fout = open(dpath, 'w')
95102 fout.write(rfke)
96103 except struct.error as e:
0 # pip installation and distribution
0 # pip installation and distribution sudo pip install PyRIC
11
22 [bdist_wheel]
33 universal=1
1919 contributors may be used to endorse or promote products derived from this
2020 software without specific prior written permission.
2121
22 sudo pip install PyRIC
23
2224 """
2325
2426 #__name__ = 'setup'
3739 version=pyric.version,
3840 description="Python Wireless Library",
3941 long_description=pyric.long_desc,
40 url='https://github.com/wraith-wireless/PyRIC/',
42 url='http://wraith-wireless.github.io/PyRIC/',
4143 download_url="https://github.com/wraith-wireless/pyric/archive/"+pyric.version+".tar.gz",
4244 author=pyric.__author__,
4345 author_email=pyric.__email__,
5658 'Topic :: Utilities',
5759 'Operating System :: POSIX :: Linux',
5860 'Programming Language :: Python',
59 'Programming Language :: Python :: 2.7'],
61 'Programming Language :: Python :: 2.7',
62 'Programming Language :: Python :: 3.0',
63 'Programming Language :: Python :: 3.5'],
6064 keywords='Linux Python nl80211 iw iwconfig ifconfig wireless WLAN WiFi pentest',
6165 packages=find_packages(),
6266 package_data={'pyric':['nlhelp/*.help','utils/data/*.txt']}
1212 usage:
1313 sudo python pyw.unittest.py -v
1414
15 Results as of 31-May-15
15 Results as of 24-July-16
16
1617 sudo python pyw.unittest.py
17 .............................................................
18 Testing PyRIC v0.1.5 pyw v0.1.8 on Python 2.7.12
19 ...................................................................................
1820 ----------------------------------------------------------------------
19 Ran 61 tests in 5.360s
21 Ran 83 tests in 5.919s
2022
2123 OK
2224
25
26 NOTE:
27 1) functions disconnect and link require a connection, they are tested/confirmed
28 manually
29 2) function devadd (and subsequently devset) are commented out. There is a
30 peculiar behavior in netlink/nl80211 (appearing in kernel 4.4.0-x) where
31 regardless of the name passed to create a new device as in
32 iw phy <phy> interface add <new dev> type <new mode>
33 pyw.devadd(<card>, <new name>, <new mode>)
34 the kernel or driver or whoever will instead assign a predicatable name
35 of the form:
36 wlx00c0ca59afa7
37 devadd has been fixed but this is currently not reflected in the below unittests
38 it has been manually tested and confirmed
2339 """
40 from __future__ import print_function # python 2to3 compability
2441
2542 #__name__ = 'pyw.unittest'
2643 __license__ = 'GPLv3'
27 __version__ = '0.0.1'
28 __date__ = 'June 2016'
44 __version__ = '0.0.3'
45 __date__ = 'July 2016'
2946 __author__ = 'Dale Patterson'
3047 __maintainer__ = 'Dale Patterson'
3148 __email__ = '[email protected]'
3350
3451 import unittest
3552 import time
53 import pyric
3654 from pyric import error
37 from pyric import pyw
38 from pyric.utils.channels import ISM_24_F2C,rf2ch
39 from pyric.net.wireless import wlan
40
55 import pyric.pyw as pyw
56 import pyric.utils.channels as channels
57 import pyric.net.wireless.wlan as wlan
58 import sys
4159
4260 # modify below to fit your system
4361 pri = {'dev':'alfa0',
4462 'mac':'00:c0:ca:59:af:a6',
45 'ifindex':4,
46 'phy':1,
63 'ifindex':18,
64 'phy':7,
65 'driver':'rt2800usb',
66 'chipset':'Ralink RT2870/3070',
4767 'mode':'managed',
4868 'tx':20,
49 'freqs':sorted(ISM_24_F2C.keys()),
69 'freqs':[2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462,2467,2472,2484],
70 #'freqs':[2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462,2467,2472,
71 # 5180,5200,5220,5240,5260,5280,5300,5320, 5500,5520,5540,5560,
72 # 5580,5600,5620,5640,5660,5680,5700,5745,5765,5785,5805, 5825],
5073 'stds':['b','g','n'],
51 'ip':'192.168.3.23',
52 'bcast':'192.168.3.63',
53 'mask':'255.255.255.192'}
74 'modes':['ibss', 'managed', 'AP', 'AP VLAN', 'wds','monitor', 'mesh'],
75 'ip':'10.0.0.2',
76 'bcast':'10.0.0.255',
77 'mask':'255.255.255.0'}
5478 newhw = '00:c0:ca:60:b0:a7'
55 newip = '192.168.3.30'
56 newbcast = '192.168.3.255'
57 newmask = '255.255.255.0'
58 nics = ['alfa0','eth0','lo','wlan0']
79 newip = '10.0.0.3'
80 nics = ['eth0','lo','wlan0','alfa0']
5981 enics = ['eth0','lo']
60 wnics = ['alfa0','wlan0']
82 wnics = ['wlan0','alfa0']
6183 inics = ['foo0','bar0']
6284 regdom = '00'
6385 newregdom = 'BO'
109131 def setUp(self): self.card = pyw.getcard(pri['dev'])
110132 def tearDown(self): pass
111133
134
112135 # test macget
113136 class MacGetTestCase(CardTestCase):
114137 def test_macget(self):
132155 self.assertRaises(error,pyw.macset,self.card,'00:0A')
133156
134157 # test inetget/inetset
135 # testing both together as the test card alfa0 is never associated thus
158 # testing both together as the test card is never associated thus
136159 # never has an ip etc
137160 # NOTE: through inetset, we get the side-effect of testing ip4set, netmaskset,
138161 # broadcastset
168191 self.assertFalse(pyw.isup(self.card))
169192 def test_invalidcardarg(self): self.assertRaises(error,pyw.down,'bad0')
170193
171 # isblocked, test only card check
194 # isblocked, test only valid card arg see below
172195 class IsBlockedTestCase(unittest.TestCase):
173196 def test_invalidcardarg(self): self.assertRaises(error,pyw.isup,'bad0')
174197
203226
204227 # test covclass
205228 # NOTE: cannot currently test set as my cards do not support it
206 # NOTEL covclassget uses phyinfo - if that works covclassget works
229 # NOTE: covclassget uses phyinfo - if that works covclassget works
207230
208231 # test get/set retryshort
209232 class RetryShortTestCase(CardTestCase):
248271 self.assertRaises(error,pyw.rtsthreshget,'bad0')
249272 self.assertRaises(error,pyw.rtsthreshset,'bad0',5)
250273 def test_invalidthresh(self):
251 self.assertRaises(error,pyw.rtsthreshset,self.card,wlan.RTS_THRESHOLD_MIN-1)
252 self.assertRaises(error,pyw.rtsthreshset,self.card,wlan.RTS_THRESHOLD_MAX+1)
274 self.assertRaises(error,pyw.rtsthreshset,self.card,wlan.RTS_THRESH_MIN-1)
275 self.assertRaises(error,pyw.rtsthreshset,self.card,wlan.RTS_THRESH_MAX+1)
253276 self.assertRaises(error, pyw.rtsthreshset,self.card,'on')
254277
255278 # test get/set RTS thresh
265288 self.assertRaises(error,pyw.fragthreshget,'bad0')
266289 self.assertRaises(error,pyw.fragthreshset,'bad0',800)
267290 def test_invalidthresh(self):
268 self.assertRaises(error,pyw.fragthreshset,self.card,wlan.FRAG_THRESHOLD_MIN-1)
269 self.assertRaises(error,pyw.fragthreshset,self.card,wlan.FRAG_THRESHOLD_MAX+1)
291 self.assertRaises(error,pyw.fragthreshset,self.card,wlan.FRAG_THRESH_MIN-1)
292 self.assertRaises(error,pyw.fragthreshset,self.card,wlan.FRAG_THRESH_MAX+1)
270293 self.assertRaises(error,pyw.fragthreshset,self.card,'on')
271294
272295 # test get freqs
273296 class DevFreqsTestCase(CardTestCase):
274297 def test_devfreqs(self):
275 self.assertItemsEqual(pri['freqs'],pyw.devfreqs(self.card))
298 self.assertListEqual(pri['freqs'],pyw.devfreqs(self.card))
276299 def test_invalidcardarg(self):
277300 self.assertRaises(error,pyw.devfreqs,'bad0')
278301
279302 # test get chs
280303 class DevCHsTestCase(CardTestCase):
281304 def test_devchs(self):
282 self.assertItemsEqual(map(rf2ch,pri['freqs']),pyw.devchs(self.card))
305 [channels.rf2ch(rf) for rf in pri['freqs']]
306 self.assertListEqual([channels.rf2ch(rf) for rf in pri['freqs']],
307 pyw.devchs(self.card))
283308 def test_invalidcardarg(self):
284309 self.assertRaises(error,pyw.devchs,'bad0')
285310
286311 # test get stds
287312 class DevSTDsTestCase(CardTestCase):
288313 def test_devchs(self):
289 self.assertItemsEqual(pri['stds'],pyw.devstds(self.card))
314 self.assertListEqual(pri['stds'],pyw.devstds(self.card))
290315 def test_invalidcardarg(self):
291316 self.assertRaises(error,pyw.devstds,'bad0')
292317
293318 # test get modes
294319 class DevModesTestCase(CardTestCase):
295320 def test_devmodes(self):
296 self.assertIn('managed',pyw.devmodes(self.card))
321 self.assertListEqual(pri['modes'],pyw.devmodes(self.card))
297322 def test_invalidcardarg(self):
298323 self.assertRaises(error,pyw.devmodes,'bad0')
299324
304329 def test_invalidcardarg(self):
305330 self.assertRaises(error,pyw.devmodes,'bad0')
306331
307 # test devinfo
332 # test devinfo - the key-value pairs of devinfo are tested via others
308333 class DevInfoTestCase(CardTestCase):
309334 def test_devinfobycard(self):
310335 self.assertIsInstance(pyw.devinfo(self.card),dict)
357382 # because freqset was already tested in chgetset, we only test invalid args
358383 class FreqSetTestCase(CardTestCase):
359384 def test_invalidrfarg(self):
360 # we test both an invalid RF and an RF the card does not support
385 # we test both an invalid RF and an RF the card does not support
361386 self.assertRaises(error,pyw.freqset,self.card,2410)
362 self.assertRaises(error,pyw.freqset,self.card,5250)
387 self.assertRaises(error,pyw.freqset,self.card,4960)
363388
364389 # test modeget
365390 class ModeGetTestCase(CardTestCase):
388413 def test_ifaces(self):
389414 self.assertIsInstance(pyw.ifaces(self.card),list)
390415 def test_invalidcardarg(self):
391 self.assertRaises(error,pyw.ifaces,'b0b0')
416 self.assertRaises(error,pyw.ifaces,'bad0')
392417
393418 # test devadd/devdel
419 """
394420 class DevAddDelTestCase(CardTestCase):
395421 def test_devadddel(self):
396422 card = pyw.devadd(self.card,'test0','monitor')
397 self.assertTrue(pyw.devdel(card))
423 self.assertTrue(card.dev in pyw.winterfaces())
424 pyw.devdel(card)
425 self.assertFalse(card.dev in pyw.winterfaces())
398426 def test_invalidcardarg(self):
399427 self.assertRaises(error,pyw.devadd,'bad0','test0','monitor')
400428 self.assertRaises(error,pyw.devdel,'bad0')
401 card = pyw.devadd(self.card,'test0','monitor')
402 pyw.devdel(card)
403 self.assertRaises(error,pyw.devdel,card)
404429 def test_invalidmodearg(self):
405430 self.assertRaises(error,pyw.devadd,self.card,'test0','foobar')
406431 def test_invalidflagsarg(self):
407432 self.assertRaises(error,pyw.devadd,self.card,'test0','monitor','foobar')
408433 self.assertRaises(error,pyw.devadd,self.card,'test0','managed','fcsfail')
409434
435 # test devset
436 class DevSetTestCase(CardTestCase):
437 def test_devset(self):
438 card = pyw.devset(self.card,'unittest0')
439 self.assertTrue(pyw.iswireless('unittest0'))
440 self.assertFalse(pyw.iswireless(pri['dev']))
441 pyw.devset(card,pri['dev'])
442 self.assertFalse(pyw.iswireless('unittest0'))
443 def test_invalidcardarg(self):
444 self.assertRaises(error,pyw.devset,'bad0','managed')
445 def test_invalidndevarg(self):
446 self.assertRaises(error,pyw.devset,self.card,None)
447 """
448 class IsConnectedTestCase(CardTestCase):
449 def test_isconnected(self):
450 self.assertFalse(pyw.isconnected(self.card))
451 def test_invalidcardarg(self):
452 self.assertRaises(error, pyw.isconnected, 'bad0')
453
454 class PhyListTestCase(unittest.TestCase):
455 def test_phylist(self):
456 self.assertTrue((pri['phy'],'phy{0}'.format(pri['phy'])) in pyw.phylist())
457
458 class IfInfoTestCase(CardTestCase):
459 def test_ifinfo(self):
460 iinfo = pyw.ifinfo(self.card)
461 self.assertTrue(pri['driver'] == iinfo['driver'])
462 self.assertTrue(pri['chipset'] == iinfo['chipset'])
463 def test_invalidcardarg(self):
464 self.assertRaises(error, pyw.ifinfo, 'bad0')
465
466 def pyvers():
467 return "{0}.{1}.{2}".format(sys.version_info.major,
468 sys.version_info.minor,
469 sys.version_info.micro)
410470 if __name__ == '__main__':
471 print("Testing PyRIC v{0} pyw v{1} on Python {2}".format(pyric.version,
472 pyw.__version__,
473 pyvers()))
411474 unittest.main()