New upstream version 0.1.6
Raphaël Hertzog
5 years ago
123 | 123 | - stainfo |
124 | 124 | - devset |
125 | 125 | - 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 ....) | |
126 | 129 | o updated nested netlink attribute handling - my understanding of it was incomplete |
127 | 130 | - There are still occasional errors |
128 | 131 | - 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 :) | |
130 | 133 | - nested attributes are now parsed correctly, any errors are a result of |
131 | 134 | incorrect packing on the other side or packet corruption and the entire |
132 | 135 | unparsed attribute will be returned. |
134 | 137 | t = (index,attribute) which (TODO #41) eases the burden on the calling |
135 | 138 | function |
136 | 139 | - 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 | |
139 | 142 | o devstds now uses phyinfo to determine standards Card supports |
140 | 143 | o completely 'remodeled' functions in pyw to take advantage of new parsing |
141 | 144 | from libnl (have left some of the error checking in place as a backup until |
143 | 146 | o fixed error on devadd during restoration in examples/pentest.py |
144 | 147 | o fixed output error, incorrect labeling |
145 | 148 | 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⏎ |
38 | 38 | activities, or otherwise in violation of any applicable law, regulation or legal |
39 | 39 | agreement. |
40 | 40 | |
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 | |
1 | 1 | include LICENSE CHANGES README.md TODO |
2 | 2 | |
3 | 3 | # Include subdirectories |
0 | # PyRIC 0.1.5: Python Radio Interface Controller | |
0 | # PyRIC 0.1.6: Python Radio Interface Controller | |
1 | 1 | ## Linux wireless library for the Python Wireless Developer and Pentester |
2 | 2 | ![](docs/logo.png?raw=true) |
3 | 3 | |
4 | 4 | [![License: GPLv3](https://img.shields.io/pypi/l/PyRIC.svg)](https://github.com/wraith-wireless/PyRIC/blob/master/LICENSE) |
5 | 5 | [![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) | |
7 | 6 | ![Supported Python Versions](https://img.shields.io/pypi/pyversions/PyRIC.svg) |
8 | 7 | ![Software status](https://img.shields.io/pypi/status/PyRIC.svg) |
9 | 8 | [![Documentation Status](https://readthedocs.org/projects/pyric/badge/?version=latest)](http://pyric.readthedocs.io/en/latest/?badge=latest) |
32 | 31 | handling the complex operations of Netlink seamlessy while maintaining a minimum |
33 | 32 | of "code walking" to understand, modify and extend. But, why stop there? Since |
34 | 33 | 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). | |
36 | 35 | |
37 | 36 | ### a. Additions to iw |
38 | 37 | Several "extensions" have been added to iw: |
40 | 39 | their own netlink (or ioctl socket) to pyw functions; |
41 | 40 | * One-time request for the nl80211 family id: pyw stores the family id in a |
42 | 41 | global variable |
43 | * Consolidating different "reference" values to wireless NICs in one class | |
42 | * Consolidate different "reference" values to wireless NICs in one class | |
44 | 43 | (Cards are tuples t=(dev,phy #,ifindex) |
45 | 44 | |
46 | 45 | These are minimal changes but they can improve the performance of any progams |
61 | 60 | halved. |
62 | 61 | |
63 | 62 | ### 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 | ||
64 | 68 | ATT, PyRIC provides the following: |
65 | 69 | * enumerate interfaces and wireless interfaces |
66 | 70 | * identify a cards driver, chipset and manufacturer |
158 | 162 | those impatient types: |
159 | 163 | |
160 | 164 | ```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 | |
163 | 167 | ``` |
164 | 168 | |
165 | 169 | will import the basic requirements and unless otherwise stated is assumed for the |
227 | 231 | Card(phy=0,dev='wlan0',ifindex=2) |
228 | 232 | ``` |
229 | 233 | |
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. | |
234 | 243 | |
235 | 244 | Before continuing you may find that a Card can become invalid. For example, I |
236 | 245 | have an older system where the USB tends to fall out. You can confirm that your |
314 | 323 | |
315 | 324 | For a brief description of coverage class and retry limits, |
316 | 325 | 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. | |
318 | 328 | |
319 | 329 | #### iv. Getting Info On Your Card |
320 | 330 | |
414 | 424 | Card(phy=0,dev=mon0,ifindex=4) |
415 | 425 | >>> pyw.winterfaces() |
416 | 426 | ['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 | |
421 | 431 | ... |
422 | 432 | (Card(phy=0,dev=mon0,ifindex=4), 'monitor') |
423 | 433 | (Card(phy=0,dev=wlan0,ifindex=3), 'managed') |
463 | 473 | >>> pyw.chset(w1, 1, None) |
464 | 474 | ``` |
465 | 475 | |
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: | |
468 | 478 | |
469 | 479 | ```bash |
470 | 480 | ?> iw dev wlan0 info # replace wlan0 with your nic |
512 | 522 | |
513 | 523 | ```python |
514 | 524 | 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 | |
517 | 527 | |
518 | 528 | def pymon(card, start=True, ch=None): |
519 | 529 | """ |
528 | 538 | if pyw.modeget(card) == 'monitor': |
529 | 539 | raise RuntimeError("Card is already in monitor mode") |
530 | 540 | 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') | |
533 | 542 | pyw.up(newcard) |
543 | if ch: pyw.chset(w1, ch, None) | |
534 | 544 | else: |
535 | 545 | if pyw.modeget(card) == 'managed': |
536 | 546 | raise RuntimeError("Card is not in monitor mode") |
537 | newcard = pyw.devset(card, card.dev[:-3) | |
547 | newcard = pyw.devset(card, card.dev[:-3]) | |
538 | 548 | pyw.modeset(newcard, 'managed') |
539 | 549 | pyw.up(newcard) |
540 | 550 | return newcard |
541 | 551 | ``` |
542 | 552 | |
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 | ||
543 | 670 | #### 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. | |
552 | 677 | |
553 | 678 | ```python |
554 | 679 | >>> pyw.isconnected(w0) |
637 | 762 | off soft blocks. |
638 | 763 | |
639 | 764 | ``` python |
640 | from pyric.utils import rfkill | |
765 | import pyric.utils.rfkill as rfkill | |
641 | 766 | |
642 | 767 | rfkill.rfkill_list() # list rfkill devices |
643 | 768 | => {'tpacpi_bluetooth_sw': {'soft': True, 'hard': False, 'type': 'bluetooth', 'idx': 1}, |
691 | 816 | - \_\_init\_\_.py initialize distrubution PyRIC module |
692 | 817 | - examples example folder |
693 | 818 | + pentest.py create wireless pentest environment example |
694 | + device_details.py display device information | |
819 | + info.py display device information | |
695 | 820 | - tests (-) test folder |
696 | 821 | + pyw.unittest.py unit test for pyw functions |
697 | 822 | - docs User Guide resources |
698 | 823 | + nlsend.png (-) image for user guide |
699 | 824 | + nlsock.png (-) image for user guide |
825 | + logo.png (-) pyric logo | |
700 | 826 | + PyRIC.tex (-) User tex file |
701 | 827 | + PyRIC.bib (-) User Guide bibliography |
702 | 828 | + PyRIC.pdf User Guide |
705 | 831 | - MANIFEST.in used by setup.py |
706 | 832 | - README.md this file |
707 | 833 | - LICENSE GPLv3 License |
834 | - CHANGES revision file | |
708 | 835 | - TODO todos for PyRIC |
709 | 836 | - pyric package directory |
710 | 837 | + \_\_init\_\_.py initialize pyric module |
729 | 856 | - nl80211_h.py nl80211 constants |
730 | 857 | - nl80211_c.py nl80211 attribute policies |
731 | 858 | - rfkill_h.py rfkill header file |
732 | - ieee80211_h.py ieee80211.h port (subset of) | |
859 | - wlan.py ieee80211.h port (subset of) | |
733 | 860 | + lib library subpackages |
734 | 861 | * \_\_init\_\_.py initialize lib subpackage |
735 | 862 | * libnl.py netlink helper functions |
736 | 863 | * libio.py sockios helper functions |
737 | 864 | + nlhelp netlinke documentation/help |
865 | * \_\_init\_\_.py initialize nlhelp subpackage | |
738 | 866 | * nsearch.py nl80211 search |
739 | 867 | * commands.help nl80211 commands help data |
740 | 868 | * attributes.help nl80211 attributes help data⏎ |
1 | 1 | o ethtool. uses ioctl but does not follow same pattern as ifconfig seems |
2 | 2 | to use |
3 | 3 | - 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) | |
6 | 5 | 11) tried NL80211_CMD_GET_WIPHY, setting _WIPHY_TX_POWER_LEVEL but did |
7 | 6 | not return the current power level - currently cannot find anything in nl80211.h |
8 | 7 | that could be used to get tx power |
15 | 14 | o slackware |
16 | 15 | o dd-wrt/OpenWRT |
17 | 16 | 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⏎ |
0 | 0 | # PyRIC root Distribution directory |
1 | 1 | # 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
18 | 18 | % |
19 | 19 | % __name__ = 'User Guide' |
20 | 20 | %__license__ = 'GPLv3' |
21 | %__version__ = '0.0.4' | |
22 | %__date__ = 'July 2016' | |
21 | %__version__ = '0.0.6' | |
22 | %__date__ = 'August 2016' | |
23 | 23 | %__author__ = 'Dale Patterson' |
24 | 24 | %__maintainer__ = 'Dale Patterson' |
25 | 25 | %__email__ = '[email protected]' |
72 | 72 | basicstyle=\footnotesize |
73 | 73 | } |
74 | 74 | |
75 | \title{\includegraphics[scale=1]{logo}\\ PyRIC v0.1.5: User Manual} | |
75 | \title{\includegraphics[scale=1]{logo}\\ PyRIC v0.1.6: User Manual} | |
76 | 76 | \author{Dale V. Patterson\\ [email protected]} |
77 | 77 | |
78 | 78 | \begin{document} |
86 | 86 | have increased dramatically in recent years. However, these tools still rely on |
87 | 87 | Linux command lines tools to setup and prepare and restore the system for use. |
88 | 88 | 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: | |
90 | 98 | \begin{enumerate} |
91 | 99 | \item \textbf{Pythonic}: No ctypes, SWIG etc. PyRIC redefines C header files as |
92 | 100 | Python and uses sockets to communicate with kernel. |
111 | 119 | While users can utilize libnl.py to communicate directly with the kernel, the |
112 | 120 | true utility of PyRIC is pyw.py. Like iw, pyw provides an interface/buffer |
113 | 121 | 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 | |
115 | 123 | experience. \\ |
116 | 124 | |
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: | |
122 | 126 | \begin{itemize} |
123 | 127 | \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, | |
124 | 138 | \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, | |
133 | 139 | \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. | |
139 | 150 | |
140 | 151 | \subsection{Background} |
141 | 152 | PyRIC arose out of a need in Wraith (https://github.com/wraith-wireless/wraith) |
184 | 195 | A Card is merely a wrapper around a tuple t = (phy index,device name,ifindex). |
185 | 196 | Since the underlying Netlink calls sometimes require the physical index, sometimes |
186 | 197 | 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: | |
191 | 202 | \begin{enumerate} |
192 | 203 | \item \textbf{pyw.getcard} returns a Card object from a given dev, |
193 | 204 | \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), | |
196 | 208 | \item \textbf{pyw.ifaces} returns a list of tuples t = (Card,mode) sharing the |
197 | 209 | same phy as a given dev. |
198 | 210 | \end{enumerate} |
316 | 328 | language=Python] |
317 | 329 | 1: import pyric # pyric error (and ecode EUNDEF) |
318 | 330 | 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) | |
365 | 355 | \end{lstlisting} |
366 | 356 | |
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. | |
389 | 381 | |
390 | 382 | \subsubsection{One-time vs Persistent Sockets} |
391 | 383 | The example in Listing \ref{lst:pentest} uses one-time sockets (netlink and |
713 | 705 | \item \textbf{pyw.getcard} returns a Card object from a given dev |
714 | 706 | \item \textbf{pyw.devinfo} returns the dict info where info['card'] is the Card |
715 | 707 | object. This function will take either a card or a dev |
708 | \item \textbf{pyw.devadd} returns a new Card object | |
716 | 709 | \item \textbf{pyw.devadd} returns a new Card object |
717 | 710 | \item \textbf{pyw.ifaces} returns a list of tuples t = (Card,mode) sharing the |
718 | 711 | same phy as a given device to do so. It is also recommended to periodically |
760 | 753 | \item retryshortget(card,[nlsock]) (iw phy card.<phy> info | grep 'retry short') |
761 | 754 | type:netlink get card's retry short limit |
762 | 755 | \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. | |
764 | 758 | \item retrylongget(card,[nlsock]) (iw phy card.<phy> info | grep 'retry long') |
765 | 759 | type:netlink get card's retry long limit |
766 | 760 | \item retrylongset(card,lim,[nlsock]) (iw phy card.<phy> set retry long <lim>) |
806 | 800 | netlink,sets the tx power to pwr (in dBm) with level setting lvl |
807 | 801 | \item txget(card,[iosock]): (iwconfig card.<dev> | grep Tx-Power card), type: |
808 | 802 | 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 | |
811 | 805 | \item chset(card,ch,chw,[nlsock]): iw phy <card.phy> set channel <ch> <chw>), |
812 | 806 | 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 | |
813 | 809 | \item freqset(card,rf,chw,[nlsock]): iw phy <card.phy> set freq <rf> <chw>), |
814 | 810 | type: netlink, set card's current frequency to rf with width chw |
815 | 811 | \item devmodes(card,[iosock]): (iw phy card.<phy>), type: netlink, get modes |
819 | 815 | \item modeget(card[nlsock]): (iw dev card.<dev> info | grep mode), type: netlink, |
820 | 816 | get card's mode |
821 | 817 | \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. | |
826 | 829 | \item devdel(card,[nlsock]): (iw card.<dev> del), type: netlink, deletes card |
827 | 830 | \begin{itemize} |
828 | 831 | \item isconnected(card, [nlsock]): (iw dev card.<dev> info | grep channel), type: |
829 | 832 | 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 | |
830 | 835 | \item disconnect(card, [nlsock]): (iw dev card.<dev> disconnect), type: netlink, |
831 | 836 | disconnects card from AP |
832 | 837 | \item link(card, [nlsock]): (iw dev card.<dev> link), type: netlink, displays |
1116 | 1121 | \end{enumerate} |
1117 | 1122 | |
1118 | 1123 | \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\\ | |
1120 | 1125 | |
1121 | 1126 | Copyright (C) 2016 Dale V. Patterson ([email protected])\\ |
1122 | 1127 |
4 | 4 | |
5 | 5 | """ |
6 | 6 | |
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 | |
9 | 10 | import pyric # pyric error (and ecode EUNDEF) |
10 | from pyric import pyw # for iw functionality | |
11 | import pyric.pyw as pyw # for iw functionality | |
11 | 12 | from pyric.utils.channels import rf2ch # rf to channel conversion |
12 | 13 | |
13 | 14 | def execute(dev,itype): |
14 | 15 | # ensure dev is a wireless interfaces |
15 | 16 | wifaces = pyw.winterfaces() |
16 | 17 | 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)) | |
18 | 19 | |
19 | 20 | # get info dicts |
20 | 21 | dinfo = pyw.devinfo(dev) |
30 | 31 | msg += "\tInet: {0} Bcast: {1} Mask: {2}\n".format(iinfo['inet'], |
31 | 32 | iinfo['bcast'], |
32 | 33 | iinfo['mask']) |
33 | print msg | |
34 | print(msg) | |
34 | 35 | |
35 | 36 | if itype == 'all' or itype == 'dev': |
36 | 37 | msg = "Device {0}\n".format(card.dev) |
45 | 46 | dinfo['RF'], |
46 | 47 | dinfo['CHW'], |
47 | 48 | dinfo['CF']) |
48 | print msg | |
49 | print(msg) | |
49 | 50 | |
50 | 51 | if itype == 'all' or itype == 'phy': |
51 | 52 | msg = "Wiphy phy{0}\n".format(card.phy) |
77 | 78 | msg += " (disabled)\n" |
78 | 79 | else: |
79 | 80 | msg += "\n" |
80 | print msg | |
81 | print(msg) | |
81 | 82 | |
82 | 83 | if __name__ == '__main__': |
83 | 84 | # 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)) | |
85 | 86 | argp = ap.ArgumentParser(description="Wireless Device Data") |
86 | 87 | argp.add_argument('-d','--dev',help="Wireless Device") |
87 | 88 | argp.add_argument('-t','--type',help="Info type one of {all|if|dev|phy}") |
88 | 89 | args = argp.parse_args() |
90 | usage = "usage: python info.py -d <dev> [-t one of {all|if|dev|phy}]" | |
89 | 91 | try: |
90 | 92 | dname = args.dev |
91 | 93 | infotype = args.type |
92 | 94 | if dname is None: |
93 | print "usage: python info.py -d <dev> [-t one of {all|if|dev|phy}]" | |
95 | print(usage) | |
94 | 96 | sys.exit(0) |
95 | 97 | if infotype is None: infotype = 'all' |
96 | 98 | 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) | |
98 | 100 | sys.exit(0) |
99 | 101 | execute(dname,infotype) |
100 | 102 | except pyric.error as e: |
101 | print e⏎ | |
103 | print(e)⏎ |
4 | 4 | |
5 | 5 | """ |
6 | 6 | |
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 | |
9 | 11 | import pyric # pyric error (and ecode EUNDEF) |
10 | from pyric import pyw # for iw functionality | |
12 | import pyric.pyw as pyw # for iw functionality | |
11 | 13 | import pyric.utils.hardware as hw # for chipset/driver |
12 | 14 | from pyric.utils.channels import rf2ch # rf to channel conversion |
13 | 15 | |
14 | 16 | def execute(dev): |
15 | print 'Setting up...' | |
17 | print('Setting up...') | |
16 | 18 | # ensure dev is a wireless interfaces |
17 | 19 | ifaces = pyw.interfaces() |
18 | 20 | wifaces = pyw.winterfaces() |
19 | 21 | 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)) | |
21 | 23 | return |
22 | 24 | 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)) | |
24 | 26 | |
25 | 27 | # get a Card & info for dev |
26 | print "Regulatory Domain currently: ", pyw.regget() | |
28 | print("Regulatory Domain currently: ", pyw.regget()) | |
27 | 29 | dinfo = pyw.devinfo(dev) |
28 | 30 | card = dinfo['card'] |
29 | 31 | pinfo = pyw.phyinfo(card) |
43 | 45 | msg += "\tSupports modes {0}\n".format(pinfo['modes']) |
44 | 46 | msg += "\tSupports commands {0}".format(pinfo['commands']) |
45 | 47 | msg += "\thw addr {0}".format(pyw.macget(card)) |
46 | print msg | |
48 | print(msg) | |
47 | 49 | |
48 | 50 | # prepare a virtual interface named pent0 in monitor mode |
49 | 51 | # 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') | |
51 | 54 | pdev = 'pent0' |
55 | pcard = pyw.devadd(card, pdev, 'monitor') | |
52 | 56 | 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])) | |
54 | 59 | pyw.devdel(iface[0]) |
60 | pyw.up(pcard) | |
61 | print("Using", pcard) | |
55 | 62 | |
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") | |
64 | 64 | pyw.chset(pcard,6,None) |
65 | 65 | 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))) | |
67 | 67 | |
68 | 68 | # DO stuff here |
69 | 69 | 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') | |
73 | 73 | while True: time.sleep(1) |
74 | 74 | except KeyboardInterrupt: |
75 | 75 | pass |
76 | 76 | |
77 | 77 | # 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) | |
80 | 81 | pyw.devdel(pcard) |
81 | ||
82 | print 'Restoring', card, 'mode =', dinfo['mode'], 'mac =', dinfo['mac'] | |
83 | card = pyw.devadd(card,card.dev,dinfo['mode']) | |
84 | 82 | pyw.macset(card,dinfo['mac']) |
85 | 83 | pyw.up(card) |
86 | print "card ", card, " restored" | |
84 | print("card ", card, " restored") | |
87 | 85 | |
88 | 86 | if __name__ == '__main__': |
89 | 87 | # 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)) | |
91 | 89 | argp = ap.ArgumentParser(description="Wireless Pentest") |
92 | 90 | argp.add_argument('-d','--dev',help="Pentesting Wireless Device") |
93 | 91 | args = argp.parse_args() |
94 | 92 | try: |
95 | 93 | dname = args.dev |
96 | 94 | if dname is None: |
97 | print "usage: python pentest.py -d <dev>" | |
95 | print("usage: python pentest.py -d <dev>") | |
96 | sys.exit(0) | |
98 | 97 | else: |
99 | 98 | execute(dname) |
100 | 99 | except pyric.error as e: |
101 | print e⏎ | |
100 | print(e)⏎ |
18 | 18 | contributors may be used to endorse or promote products derived from this |
19 | 19 | software without specific prior written permission. |
20 | 20 | |
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 * | |
23 | 26 | |
24 | 27 | Requires: |
25 | 28 | linux (3.x or 4.x kernel) |
26 | 29 | Python 2.7 |
27 | 30 | |
28 | pyric 0.1.5 | |
31 | pyric 0.1.5 through 0.1.6 | |
29 | 32 | desc: wireless nic library: wireless radio identification, manipulation, enumeration |
33 | concentrate on STA/AP related functionality | |
30 | 34 | includes: /nlhelp /lib /net /utils pyw.py |
31 | 35 | changes: |
32 | 36 | See CHANGES in top-level directory |
33 | ||
34 | ||
35 | WARNING: DO NOT import * | |
36 | ||
37 | 37 | """ |
38 | 38 | |
39 | 39 | __name__ = 'pyric' |
40 | 40 | __license__ = 'GPLv3' |
41 | __version__ = '0.1.5' | |
42 | __date__ = 'June 2016' | |
41 | __version__ = '0.1.6' | |
42 | __date__ = 'August 2016' | |
43 | 43 | __author__ = 'Dale Patterson' |
44 | 44 | __maintainer__ = 'Dale Patterson' |
45 | 45 | __email__ = '[email protected]' |
46 | 46 | __status__ = 'Production' |
47 | 47 | |
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 | ||
59 | 64 | def strerror(errno): |
60 | 65 | import os |
61 | 66 | if errno < 0: return "Undefined error" |
62 | 67 | elif errno == EPERM: return "Superuser privileges required" |
63 | 68 | 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" | |
64 | 73 | else: |
65 | 74 | return os.strerror(errno) |
66 | 75 | |
67 | 76 | # for setup.py use |
68 | 77 | # redefine version for easier access |
69 | 78 | version = __version__ |
79 | ||
70 | 80 | # define long description |
71 | 81 | long_desc = """ |
72 | # PyRIC 0.1.4: Python Radio Interface Controller | |
82 | # PyRIC 0.1.6: Python Radio Interface Controller | |
73 | 83 | ## Linux wireless library for the Python Wireless Developer and Pentester |
74 | 84 | |
75 | 85 | ## DESCRIPTION: |
90 | 100 | tools. Never worry about newer iw versions and having to rewrite your parsers. |
91 | 101 | 5. Easy: If you can use iw, you can use PyRIC. |
92 | 102 | |
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 | ||
102 | 103 | ## CURRENT STATE |
103 | 104 | ATT, PyRIC pyw provides the following: |
104 | 105 | * enumerate interfaces and wireless interfaces |
118 | 119 | * add/delete interfaces |
119 | 120 | * enumerate ISM and UNII channels |
120 | 121 | * block/unblock rfkill devices |
122 | * check 'connectivity', disconnect from AP | |
121 | 123 | |
122 | 124 | In utils, several helpers can be found that can be used to: |
123 | 125 | * enumerate channels and frequencies and convert between the two |
125 | 127 | * fetch and parse the IEEE oui text file |
126 | 128 | * further rfkill operations to include listing all rfkill devices |
127 | 129 | |
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 | """ |
63 | 63 | return ioctl(iosock.fileno(),flag,ifreq) |
64 | 64 | except (AttributeError,struct.error) as e: |
65 | 65 | # 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") | |
67 | 67 | else: raise error(errno.EINVAL,e) |
68 | 68 | except IOError as e: |
69 | 69 | # generally device cannot be found sort but can also be |
47 | 47 | import pyric.net.netlink_h as nlh |
48 | 48 | import pyric.net.genetlink_h as genlh |
49 | 49 | from pyric.net.policy import nla_datatype |
50 | import sys | |
51 | _PY3_ = sys.version_info.major == 3 | |
50 | 52 | |
51 | 53 | class error(EnvironmentError): pass |
52 | 54 | |
235 | 237 | :returns: a GENLMsg received from the socket |
236 | 238 | """ |
237 | 239 | 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 | |
242 | 243 | msg = nlmsg_fromstream(sock.recv()) |
243 | 244 | try: |
245 | # catch the follow on ack | |
244 | 246 | _ = nlmsg_fromstream(sock.recv()) |
245 | 247 | except error as e: |
248 | # on success, just return the orginal message | |
246 | 249 | if e.errno == nlh.NLE_SUCCESS: pass |
247 | 250 | 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") | |
249 | 252 | return msg |
250 | 253 | 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) | |
254 | 257 | except error as e: |
255 | 258 | if e.errno == nlh.NLE_SUCCESS: return nlh.NLE_SUCCESS |
256 | 259 | raise # rethrow |
350 | 353 | |
351 | 354 | @nltype.setter |
352 | 355 | 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)) | |
354 | 357 | self['type'] = v |
355 | 358 | |
356 | 359 | @property |
364 | 367 | |
365 | 368 | @seq.setter |
366 | 369 | 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") | |
368 | 371 | self['seq'] = v |
369 | 372 | |
370 | 373 | @property |
372 | 375 | |
373 | 376 | @pid.setter |
374 | 377 | 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") | |
376 | 379 | self['pid'] = v |
377 | 380 | |
378 | 381 | @property |
380 | 383 | |
381 | 384 | @cmd.setter |
382 | 385 | def cmd(self,v): |
383 | if v < 0: raise error(errno.ERANGE,"invalid cmd") | |
386 | if v < 0: raise error(errno.ERANGE,"Invalid cmd") | |
384 | 387 | self['cmd'] = v |
385 | 388 | |
386 | 389 | @property |
397 | 400 | for a,v,d in self['attrs']: |
398 | 401 | try: |
399 | 402 | 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 | |
402 | 405 | raise error(-1,"Packing {0} {1}: {2}".format(a,v,e)) |
403 | 406 | return nlh.nlmsghdr(len(payload),self.nltype,self.flags,self.seq,self.pid) + payload |
404 | 407 | |
440 | 443 | raise error(abs(e),strerror(abs(e))) |
441 | 444 | c,_,_ = struct.unpack_from(genlh.genl_genlmsghdr,stream,nlh.NLMSGHDRLEN) |
442 | 445 | 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)) | |
444 | 447 | |
445 | 448 | # create a new message with hdr values then parse the attributes |
446 | 449 | msg = nlmsg_new(t,c,s,p,fs) |
474 | 477 | # Note: we use unpack_from which will ignore the null bytes in numeric |
475 | 478 | # datatypes & for strings, strip trailing null bytes |
476 | 479 | # 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 | |
477 | 486 | if dt == nlh.NLA_STRING: a = _nla_strip_(a) |
478 | 487 | elif dt == nlh.NLA_U8: a = struct.unpack_from("B",a,0)[0] |
479 | 488 | elif dt == nlh.NLA_U16: a = struct.unpack_from("H",a,0)[0] |
565 | 574 | elif etype == nlh.NLA_U32: fmt = "I" |
566 | 575 | elif etype == nlh.NLA_U64: fmt = "Q" |
567 | 576 | else: |
568 | raise error(errno.EINVAL,"set elements are not valid datatype") | |
577 | raise error(errno.EINVAL,"Set elements are not valid datatype") | |
569 | 578 | esize = struct.calcsize(fmt) |
570 | 579 | |
571 | 580 | ss = [] |
578 | 587 | ss.append(s) |
579 | 588 | idx += esize |
580 | 589 | except struct.error: |
581 | raise error(errno.EINVAL,"set elements failed to unpack") | |
590 | raise error(errno.EINVAL,"Set elements failed to unpack") | |
582 | 591 | return ss |
583 | 592 | |
584 | 593 | def nla_put(msg,v,a,d): |
589 | 598 | :param a: attribute type |
590 | 599 | :param d: attribute datatype |
591 | 600 | """ |
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") | |
593 | 602 | msg['attrs'].append((a,v,d)) |
594 | 603 | |
595 | 604 | # nla_put_* append data of specified datatype |
616 | 625 | :param a: attribute type |
617 | 626 | :param d: attribute datatype |
618 | 627 | """ |
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") | |
620 | 629 | msg['attrs'][i] = (a,v,d) |
621 | 630 | |
622 | 631 | def nla_pop(msg,i): |
685 | 694 | elif d == nlh.NLA_U16: attr = struct.pack("H",v) |
686 | 695 | elif d == nlh.NLA_U32: attr = struct.pack("I",v) |
687 | 696 | 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) | |
689 | 700 | elif d == nlh.NLA_FLAG: attr = '' # a 0 sized attribute |
690 | 701 | elif d == nlh.NLA_MSECS: attr = struct.pack("Q",v) |
691 | 702 | elif d == nlh.NLA_NESTED: |
692 | 703 | # assumes a single layer of nesting |
693 | 704 | 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 | |
696 | 706 | nattr = struct.pack('H',nested[0]) + nested[1] |
697 | 707 | nattr += struct.pack("{0}x".format(nlh.NLMSG_ALIGNBY(len(nattr)))) |
698 | 708 | 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 | |
704 | 709 | else: |
705 | 710 | fmt = "" # appease PyCharm |
706 | 711 | if d == nlh.NLA_SET_U8: fmt = "B" |
31 | 31 | |
32 | 32 | """ |
33 | 33 | |
34 | #__name__ = 'genetlink_h.py' | |
34 | __name__ = 'genetlink_h' | |
35 | 35 | __license__ = 'GPLv3' |
36 | 36 | __version__ = '0.0.1' |
37 | 37 | __date__ = 'March 2016' |
57 | 57 | __status__ = 'Production' |
58 | 58 | |
59 | 59 | 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 | |
61 | 63 | |
62 | 64 | IFNAMSIZ = 16 |
63 | 65 | IFALIASZ = 256 |
151 | 153 | IF_LINK_MODE_DEFAULT = 0 |
152 | 154 | IF_LINK_MODE_DORMANT = 1 # limit upward transition to dormant |
153 | 155 | |
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 | """ | |
164 | 167 | AF_UNSPEC = 0 # from socket.h sa_family unspecified |
165 | 168 | ARPHRD_ETHER = 1 # from net/if_arp.h sa_family ethernet a.k.a AF_LOCAL |
166 | 169 | ARPHRD_IEEE80211 = 801 # net/if_arp.h sa_family IEEE 802.11 |
188 | 191 | raise AttributeError("sa_family {0} not supported".format(sa_family)) |
189 | 192 | return struct.pack(sa_addr,*vs) |
190 | 193 | |
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 | |
231 | 234 | ifr_flags = 'h' |
232 | 235 | ifr_ifindex = 'i' |
233 | 236 | ifr_iwname = '{0}s'.format(256-IFNAMSIZ) # dirty hack to get an unknown string back |
254 | 257 | NOTE: ifreq will return AttributeError for any caught exception |
255 | 258 | """ |
256 | 259 | # pack the nic |
260 | if _PY3_: ifrn = bytes(ifrn,'ascii') | |
257 | 261 | try: |
258 | 262 | # NOTE: don't need to keep the name to 16 chars as struct does it for us |
259 | 263 | ifr = struct.pack(ifr_name,ifrn) |
262 | 266 | |
263 | 267 | try: |
264 | 268 | if not ifru: pass # only pass the device name |
265 | elif ifru == sioc.SIOCGIFHWADDR: # get hwaddr | |
269 | elif ifru == sioch.SIOCGIFHWADDR: # get hwaddr | |
266 | 270 | ifr += sockaddr(ARPHRD_ETHER,None) |
267 | elif ifru == sioc.SIOCSIFHWADDR: # set hwaddr | |
271 | elif ifru == sioch.SIOCSIFHWADDR: # set hwaddr | |
268 | 272 | 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 | |
272 | 276 | 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 | |
276 | 280 | ifr += sockaddr(AF_INET,param[0]) |
277 | elif ifru == sioc.SIOCGIFFLAGS: # get flags | |
281 | elif ifru == sioch.SIOCGIFFLAGS: # get flags | |
278 | 282 | ifr += struct.pack('{0}x'.format(IFFLAGLEN)) |
279 | elif ifru == sioc.SIOCSIFFLAGS: # set flags | |
283 | elif ifru == sioch.SIOCSIFFLAGS: # set flags | |
280 | 284 | ifr += struct.pack(ifr_flags,param[0]) |
281 | elif ifru == sioc.SIOCGIFINDEX: # get if index | |
285 | elif ifru == sioch.SIOCGIFINDEX: # get if index | |
282 | 286 | ifr += struct.pack('{0}x'.format(IFIFINDEXLEN)) |
283 | elif ifru == sioc.SIOCGIWNAME: # get iw name | |
287 | elif ifru == sioch.SIOCGIWNAME: # get iw name | |
284 | 288 | ifr += struct.pack('{0}x'.format(IWNAMELEN)) |
285 | elif ifru == sioc.SIOCGIWTXPOW: # get tx pwr | |
289 | elif ifru == sioch.SIOCGIWTXPOW: # get tx pwr | |
286 | 290 | ifr += struct.pack('{0}x'.format(IWTXPWRLEN)) |
287 | 291 | else: |
288 | 292 | raise AttributeError("ifru {0} not supported".format(ifru)) |
33 | 33 | |
34 | 34 | """ |
35 | 35 | |
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' | |
41 | 37 | __license__ = 'GPLv3' |
42 | 38 | __version__ = '0.0.3' |
43 | 39 | __date__ = 'March 2016' |
331 | 327 | |
332 | 328 | # defined error codes |
333 | 329 | # only use success and failure -> using errno for other error numbers |
334 | NLE = ['Success','Unspecified failure'] | |
335 | 330 | NLE_SUCCESS = 0 |
336 | 331 | NLE_FAILURE = 1⏎ |
18 | 18 | contributors may be used to endorse or promote products derived from this |
19 | 19 | software without specific prior written permission. |
20 | 20 | |
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 | |
22 | 22 | |
23 | 23 | Std will refer to IEEE Std 802.11-2012 |
24 | 24 |
49 | 49 | try: |
50 | 50 | # first three lines are comments, 4th line is empty |
51 | 51 | cin = open(cmdpath,'r') |
52 | for _ in xrange(4): _in = cin.readline() | |
52 | for _ in range(4): _in = cin.readline() | |
53 | 53 | commands = json.loads(cin.readline()) |
54 | 54 | cmdlookup = json.loads(cin.readline()) |
55 | 55 | except: |
64 | 64 | try: |
65 | 65 | # first three lines are comments, 3th line is empty |
66 | 66 | ain = open(attrpath,'r') |
67 | for _ in xrange(4): _in = ain.readline() | |
67 | for _ in range(4): _in = ain.readline() | |
68 | 68 | attributes = json.loads(ain.readline()) |
69 | 69 | attrlookup = json.loads(ain.readline()) |
70 | 70 | except: |
0 | 0 | #!/usr/bin/env python |
1 | 1 | |
2 | """ pyw.py: python iw | |
2 | """ pyw.py: Linux wireless library for the Python Wireless Developer and Pentester | |
3 | 3 | |
4 | 4 | Copyright (C) 2016 Dale V. Patterson ([email protected]) |
5 | 5 | |
62 | 62 | devadd which will accept a Card or a phy |
63 | 63 | 2) All functions allow pyric errors to pass through. Callers must catch these |
64 | 64 | if they desire |
65 | ||
66 | 65 | """ |
67 | 66 | |
68 | 67 | __name__ = 'pyw' |
69 | 68 | __license__ = 'GPLv3' |
70 | __version__ = '0.1.8' | |
71 | __date__ = 'July 2016' | |
69 | __version__ = '0.1.9' | |
70 | __date__ = 'August 2016' | |
72 | 71 | __author__ = 'Dale Patterson' |
73 | 72 | __maintainer__ = 'Dale Patterson' |
74 | 73 | __email__ = '[email protected]' |
75 | 74 | __status__ = 'Production' |
76 | 75 | |
77 | 76 | import struct # ioctl unpacking |
77 | import re # check addr validity | |
78 | 78 | import pyric # pyric exception |
79 | import re # check addr validity | |
80 | 79 | 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 | |
83 | 82 | 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 | |
85 | 84 | import pyric.net.netlink_h as nlh # netlink definition |
86 | 85 | import pyric.net.genetlink_h as genlh # genetlink definition |
87 | 86 | 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 | |
89 | 89 | import pyric.net.sockios_h as sioch # sockios constants |
90 | 90 | 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 | |
93 | 92 | |
94 | 93 | _FAM80211ID_ = None |
95 | 94 | |
159 | 158 | return _iostub_(iswireless, dev) |
160 | 159 | |
161 | 160 | try: |
162 | # if the call succeeds, found to be wireless | |
161 | # if the call succeeds, dev is found to be wireless | |
163 | 162 | _ = io.io_transfer(iosock, sioch.SIOCGIWNAME, ifh.ifreq(dev)) |
164 | 163 | return True |
165 | 164 | except AttributeError as e: |
167 | 166 | except io.error as e: |
168 | 167 | # ENODEV or ENOTSUPP means not wireless, reraise any others |
169 | 168 | 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) | |
171 | 170 | |
172 | 171 | def phylist(): |
173 | 172 | """ :returns: a list of tuples t = (physical indexe, physical name) """ |
174 | 173 | # we could walk the directory /sys/class/ieee80211 as well but we'll |
175 | 174 | # let rfkill do it (just in case the above path differs across distros or |
176 | # in future upgrades | |
175 | # in future upgrades) | |
177 | 176 | phys = [] |
178 | 177 | rfdevs = rfkill.rfkill_list() |
179 | 178 | for rfk in rfdevs: |
209 | 208 | :param rd: regulatory domain code |
210 | 209 | :param argv: netlink socket at argv[0] (or empty) |
211 | 210 | """ |
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 | ||
214 | 213 | try: |
215 | 214 | nlsock = argv[0] |
216 | 215 | except IndexError: |
242 | 241 | def __new__(cls, p, d, i): |
243 | 242 | return super(Card, cls).__new__(cls, tuple((p, d, i))) |
244 | 243 | 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) | |
248 | 245 | @property |
249 | 246 | def phy(self): return self[0] |
250 | 247 | @property |
256 | 253 | """ |
257 | 254 | get the Card object from device name |
258 | 255 | :param dev: device name |
256 | :param argv: netlink socket at argv[0] or empty | |
259 | 257 | :returns: a Card with device name dev |
260 | 258 | """ |
261 | 259 | try: |
323 | 321 | :param argv: ioctl socket at argv[0] (or empty) |
324 | 322 | :returns: mac address after operation |
325 | 323 | """ |
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") | |
327 | 325 | |
328 | 326 | try: |
329 | 327 | iosock = argv[0] |
637 | 635 | idx = rfkill.getidx(card.phy) |
638 | 636 | return rfkill.soft_blocked(idx), rfkill.hard_blocked(idx) |
639 | 637 | except AttributeError: |
640 | raise pyric.error(pyric.ENODEV, "Card is no longer regsitered") | |
638 | raise pyric.error(pyric.ENODEV, "Card is no longer registered") | |
641 | 639 | |
642 | 640 | def block(card): |
643 | 641 | """ |
659 | 657 | idx = rfkill.getidx(card.phy) |
660 | 658 | rfkill.rfkill_unblock(idx) |
661 | 659 | except AttributeError: |
662 | raise pyric.error(pyric.ENODEV, "Card no longer registered") | |
660 | raise pyric.error(pyric.ENODEV, "Card is no longer registered") | |
663 | 661 | |
664 | 662 | ################################################################################ |
665 | 663 | #### RADIO PROPERTIES #### |
716 | 714 | except AttributeError: |
717 | 715 | raise pyric.error(pyric.EINVAL, "Invalid Card") |
718 | 716 | except ValueError: |
719 | raise pyric.error(pyric.EINVAL, "Invalid parameter on") | |
717 | raise pyric.error(pyric.EINVAL, "Invalid parameter {0} for on".format(on)) | |
720 | 718 | except nl.error as e: |
721 | 719 | raise pyric.error(e.errno, e.strerror) |
722 | 720 | |
736 | 734 | |
737 | 735 | def covclassset(card, cc, *argv): |
738 | 736 | """ |
739 | REQUIRES ROOT PRIVILEGES | |
737 | REQUIRES ROOT PRIVILEGES/DOES NOT WORK ON ALL SYSTEMS | |
740 | 738 | sets the coverage class. The coverage class IAW IEEE Std 802.11-2012 is |
741 | 739 | defined as the Air propagation time & together with max tx power control |
742 | 740 | the BSS diamter |
748 | 746 | if cc < wlan.COV_CLASS_MIN or cc > wlan.COV_CLASS_MAX: |
749 | 747 | # this can work 'incorrectly' on non-int values but these will |
750 | 748 | # 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) | |
754 | 752 | |
755 | 753 | try: |
756 | 754 | nlsock = argv[0] |
768 | 766 | except AttributeError: |
769 | 767 | raise pyric.error(pyric.EINVAL, "Invalid Card") |
770 | 768 | 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)) | |
772 | 770 | except nl.error as e: |
773 | 771 | raise pyric.error(e.errno, e.strerror) |
774 | 772 | |
793 | 791 | :param card: Card object |
794 | 792 | :param lim: max # of short retries 1 - 255 |
795 | 793 | :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 | |
797 | 796 | """ |
798 | 797 | if lim < wlan.RETRY_MIN or lim > wlan.RETRY_MAX: |
799 | 798 | # this can work 'incorrectly' on non-int values but these will |
800 | 799 | # 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) | |
804 | 803 | |
805 | 804 | try: |
806 | 805 | nlsock = argv[0] |
818 | 817 | except AttributeError: |
819 | 818 | raise pyric.error(pyric.EINVAL, "Invalid Card") |
820 | 819 | 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)) | |
822 | 821 | except nl.error as e: |
823 | 822 | raise pyric.error(e.errno, e.strerror) |
824 | 823 | |
843 | 842 | :param card: Card object |
844 | 843 | :param lim: max # of short retries 1 - 255 |
845 | 844 | :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 | |
847 | 847 | """ |
848 | 848 | if lim < wlan.RETRY_MIN or lim > wlan.RETRY_MAX: |
849 | 849 | # this can work 'incorrectly' on non-int values but these will |
850 | 850 | # 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) | |
854 | 854 | |
855 | 855 | try: |
856 | 856 | nlsock = argv[0] |
868 | 868 | except AttributeError: |
869 | 869 | raise pyric.error(pyric.EINVAL, "Invalid Card") |
870 | 870 | 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)) | |
872 | 872 | except nl.error as e: |
873 | 873 | raise pyric.error(e.errno, e.strerror) |
874 | 874 | |
899 | 899 | if thresh == 'off': thresh = wlan.RTS_THRESH_OFF |
900 | 900 | elif thresh == wlan.RTS_THRESH_OFF: pass |
901 | 901 | 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) | |
905 | 905 | |
906 | 906 | try: |
907 | 907 | nlsock = argv[0] |
919 | 919 | except AttributeError: |
920 | 920 | raise pyric.error(pyric.EINVAL, "Invalid Card") |
921 | 921 | 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)) | |
923 | 923 | except nl.error as e: |
924 | 924 | raise pyric.error(e.errno, e.strerror) |
925 | 925 | |
950 | 950 | if thresh == 'off': thresh = wlan.FRAG_THRESH_OFF |
951 | 951 | elif thresh == wlan.FRAG_THRESH_OFF: pass |
952 | 952 | 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) | |
956 | 956 | |
957 | 957 | try: |
958 | 958 | nlsock = argv[0] |
988 | 988 | except IndexError: |
989 | 989 | return _nlstub_(devfreqs, card) |
990 | 990 | |
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 | |
992 | 997 | |
993 | 998 | def devchs(card, *argv): |
994 | 999 | """ |
1002 | 1007 | except IndexError: |
1003 | 1008 | return _nlstub_(devchs, card) |
1004 | 1009 | |
1005 | return map(channels.rf2ch, phyinfo(card, nlsock)['freqs']) | |
1010 | return [channels.rf2ch(rf) for rf in devfreqs(card,nlsock)] | |
1006 | 1011 | |
1007 | 1012 | def devstds(card, *argv): |
1008 | 1013 | """ |
1113 | 1118 | except IndexError: |
1114 | 1119 | return _nlstub_(devinfo, card) |
1115 | 1120 | |
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 | |
1125 | 1132 | msg = nl.nlmsg_new(nltype=_familyid_(nlsock), |
1126 | 1133 | cmd=nl80211h.NL80211_CMD_GET_INTERFACE, |
1127 | 1134 | flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK) |
1128 | 1135 | nl.nla_put_u32(msg, idx, nl80211h.NL80211_ATTR_IFINDEX) |
1129 | 1136 | nl.nl_sendmsg(nlsock, msg) |
1130 | 1137 | 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) | |
1131 | 1141 | 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") | |
1132 | 1151 | raise pyric.error(e.errno, e.strerror) |
1133 | 1152 | |
1134 | 1153 | # pull out attributes |
1277 | 1296 | _ = nl.nl_recvmsg(nlsock) |
1278 | 1297 | except ValueError: |
1279 | 1298 | # 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)) | |
1281 | 1300 | except AttributeError: |
1282 | 1301 | raise pyric.error(pyric.EINVAL, "Invalid Card") |
1283 | 1302 | except nl.error as e: |
1334 | 1353 | :param ch: channel number |
1335 | 1354 | :param chw: channel width oneof {[None|'HT20'|'HT40-'|'HT40+'} |
1336 | 1355 | :param argv: netlink socket at argv[0] (or empty) |
1337 | :returns: True on success | |
1338 | 1356 | 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 | """ | |
1348 | 1360 | try: |
1349 | 1361 | nlsock = argv[0] |
1350 | 1362 | except IndexError: |
1351 | 1363 | return _nlstub_(chset, card, ch, chw) |
1352 | 1364 | |
1353 | 1365 | 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'] | |
1354 | 1381 | |
1355 | 1382 | def freqset(card, rf, chw=None, *argv): |
1356 | 1383 | """ |
1360 | 1387 | :param rf: frequency |
1361 | 1388 | :param chw: channel width oneof {[None|'HT20'|'HT40-'|'HT40+'} |
1362 | 1389 | :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 | """ | |
1368 | 1394 | try: |
1369 | 1395 | nlsock = argv[0] |
1370 | 1396 | except IndexError: |
1371 | 1397 | return _nlstub_(freqset, card, rf, chw) |
1372 | 1398 | |
1373 | 1399 | try: |
1400 | chw = channels.CHTYPES.index(chw) | |
1374 | 1401 | msg = nl.nlmsg_new(nltype=_familyid_(nlsock), |
1375 | 1402 | cmd=nl80211h.NL80211_CMD_SET_WIPHY, |
1376 | 1403 | flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK) |
1379 | 1406 | nl.nla_put_u32(msg, chw, nl80211h.NL80211_ATTR_WIPHY_CHANNEL_TYPE) |
1380 | 1407 | nl.nl_sendmsg(nlsock, msg) |
1381 | 1408 | _ = nl.nl_recvmsg(nlsock) |
1409 | except ValueError: | |
1410 | raise pyric.error(pyric.EINVAL, "Invalid channel width") | |
1382 | 1411 | except AttributeError: |
1383 | 1412 | raise pyric.error(pyric.EINVAL, "Invalid Card") |
1384 | 1413 | except nl.error as e: |
1414 | if e.errno == pyric.EBUSY: raise pyric.error(e.errno,pyric.strerror(e.errno)) | |
1385 | 1415 | raise pyric.error(e.errno, e.strerror) |
1386 | 1416 | |
1387 | 1417 | #### INTERFACE & MODE RELATED #### |
1483 | 1513 | set a new dev. |
1484 | 1514 | o this is not a true set name: it adds a new card with ndev as the dev then |
1485 | 1515 | 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 | |
1487 | 1517 | have a new ifindex |
1488 | 1518 | """ |
1489 | 1519 | try: |
1508 | 1538 | def devadd(card, vdev, mode, flags=None, *argv): |
1509 | 1539 | """ |
1510 | 1540 | 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 | |
1511 | 1627 | adds a virtual interface on device having type mode (iw phy <card.phy> |
1512 | 1628 | interface add <vnic> type <mode> |
1513 | 1629 | :param card: Card object or physical index |
1519 | 1635 | |'cook'|'active'} |
1520 | 1636 | :param argv: netlink socket at argv[0] (or empty) |
1521 | 1637 | :returns: the new Card |
1638 | NOTE: the new Card will be 'down' | |
1522 | 1639 | """ |
1523 | 1640 | if mode not in IFTYPES: raise pyric.error(pyric.EINVAL, 'Invalid mode') |
1524 | 1641 | if flags: |
1532 | 1649 | try: |
1533 | 1650 | nlsock = argv[0] |
1534 | 1651 | 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 | |
1538 | 1655 | try: |
1539 | 1656 | phy = card.phy |
1540 | 1657 | except AttributeError: |
1558 | 1675 | except nl.error as e: |
1559 | 1676 | raise pyric.error(e.errno, e.strerror) |
1560 | 1677 | |
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)) | |
1588 | 1682 | |
1589 | 1683 | ################################################################################ |
1590 | 1684 | #### STA FUNCTIONS #### |
1604 | 1698 | # dirty hack - using the precence of an RF to determine connected-ness |
1605 | 1699 | return devinfo(card, nlsock)['RF'] is not None |
1606 | 1700 | |
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 | ||
1607 | 1735 | def disconnect(card, *argv): |
1608 | 1736 | """ |
1609 | 1737 | REQUIRES ROOT PRIVILEGES |
1610 | 1738 | disconnect the card from an AP |
1611 | 1739 | :param card: Card object |
1612 | 1740 | :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 | |
1614 | 1743 | """ |
1615 | 1744 | try: |
1616 | 1745 | nlsock = argv[0] |
1697 | 1826 | if idx == nl80211h.NL80211_BSS_SIGNAL_MBM: |
1698 | 1827 | info['rss'] = struct.unpack_from('i', attr, 0)[0] / 100 |
1699 | 1828 | 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 | """ | |
1708 | 1840 | try: |
1709 | 1841 | l = struct.unpack_from('>H', attr, 0)[0] # have to change the format |
1710 | 1842 | info['ssid'] = struct.unpack_from('{0}s'.format(l), attr, 2)[0] |
1797 | 1929 | 'tx-bitrate':{}, 'rx-bitrate':{}} |
1798 | 1930 | |
1799 | 1931 | _, bs, d = nl.nla_find(rmsg, nl80211h.NL80211_ATTR_STA_INFO, False) |
1932 | if d == nlh.NLA_ERROR: return info | |
1800 | 1933 | for sidx, sattr in bs: # sidx indexes the enum nl80211_sta_info |
1801 | 1934 | try: |
1802 | 1935 | if sidx == nl80211h.NL80211_STA_INFO_RX_BYTES: |
1830 | 1963 | |
1831 | 1964 | |
1832 | 1965 | 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]) | |
1835 | 1975 | |
1836 | 1976 | def _hex2mac_(v): |
1837 | 1977 | """ |
1838 | 1978 | :param v: packed bytestream of form \xd8\xc7\xc8\x00\x11\x22 |
1839 | 1979 | :returns: a ':' separated mac address from byte stream v |
1840 | 1980 | """ |
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]) | |
1842 | 1986 | |
1843 | 1987 | def _mac2hex_(v): |
1844 | 1988 | """ |
2106 | 2250 | :returns: list of supported commands as strings |
2107 | 2251 | """ |
2108 | 2252 | 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 | |
2110 | 2254 | 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 | |
2117 | 2260 | cmd = cmdbynum(struct.unpack_from('I', cmd, 0)[0]) |
2118 | 2261 | if type(cmd) is type([]): cmd = cmd[0] |
2119 | 2262 | cs.append(cmd[13:].lower()) # skip NL80211_CMD_ |
2202 | 2345 | raise pyric.error(pyric.EINVAL, e) |
2203 | 2346 | except struct.error as e: |
2204 | 2347 | 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) | |
2207 | 2348 | |
2208 | 2349 | def _familyid_(nlsock): |
2209 | 2350 | """ |
2296 | 2437 | nl.nla_put_u32(msg, channels.ch2rf(ch), nl80211h.NL80211_ATTR_WIPHY_FREQ) |
2297 | 2438 | nl.nla_put_u32(msg, channels.CHTYPES.index(chw), nl80211h.NL80211_ATTR_WIPHY_CHANNEL_TYPE) |
2298 | 2439 | nl.nl_sendmsg(nlsock, msg) |
2299 | _ = nl.nl_recvmsg(nlsock)⏎ | |
2440 | _ = nl.nl_recvmsg(nlsock) |
20 | 20 | |
21 | 21 | utils 0.0.1 |
22 | 22 | 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 | |
24 | 24 | changes: |
25 | 25 | o added mac address related to hardware.py |
26 | 26 | o randhw does not force an ouis dict, if not present, randomly generates the |
37 | 37 | import pyric.net.wireless.nl80211_h as nl80211h |
38 | 38 | |
39 | 39 | # 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 | |
42 | 42 | |
43 | 43 | # ISM Bands (ieee80211.h-> BAND_ID_2G) |
44 | 44 | ISM_24_C2F={1:2412,2:2417,3:2422,4:2427,5:2432,6:2437,7:2442, |
47 | 47 | 2447:8,2417:2,2452:9,2422:3,2457:10,2427:4,2462:11} |
48 | 48 | |
49 | 49 | # 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, | |
50 | 52 | 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, | |
52 | 54 | 102:5510,104:5520,106:5530,108:5540,110:5550,112:5560,114:5570,116:5580, |
53 | 55 | 118:5590,120:5600,122:5610,124:5620,126:5630,128:5640,132:5660,136:5680, |
54 | 56 | 138:5690,140:5700,142:5710,144:5720,149:5745,151:5755,153:5765,155:5775, |
55 | 57 | 157:5785,159:5795,161:5805,165:5825} |
56 | 58 | 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} | |
62 | 64 | |
63 | 65 | # UNII 4 Bands (ieee80211.h-> BAND_ID_5G) |
64 | 66 | UNII_4_C2F={183:4915,184:4920,185:4925,187:4935,188:4940,189:4945,192:4960,196:4980} |
69 | 71 | #134 3672.5 134 3670.0 135 3677.5 136 3682.5 136 3680.0 |
70 | 72 | #137 3687.5 137 3685.0 138 3689.5 138 3690.0 |
71 | 73 | |
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())) | |
75 | 90 | |
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()) | |
78 | 102 | return sorted(ISM_24_F2C.keys() + UNII_5_F2C.keys()+ UNII_4_F2C.keys()) |
79 | 103 | |
80 | 104 | def ch2rf(c): |
97 | 121 | if f in ISM_24_F2C: return ISM_24_F2C[f] |
98 | 122 | if f in UNII_5_F2C: return UNII_5_F2C[f] |
99 | 123 | if f in UNII_4_F2C: return UNII_4_F2C[f] |
100 | return None⏎ | |
124 | return None |
71 | 71 | :returns: random hw address |
72 | 72 | """ |
73 | 73 | 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)]) | |
75 | 75 | else: |
76 | 76 | 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)]) | |
78 | 78 | return o + ':' + u |
79 | 79 | |
80 | 80 | def ifcard(dev): |
22 | 22 | Fetchs and stores oui data from IEEE |
23 | 23 | |
24 | 24 | """ |
25 | from __future__ import print_function # python 2to3 compability | |
25 | 26 | |
26 | #__name__ = 'ouifetch' | |
27 | __name__ = 'ouifetch' | |
27 | 28 | __license__ = 'GPLv3' |
28 | __version__ = '0.0.1' | |
29 | __date__ = 'August 2014' | |
29 | __version__ = '0.0.2' | |
30 | __date__ = 'July 2016' | |
30 | 31 | __author__ = 'Dale Patterson' |
31 | 32 | __maintainer__ = 'Dale Patterson' |
32 | 33 | __email__ = '[email protected]' |
33 | 34 | __status__ = 'Production' |
34 | 35 | |
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 | |
37 | 46 | import pyric |
38 | 47 | |
39 | 48 | OUIURL = 'http://standards-oui.ieee.org/oui.txt' |
74 | 83 | # determine if data path is legit |
75 | 84 | if opath is None: opath = OUIPATH |
76 | 85 | 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)) | |
78 | 87 | sys.exit(1) |
79 | 88 | |
80 | 89 | # fetch oui file from ieee |
81 | 90 | fout = None |
82 | 91 | |
83 | 92 | # set up url request |
84 | req = urllib2.Request(OUIURL) | |
93 | req = url_request(OUIURL) | |
85 | 94 | req.add_header('User-Agent',"PyRIC +https://github.com/wraith-wireless/PyRIC/") |
86 | 95 | try: |
87 | 96 | # 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") | |
91 | 100 | |
92 | if verbose: print "Opening data file {0} for writing".format(opath) | |
101 | if verbose: print("Opening data file {0} for writing".format(opath)) | |
93 | 102 | fout = open(opath,'w') |
94 | 103 | gen = datetime.datetime.utcnow().isoformat() # use current time as the first line |
95 | 104 | fout.write(gen+'\n') |
109 | 118 | # write to file & update count |
110 | 119 | fout.write('{0}\t{1}\n'.format(oui,manuf)) |
111 | 120 | 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)) | |
116 | 125 | except IOError as e: |
117 | print "Error opening output file {0}".format(e) | |
126 | print("Error opening output file {0}".format(e)) | |
118 | 127 | except Exception as e: |
119 | print "Error parsing oui file: {0}".format(e) | |
128 | print("Error parsing oui file: {0}".format(e)) | |
120 | 129 | finally: |
121 | 130 | if fout: fout.close() |
122 | 131 |
44 | 44 | import pyric |
45 | 45 | import errno |
46 | 46 | import pyric.net.wireless.rfkill_h as rfkh |
47 | import sys | |
48 | _PY3_ = sys.version_info.major == 3 | |
47 | 49 | |
48 | 50 | RFKILL_STATE = [False,True] # Unblocked = 0, Blocked = 1 |
49 | 51 | |
69 | 71 | fcntl.fcntl(fin.fileno(),fcntl.F_SETFL,flags|os.O_NONBLOCK) |
70 | 72 | while True: |
71 | 73 | 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) | |
74 | 80 | if op == rfkh.RFKILL_OP_ADD: |
75 | 81 | rfks[getname(idx)] = {'idx':idx, |
76 | 82 | 'type':rfkh.RFKILL_TYPES[t], |
91 | 97 | fout = None |
92 | 98 | try: |
93 | 99 | rfke = rfkh.rfkill_event(idx,rfkh.RFKILL_TYPE_ALL,rfkh.RFKILL_OP_CHANGE,1,0) |
100 | if _PY3_: rfke = rfke.decode('ascii') | |
94 | 101 | fout = open(dpath, 'w') |
95 | 102 | fout.write(rfke) |
96 | 103 | except struct.error as e: |
0 | # pip installation and distribution | |
0 | # pip installation and distribution sudo pip install PyRIC | |
1 | 1 | |
2 | 2 | [bdist_wheel] |
3 | 3 | universal=1⏎ |
19 | 19 | contributors may be used to endorse or promote products derived from this |
20 | 20 | software without specific prior written permission. |
21 | 21 | |
22 | sudo pip install PyRIC | |
23 | ||
22 | 24 | """ |
23 | 25 | |
24 | 26 | #__name__ = 'setup' |
37 | 39 | version=pyric.version, |
38 | 40 | description="Python Wireless Library", |
39 | 41 | long_description=pyric.long_desc, |
40 | url='https://github.com/wraith-wireless/PyRIC/', | |
42 | url='http://wraith-wireless.github.io/PyRIC/', | |
41 | 43 | download_url="https://github.com/wraith-wireless/pyric/archive/"+pyric.version+".tar.gz", |
42 | 44 | author=pyric.__author__, |
43 | 45 | author_email=pyric.__email__, |
56 | 58 | 'Topic :: Utilities', |
57 | 59 | 'Operating System :: POSIX :: Linux', |
58 | 60 | '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'], | |
60 | 64 | keywords='Linux Python nl80211 iw iwconfig ifconfig wireless WLAN WiFi pentest', |
61 | 65 | packages=find_packages(), |
62 | 66 | package_data={'pyric':['nlhelp/*.help','utils/data/*.txt']} |
12 | 12 | usage: |
13 | 13 | sudo python pyw.unittest.py -v |
14 | 14 | |
15 | Results as of 31-May-15 | |
15 | Results as of 24-July-16 | |
16 | ||
16 | 17 | sudo python pyw.unittest.py |
17 | ............................................................. | |
18 | Testing PyRIC v0.1.5 pyw v0.1.8 on Python 2.7.12 | |
19 | ................................................................................... | |
18 | 20 | ---------------------------------------------------------------------- |
19 | Ran 61 tests in 5.360s | |
21 | Ran 83 tests in 5.919s | |
20 | 22 | |
21 | 23 | OK |
22 | 24 | |
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 | |
23 | 39 | """ |
40 | from __future__ import print_function # python 2to3 compability | |
24 | 41 | |
25 | 42 | #__name__ = 'pyw.unittest' |
26 | 43 | __license__ = 'GPLv3' |
27 | __version__ = '0.0.1' | |
28 | __date__ = 'June 2016' | |
44 | __version__ = '0.0.3' | |
45 | __date__ = 'July 2016' | |
29 | 46 | __author__ = 'Dale Patterson' |
30 | 47 | __maintainer__ = 'Dale Patterson' |
31 | 48 | __email__ = '[email protected]' |
33 | 50 | |
34 | 51 | import unittest |
35 | 52 | import time |
53 | import pyric | |
36 | 54 | 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 | |
41 | 59 | |
42 | 60 | # modify below to fit your system |
43 | 61 | pri = {'dev':'alfa0', |
44 | 62 | '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', | |
47 | 67 | 'mode':'managed', |
48 | 68 | '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], | |
50 | 73 | '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'} | |
54 | 78 | 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'] | |
59 | 81 | enics = ['eth0','lo'] |
60 | wnics = ['alfa0','wlan0'] | |
82 | wnics = ['wlan0','alfa0'] | |
61 | 83 | inics = ['foo0','bar0'] |
62 | 84 | regdom = '00' |
63 | 85 | newregdom = 'BO' |
109 | 131 | def setUp(self): self.card = pyw.getcard(pri['dev']) |
110 | 132 | def tearDown(self): pass |
111 | 133 | |
134 | ||
112 | 135 | # test macget |
113 | 136 | class MacGetTestCase(CardTestCase): |
114 | 137 | def test_macget(self): |
132 | 155 | self.assertRaises(error,pyw.macset,self.card,'00:0A') |
133 | 156 | |
134 | 157 | # 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 | |
136 | 159 | # never has an ip etc |
137 | 160 | # NOTE: through inetset, we get the side-effect of testing ip4set, netmaskset, |
138 | 161 | # broadcastset |
168 | 191 | self.assertFalse(pyw.isup(self.card)) |
169 | 192 | def test_invalidcardarg(self): self.assertRaises(error,pyw.down,'bad0') |
170 | 193 | |
171 | # isblocked, test only card check | |
194 | # isblocked, test only valid card arg see below | |
172 | 195 | class IsBlockedTestCase(unittest.TestCase): |
173 | 196 | def test_invalidcardarg(self): self.assertRaises(error,pyw.isup,'bad0') |
174 | 197 | |
203 | 226 | |
204 | 227 | # test covclass |
205 | 228 | # 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 | |
207 | 230 | |
208 | 231 | # test get/set retryshort |
209 | 232 | class RetryShortTestCase(CardTestCase): |
248 | 271 | self.assertRaises(error,pyw.rtsthreshget,'bad0') |
249 | 272 | self.assertRaises(error,pyw.rtsthreshset,'bad0',5) |
250 | 273 | 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) | |
253 | 276 | self.assertRaises(error, pyw.rtsthreshset,self.card,'on') |
254 | 277 | |
255 | 278 | # test get/set RTS thresh |
265 | 288 | self.assertRaises(error,pyw.fragthreshget,'bad0') |
266 | 289 | self.assertRaises(error,pyw.fragthreshset,'bad0',800) |
267 | 290 | 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) | |
270 | 293 | self.assertRaises(error,pyw.fragthreshset,self.card,'on') |
271 | 294 | |
272 | 295 | # test get freqs |
273 | 296 | class DevFreqsTestCase(CardTestCase): |
274 | 297 | def test_devfreqs(self): |
275 | self.assertItemsEqual(pri['freqs'],pyw.devfreqs(self.card)) | |
298 | self.assertListEqual(pri['freqs'],pyw.devfreqs(self.card)) | |
276 | 299 | def test_invalidcardarg(self): |
277 | 300 | self.assertRaises(error,pyw.devfreqs,'bad0') |
278 | 301 | |
279 | 302 | # test get chs |
280 | 303 | class DevCHsTestCase(CardTestCase): |
281 | 304 | 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)) | |
283 | 308 | def test_invalidcardarg(self): |
284 | 309 | self.assertRaises(error,pyw.devchs,'bad0') |
285 | 310 | |
286 | 311 | # test get stds |
287 | 312 | class DevSTDsTestCase(CardTestCase): |
288 | 313 | def test_devchs(self): |
289 | self.assertItemsEqual(pri['stds'],pyw.devstds(self.card)) | |
314 | self.assertListEqual(pri['stds'],pyw.devstds(self.card)) | |
290 | 315 | def test_invalidcardarg(self): |
291 | 316 | self.assertRaises(error,pyw.devstds,'bad0') |
292 | 317 | |
293 | 318 | # test get modes |
294 | 319 | class DevModesTestCase(CardTestCase): |
295 | 320 | def test_devmodes(self): |
296 | self.assertIn('managed',pyw.devmodes(self.card)) | |
321 | self.assertListEqual(pri['modes'],pyw.devmodes(self.card)) | |
297 | 322 | def test_invalidcardarg(self): |
298 | 323 | self.assertRaises(error,pyw.devmodes,'bad0') |
299 | 324 | |
304 | 329 | def test_invalidcardarg(self): |
305 | 330 | self.assertRaises(error,pyw.devmodes,'bad0') |
306 | 331 | |
307 | # test devinfo | |
332 | # test devinfo - the key-value pairs of devinfo are tested via others | |
308 | 333 | class DevInfoTestCase(CardTestCase): |
309 | 334 | def test_devinfobycard(self): |
310 | 335 | self.assertIsInstance(pyw.devinfo(self.card),dict) |
357 | 382 | # because freqset was already tested in chgetset, we only test invalid args |
358 | 383 | class FreqSetTestCase(CardTestCase): |
359 | 384 | 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 | |
361 | 386 | 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) | |
363 | 388 | |
364 | 389 | # test modeget |
365 | 390 | class ModeGetTestCase(CardTestCase): |
388 | 413 | def test_ifaces(self): |
389 | 414 | self.assertIsInstance(pyw.ifaces(self.card),list) |
390 | 415 | def test_invalidcardarg(self): |
391 | self.assertRaises(error,pyw.ifaces,'b0b0') | |
416 | self.assertRaises(error,pyw.ifaces,'bad0') | |
392 | 417 | |
393 | 418 | # test devadd/devdel |
419 | """ | |
394 | 420 | class DevAddDelTestCase(CardTestCase): |
395 | 421 | def test_devadddel(self): |
396 | 422 | 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()) | |
398 | 426 | def test_invalidcardarg(self): |
399 | 427 | self.assertRaises(error,pyw.devadd,'bad0','test0','monitor') |
400 | 428 | 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) | |
404 | 429 | def test_invalidmodearg(self): |
405 | 430 | self.assertRaises(error,pyw.devadd,self.card,'test0','foobar') |
406 | 431 | def test_invalidflagsarg(self): |
407 | 432 | self.assertRaises(error,pyw.devadd,self.card,'test0','monitor','foobar') |
408 | 433 | self.assertRaises(error,pyw.devadd,self.card,'test0','managed','fcsfail') |
409 | 434 | |
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) | |
410 | 470 | if __name__ == '__main__': |
471 | print("Testing PyRIC v{0} pyw v{1} on Python {2}".format(pyric.version, | |
472 | pyw.__version__, | |
473 | pyvers())) | |
411 | 474 | unittest.main()⏎ |