0 | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
1 | |
% Copyright (C) 2016 Dale V. Patterson ([email protected])
|
2 | |
%
|
3 | |
%This program is free software: you can redistribute it and/or modify it under
|
4 | |
%the terms of the GNU General Public License as published by the Free Software
|
5 | |
%Foundation, either version 3 of the License, or (at your option) any later
|
6 | |
%version.
|
7 | |
%
|
8 | |
%Redistribution and use in source and binary forms, with or without modifications,
|
9 | |
%are permitted provided that the following conditions are met:
|
10 | |
% o Redistributions of source code must retain the above copyright notice, this
|
11 | |
% list of conditions and the following disclaimer.
|
12 | |
% o Redistributions in binary form must reproduce the above copyright notice,
|
13 | |
% this list of conditions and the following disclaimer in the documentation
|
14 | |
% and/or other materials provided with the distribution.
|
15 | |
% o Neither the name of the orginal author Dale V. Patterson nor the names of any
|
16 | |
% contributors may be used to endorse or promote products derived from this
|
17 | |
% software without specific prior written permission.
|
18 | |
%
|
19 | |
% __name__ = 'User Guide'
|
20 | |
%__license__ = 'GPLv3'
|
21 | |
%__version__ = '0.0.7'
|
22 | |
%__date__ = 'December 2016'
|
23 | |
%__author__ = 'Dale Patterson'
|
24 | |
%__maintainer__ = 'Dale Patterson'
|
25 | |
%__email__ = '[email protected]'
|
26 | |
%__status__ = 'Production'
|
27 | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
28 | |
|
29 | |
\documentclass[11pt]{article}
|
30 | |
\usepackage[utf8]{inputenc}
|
31 | |
\setlength{\parindent}{0pt}
|
32 | |
\usepackage{graphicx}
|
33 | |
\usepackage{listings}
|
34 | |
\usepackage{caption}
|
35 | |
\usepackage{geometry}
|
36 | |
\usepackage{color}
|
37 | |
\usepackage{graphicx}
|
38 | |
\usepackage[titletoc,toc,title]{appendix}
|
39 | |
\usepackage[T1]{fontenc}
|
40 | |
|
41 | |
\definecolor{codegreen}{rgb}{0,0.6,0}
|
42 | |
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
|
43 | |
\definecolor{codepurple}{rgb}{0.58,0,0.82}
|
44 | |
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
|
45 | |
|
46 | |
\geometry{left=1.0in,right=1.0in,top=1.0in,bottom=1.0in }
|
47 | |
|
48 | |
\lstset{
|
49 | |
frame=top,
|
50 | |
frame=bottom,
|
51 | |
basicstyle=\small\normalfont\ ,
|
52 | |
stepnumber=1,
|
53 | |
numbersep=10pt,
|
54 | |
tabsize=2,
|
55 | |
extendedchars=true,
|
56 | |
breaklines=true,
|
57 | |
captionpos=b,
|
58 | |
mathescape=true,
|
59 | |
showspaces=false,
|
60 | |
showtabs=false,
|
61 | |
xleftmargin=17pt,
|
62 | |
framexleftmargin=17pt,
|
63 | |
framexrightmargin=17pt,
|
64 | |
framexbottommargin=5pt,
|
65 | |
framextopmargin=5pt,
|
66 | |
showstringspaces=false,
|
67 | |
backgroundcolor=\color{backcolour},
|
68 | |
commentstyle=\color{codegreen},
|
69 | |
keywordstyle=\color{magenta},
|
70 | |
numberstyle=\tiny\color{codegray},
|
71 | |
stringstyle=\color{codepurple},
|
72 | |
basicstyle=\footnotesize
|
73 | |
}
|
74 | |
|
75 | |
\title{\includegraphics[scale=1]{logo}\\ PyRIC v0.1.6.4: User Manual}
|
76 | |
\author{Dale V. Patterson\\ [email protected]}
|
77 | |
|
78 | |
\begin{document}
|
79 | |
\maketitle
|
80 | |
\tableofcontents
|
81 | |
|
82 | |
\section{About PyRIC}\label{sec:About}
|
83 | |
PyRIC (is a Linux only) library providing wireless developers and pentesters the
|
84 | |
ability to identify, enumerate and manipulate their system's wireless cards
|
85 | |
programmatically in Python. Pentesting applications and scripts written in Python
|
86 | |
have increased dramatically in recent years. However, these tools still rely on
|
87 | |
Linux command lines tools to setup and prepare and restore the system for use.
|
88 | |
Until now. Why use subprocess.Popen, regular expressions and str.find to interact
|
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:
|
98 | |
\begin{enumerate}
|
99 | |
\item \textbf{Pythonic}: No ctypes, SWIG etc. PyRIC redefines C header files as
|
100 | |
Python and uses sockets to communicate with kernel.
|
101 | |
\item \textbf{Self-sufficient}: No third-party files used, PyRIC is completely self-
|
102 | |
contained
|
103 | |
\item \textbf{Fast}: (relatively speaking) PyRIC is faster than using iw through
|
104 | |
subprocess.Popen
|
105 | |
\item \textbf{Parseless}: Get the output you without parsing output from iw. Never
|
106 | |
worry about iw updates and rewriting your parsers.
|
107 | |
\item \textbf{Easy}: If you can use iw, you can use PyRIC
|
108 | |
\end{enumerate}
|
109 | |
|
110 | |
At it's heart, PyRIC is a Python port of (a subset of) iw and by extension, a
|
111 | |
Python port of Netlink w.r.t nl80211 functionality. The original goal of PyRIC
|
112 | |
was to provide a simple interface to the underlying nl80211 kernel support,
|
113 | |
handling the complex operations of Netlink seamlessy while maintaining a minimum
|
114 | |
of "code walking" to understand, modify and extend. But, why stop there? Since
|
115 | |
it's initial inception, PyRIC has grown to include ioctl support to replicate
|
116 | |
features of ifconfig such as getting or setting the mac address and has recently
|
117 | |
implemented rkill support to soft block or unblock wireless cards.\\
|
118 | |
|
119 | |
While users can utilize libnl.py to communicate directly with the kernel, the
|
120 | |
true utility of PyRIC is pyw.py. Like iw, pyw provides an interface/buffer
|
121 | |
between the caller and the kernel, handling all message construction, parsing
|
122 | |
and data transfer transparently and without requiring any Netlink knowledge or
|
123 | |
experience. \\
|
124 | |
|
125 | |
At this time, PyRIC can:
|
126 | |
\begin{itemize}
|
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,
|
138 | |
\item get/set regulatory domain,
|
139 | |
\item get/set mode,
|
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.
|
150 | |
|
151 | |
\subsection{Background}
|
152 | |
PyRIC arose out of a need in Wraith (https://github.com/wraith-wireless/wraith)
|
153 | |
for Python nl80211/netlink and ioctl functionality. Originally, Wraith used
|
154 | |
ifconfig, iwconfig and iw via subprocess.Popen and parsed the output. There
|
155 | |
are obvious shortfalls with this method, especially in terms of iw that is
|
156 | |
actively changing (revisions break the parser) and I started looking for an
|
157 | |
open source alternative. There are several open source projects out there
|
158 | |
such as pyroute, pymnl (and the python files included in the libnl source) but
|
159 | |
they generally have either not been maintained recently or come with warnings.
|
160 | |
I desired a simple interface to the underlying nl80211 kernel support that
|
161 | |
handles the complex operations of netlink seamlessy while maintaining a minimum
|
162 | |
of "code walking" to understand, modify and extend. I decided to write my own
|
163 | |
because I do not need complete netlink functionality, only that provided by
|
164 | |
generic netlink and within the nl80221 family. Additionally, for Wraith, I do
|
165 | |
not need a full blown port of iw et. al. functionality to Python but only
|
166 | |
require the ability to turn a wireless nic on/off, get/set the hwaddr, get/set
|
167 | |
the channel, determine some properties of the card and add/delete interfaces.
|
168 | |
|
169 | |
So, why did I do this and why is it done "this" way? When I first started to
|
170 | |
explore the idea of moving away from iw output parsing, I looked at the source
|
171 | |
for iw, and existing Python ports. Just to figure out how to get the family id
|
172 | |
for nl80211 required reading through five different source files with no
|
173 | |
comments. To that extent, I have attempted to keep subclassing to a minimum,
|
174 | |
the total number of classes to a minimum, combine files where possible and where
|
175 | |
it makes since and keep the number of files required to be open simultaneously
|
176 | |
in order to understand the methodology and follow the program to a minimum. One
|
177 | |
can understand the PyRIC program flow with only two files open at any time namely,
|
178 | |
pyw and libnl. In fact, only an understanding of pyw is required to add additional
|
179 | |
commands although an understanding of libnl.py is helpful especially, if for
|
180 | |
example, the code is to be extended to handle multicast or callbacks.
|
181 | |
|
182 | |
\subsection{Naming Conventions}
|
183 | |
The terms interface, device and radio are all used interchangeably throughout to
|
184 | |
refer to a network interface controller (NIC). The following terms will always
|
185 | |
have one meaning:
|
186 | |
\begin{itemize}
|
187 | |
\item \textbf{dev} - the device name i.e. wlan0 or eth0 of a NIC,
|
188 | |
\item \textbf{phy} - the physical index of a NIC i.e. the 0 in phy0,
|
189 | |
\item \textbf{ifindex} - the interface index of a NIC,
|
190 | |
\item \textbf{card} or \textbf{Card} - a NIC abstraction, an object used in pyw
|
191 | |
functions see the following section for a description.
|
192 | |
\end{itemize}
|
193 | |
|
194 | |
\subsection{Cards}
|
195 | |
A Card is merely a wrapper around a tuple t = (phy index,device name,ifindex).
|
196 | |
Since the underlying Netlink calls sometimes require the physical index, sometimes
|
197 | |
the device name, and sometimes the ifindex, pyw functions\footnote{Not all functions
|
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:
|
202 | |
\begin{enumerate}
|
203 | |
\item \textbf{pyw.getcard} returns a Card object from a given dev,
|
204 | |
\item \textbf{pyw.devinfo} returns the dict info where info['card'] is the Card
|
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),
|
208 | |
\item \textbf{pyw.ifaces} returns a list of tuples t = (Card,mode) sharing the
|
209 | |
same phy as a given dev.
|
210 | |
\end{enumerate}
|
211 | |
|
212 | |
A side affect of using Cards is that many of the netlink calls require the ifindex.
|
213 | |
The ifindex is found through the use of ioctl, meaning two sockets have to be
|
214 | |
created and two messages have to be sent, received and parsed in order to execute
|
215 | |
the command. With Cards, the ifindex is requested for only once. \\
|
216 | |
|
217 | |
Keep in mind that any identifier (phy, dev, ifindex) can be invalidated outside
|
218 | |
of your control. Another program can rename your interface, that is change the
|
219 | |
dev without your knowledge. Depending on what functions are being used this may
|
220 | |
not be noticed right away as the phy will remain the same. Also for usb devices,
|
221 | |
(if the usb is disconnected and reconnected) will have the same dev but the phy
|
222 | |
and ifindex will be different.
|
223 | |
|
224 | |
\subsection{Benchmarks}
|
225 | |
PyRIC makes use of several "extensions" to speed up pyw functions:
|
226 | |
\begin{enumerate}
|
227 | |
\item \textbf{Persistent sockets}: pyw provides the caller with functions and
|
228 | |
the ability to pass their own netlink (or ioctl socket) to pyw functions
|
229 | |
\item \textbf{One-time request for the nl80211 family id}: pyw stores the family
|
230 | |
id in a global variable
|
231 | |
\item \textbf{Consolidation} different "reference" values are consolidated in one
|
232 | |
class (see the previous section)
|
233 | |
\end{enumerate}
|
234 | |
|
235 | |
\begin{table}
|
236 | |
\begin{center}
|
237 | |
\begin{tabular}{| l | r | r | r | r|}
|
238 | |
\hline
|
239 | |
chset & Total & Avg & Longest & Shortest \\
|
240 | |
\hline
|
241 | |
Popen(iw) & 588.3059 & 0.0588 & 0.0682 & 0.0021 \\
|
242 | |
\hline
|
243 | |
one-time & 560.3559 & 0.0560 & 0.0645 & 0.0003 \\
|
244 | |
\hline
|
245 | |
persistent & 257.8293 & 0.0257 & 0.0354 & 0.0004 \\
|
246 | |
\hline
|
247 | |
\end{tabular}
|
248 | |
\caption{Benchmark: Popen(iw) vs pyw}
|
249 | |
\end{center}
|
250 | |
\label{tab:benchmark}
|
251 | |
\end{table}
|
252 | |
|
253 | |
While small, these changes can improve the performance of any programs using pyw.
|
254 | |
Table 1 shows benchmarks for hop time on an Alfa AWUS036NH conducted 10000 times.
|
255 | |
Note that we are not implying that PyRIC is faster than iw. Rather, the table
|
256 | |
shows that PyRIC is faster than using Popen to execute iw. Using one-time sockets,
|
257 | |
there is a difference of 28 seconds over Popen and iw with a small decrease in
|
258 | |
the average hoptime. Not a big difference. However, the performance increased
|
259 | |
dramatically when persistent netlink sockets are used with the total time and
|
260 | |
average hop time nearly halved.
|
261 | |
|
262 | |
\section{Installing PyRIC}\label{sec:installing}
|
263 | |
The easiest way to install PyRIC is through PyPI:\\
|
264 | |
|
265 | |
\texttt{sudo pip install PyRIC}\\
|
266 | |
|
267 | |
You can also install PyRIC from source. The tarball can be downloaded from:
|
268 | |
|
269 | |
\begin{itemize}
|
270 | |
\item PyPi: https://pypi.python.org/pypi/PyRIC,
|
271 | |
\item PyRIC Web: http://wraith-wireless.github.io/PyRIC, or
|
272 | |
\item Github: https://github.com/wraith-wireless/PyRIC.
|
273 | |
\end{itemize}
|
274 | |
|
275 | |
After downloading, extract and run:\\
|
276 | |
|
277 | |
\texttt{sudo python setup.py install}\\
|
278 | |
|
279 | |
If you just want to test PyRIC out, download your choice from above. After
|
280 | |
extraction, move the pyric folder (the package directory) to your location of
|
281 | |
choice and from there start Python and import pyw. It is very important that you
|
282 | |
do not try and run it from PyRIC which is the distribution directory. This will
|
283 | |
break the imports pyw.py uses. \\
|
284 | |
|
285 | |
You will only be able to test PyRIC from the pyric directory but, if you want to,
|
286 | |
you can add it to your Python path and run it from any program or any location.
|
287 | |
To do so, assume you untared PyRIC to /home/bob/PyRIC. Create a text file named
|
288 | |
pyric.pth with one line \\
|
289 | |
|
290 | |
/home/bob/PyRIC \\
|
291 | |
|
292 | |
and save this file to /usr/lib/python2.7/dist-packages (or
|
293 | |
/usr/lib/python3/dist-packages if you want to try it in Python 3).
|
294 | |
|
295 | |
\begin{table}
|
296 | |
\begin{center}
|
297 | |
\begin{tabular}{| l | r | r | r |}
|
298 | |
\hline
|
299 | |
Source & Stability & Recency & Installation \\
|
300 | |
\hline
|
301 | |
pip & 5 & 3 & 5\\
|
302 | |
\hline
|
303 | |
PyPI & 5 & 3 & 4\\
|
304 | |
\hline
|
305 | |
PyRIC Web & 4 & 4 & 4\\
|
306 | |
\hline
|
307 | |
Github & 3 & 5 & 3\\
|
308 | |
\hline
|
309 | |
\end{tabular}
|
310 | |
\caption{Stability vs Recency vs Installation}
|
311 | |
\end{center}
|
312 | |
\label{tab:install}
|
313 | |
\end{table}
|
314 | |
|
315 | |
\section{Using PyRIC}\label{sec:using}
|
316 | |
As stated previously, PyRIC provides a set of functions to interact with your
|
317 | |
system's radio(s) and the ability to interact directly with the kernel through
|
318 | |
netlink and ioctl sockets.
|
319 | |
|
320 | |
\subsection{Interacting with the Wireless Core and Wireless NICs: pyw.py}
|
321 | |
If you can use iw, you can use pyw. The easist way to explain how to use pyw is
|
322 | |
with an example. Imagine your wireless network, on ch 6, has been experiencing
|
323 | |
difficulties lately and you want to capture some traffic to analyse it. Listing
|
324 | |
\ref{lst:pentest} shows how to set up a wireless pentest environment. \\
|
325 | |
|
326 | |
\begin{lstlisting}[caption={Setting up a Wireless Pentest Environment},
|
327 | |
label={lst:pentest},
|
328 | |
language=Python]
|
329 | |
1: import pyric # pyric error (and ecode EUNDEF)
|
330 | |
2: from pyric import pyw # for iw functionality
|
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)
|
355 | |
\end{lstlisting}
|
356 | |
|
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.
|
381 | |
|
382 | |
\subsubsection{One-time vs Persistent Sockets}
|
383 | |
The example in Listing \ref{lst:pentest} uses one-time sockets (netlink and
|
384 | |
ioctl). When using iw, there are several things that occur prior to the actual
|
385 | |
command or request being submitted. First, iw creates a netlink socket. Then,
|
386 | |
iw will request the family id for nl80211. The relative time spent doing this
|
387 | |
is neglible but, it is redundant and it may become noticeable in programs that
|
388 | |
repeatedly use the Netlink service. Once comlete, iw closes the socket. In some
|
389 | |
cases, the ifindex of the device is needed and iw will also initiate an ioctl
|
390 | |
call to retrieve it. PyRIC eliminates these redundancies by using a global
|
391 | |
variable in pyw that stores the family id after the first time it is requested
|
392 | |
and by providing callers the option to use persistent sockets.
|
393 | |
\begin{itemize}
|
394 | |
\item \textbf{One-time Sockets} Similar to iw. The command, creates the netlink
|
395 | |
socket (or ioctl socket), composes the message, sends the message and receives
|
396 | |
the response, parses the results, closes the socket and returns the results to
|
397 | |
the caller. At no time does the caller need to be aware of any underlying Netlink
|
398 | |
processes or structures.
|
399 | |
\item \textbf{Persistent Sockets} Communication and parsing only. The onus of
|
400 | |
socket creation and deletion is on the caller which allows them to create one
|
401 | |
(or more) socket(s). The pyw functions will only handle message construction,
|
402 | |
message sending and receiving and message parsing.
|
403 | |
\end{itemize}
|
404 | |
The caller needs to be cognizant of whether the function requires a netlink or
|
405 | |
ioctl socket. Passing the wrong type will result in an error. \\
|
406 | |
|
407 | |
NOTE: One must remember that there is an upper limit to the number of open netlink
|
408 | |
sockets. It is advised to use one-time functions as much as possible and save the
|
409 | |
use of persistent sockets for use in code that repeatedly makes use of netlink. \\
|
410 | |
|
411 | |
The latest version of pyw.py (v 0.1.*) implements this functionality through the
|
412 | |
use of what I call templates\footnote{I use templates and stubs for the lack
|
413 | |
of any better naming convention}, Listing \ref{lst:template} and stubs Listing
|
414 | |
\ref{lst:stub}.
|
415 | |
|
416 | |
\begin{lstlisting}[caption={A Basic Netlink Function Template},
|
417 | |
label={lst:template},
|
418 | |
language=Python]
|
419 | |
def fcttemplate(arg0,arg1,..,argn,nlsock=None):
|
420 | |
# put parameter validation (if any) here
|
421 | |
if nlsock is None: _nlstub_(fcttemplate,arg0,arg1,...,argn)
|
422 | |
|
423 | |
# command execution
|
424 | |
...
|
425 | |
return results
|
426 | |
\end{lstlisting}
|
427 | |
|
428 | |
The template function in Listing \ref{lst:template} checks if nlsock is instantiatd
|
429 | |
\footnote{ioctl calls operate in the same manner}. If so, it proceeds to execution.
|
430 | |
If there is no socket, the stub is executed which creates one. If something other
|
431 | |
than a netlink socket is at argv[0], an error will be raised during execution. \\
|
432 | |
|
433 | |
\begin{lstlisting}[caption={Function \_nlstub\_},
|
434 | |
label={lst:stub},
|
435 | |
language=Python]
|
436 | |
def _nlstub_(fct,*argv):
|
437 | |
nlsock = None
|
438 | |
try:
|
439 | |
nlsock = nlsock = nl.nl_socket_alloc()
|
440 | |
argv = list(argv) + nlsock=None
|
441 | |
return fct(*argv)
|
442 | |
except pyric.error:
|
443 | |
raise # catch & release
|
444 | |
finally:
|
445 | |
if nlsock: nl.nl_socket_free(nlsock)
|
446 | |
\end{lstlisting}
|
447 | |
|
448 | |
The stub function, Listing \ref{lst:stub} allocates a netlink socket, executes
|
449 | |
the original (now with a netlink socket) and then destroys the netlink socket.\\
|
450 | |
|
451 | |
\begin{lstlisting}[caption={Using Persistent Sockets},
|
452 | |
label={lst:persistent},
|
453 | |
language=Python]
|
454 | |
1: import pyric # pyric errors
|
455 | |
2: from pyric import pyw # for iw functionality
|
456 | |
3: from pyric.lib import libnl as nl # for netlink sockets
|
457 | |
4:
|
458 | |
5: nlsock = nl.nl_socket_alloc(timeout=1)
|
459 | |
6: card = pyw.getcard('wlan0',nlsock)
|
460 | |
7: print pyw.devmodes(card,nlsock)
|
461 | |
8: nl.nl_socket_free(nlsock)
|
462 | |
\end{lstlisting}
|
463 | |
|
464 | |
Listing \ref{lst:persistent}, shows the creation of a persistent netlink socket
|
465 | |
that is used in the creation of a card and in retrieved the card's supported
|
466 | |
modes. \\
|
467 | |
|
468 | |
Use Python's built in help features on pyw functions or see Appendex \ref{sec:pywapi}
|
469 | |
to determine what type of socket is needed.
|
470 | |
|
471 | |
\subsection{Additional Tools}
|
472 | |
In the utils directory, PyRIC includes channels.py, hardware.py, rfkill.py and
|
473 | |
ouifetch.py. These provide a port of rfkill, channel/frequency enumeration and
|
474 | |
device chipset, driver retrieval as well as some mac address functions. More
|
475 | |
information can be found in the Appendices and in README.md.
|
476 | |
|
477 | |
\subsection{Interacting with the Kernel: libnl.py and libio.py}
|
478 | |
The kernel interfaces, libnl.py and libio.py are located in the lib directory.
|
479 | |
They handle socket creation/deletion, message creation/parsing and kernel
|
480 | |
communication. Aside from creating and deleting persistent sockets, there is
|
481 | |
little need to access their functions unless you plan on extending pyw
|
482 | |
functionality. As such, a further discussion of libnl.py and libio.py can be
|
483 | |
found in the next section.
|
484 | |
|
485 | |
\section{Extending PyRIC}\label{sec:extending}
|
486 | |
You may find that pyw does not offer some of the functionality you need. Using
|
487 | |
libnl.py and/or libnl.io, additional functionality can be added to your program.\\
|
488 | |
|
489 | |
It is helpful if the reader has a basic knowledge of netlinks. For a review, see
|
490 | |
"Communicating between the kernel and user-space in Linux using Netlink Sockets"
|
491 | |
\cite{spae}.
|
492 | |
|
493 | |
\subsection{Porting C}
|
494 | |
All Python ports of C header files can be found in the net directory. C Enums
|
495 | |
and \#defines are ported using constants. C structs are ported using three
|
496 | |
Python structures and the Python struct package:
|
497 | |
\begin{enumerate}
|
498 | |
\item a format string for packing and unpacking the struct
|
499 | |
\item a constant specifying the size of the struct in bytes
|
500 | |
\item a function taking the attributes of the struct as arguments and returning
|
501 | |
a packed string
|
502 | |
\end{enumerate}
|
503 | |
Listing \ref{lst:cstruct} shows the C definition of the nlmsghdr found in netlink.h.
|
504 | |
|
505 | |
\begin{lstlisting}[caption={C Struct nlmsghdr},
|
506 | |
label={lst:cstruct},
|
507 | |
language=C]
|
508 | |
struct nlmsghdr {
|
509 | |
__u32 nlmsg_len;
|
510 | |
__u16 nlmsg_type;
|
511 | |
__u16 nlmsg_flags;
|
512 | |
__u32 nlmsg_seq;
|
513 | |
__u32 nlmsg_pid;
|
514 | |
};
|
515 | |
\end{lstlisting}
|
516 | |
|
517 | |
And Listing \ref{lst:pstruct} shows the ported version in Python.
|
518 | |
|
519 | |
\begin{lstlisting}[caption={Corresponding Python Definition},
|
520 | |
label={lst:pstruct},
|
521 | |
language=Python]
|
522 | |
nl_nlmsghdr = "IHHII"
|
523 | |
NLMSGHDRLEN = struct.calcsize(nl_nlmsghdr)
|
524 | |
def nlmsghdr(mlen,nltype,flags,seq,pid):
|
525 | |
return struct.pack(nl_nlmsghdr,NLMSGHDRLEN+mlen,nltype,flags,seq,pid)
|
526 | |
\end{lstlisting}
|
527 | |
|
528 | |
When using pyw, dealing with these structures is handled transparently by libnl.py
|
529 | |
and libio.py. When extending or customizing pyw, a basic understanding of the
|
530 | |
definitions in netlink\_h.py, genetlink\_h.py and if\_h.py.
|
531 | |
|
532 | |
\subsection{Input/Output Control (ioctl)}
|
533 | |
PyRIC provides more than just iw-related functions, it also implements functions
|
534 | |
from ifconfig and iwconfig. These command line tools still use ioctl (or the proc
|
535 | |
directory). For example, interfaces() reads from '/proc/net/dev' to retrieve all
|
536 | |
system interfaces and winterfaces() use ioctl to check if a device is wireless.
|
537 | |
Input/Output control calls have only been used when there was no viable alternative
|
538 | |
and, it should not be necessary to have to add any further ioctl commands. If you
|
539 | |
find that you need an ioctl related command, search through if\_h.py for the
|
540 | |
appropriate structure and add it's definitions to ifreq.
|
541 | |
|
542 | |
\subsection{Netlink and nl80211}
|
543 | |
Documentation on Netlink, and nl80211 in particular, is so minimal as to be
|
544 | |
neglible. The clusterfuck of code and lack of comments in the iw source tree
|
545 | |
make it impossible to use as any sort of roadmap. Fortunately Thomas Graf's
|
546 | |
site\cite{libnl} has excellent coverage of libnl, the Netlink library. Using
|
547 | |
this as a reference, a simple Netlink parser was put together which later became
|
548 | |
libnl.py. Using the command line tool strace and libnl.py, Netlink messages could
|
549 | |
be dissected and analyzed.\\
|
550 | |
|
551 | |
Let us consider adding a virtual interface with the command:\\
|
552 | |
|
553 | |
\texttt{sudo iw phy0 interface add test0 type monitor}\\
|
554 | |
|
555 | |
First, we need to see what is going on under the covers. Using strace:\\
|
556 | |
|
557 | |
\texttt{strace -f -x -s 4096 iw phy0 interface add test0 type monitor}\\
|
558 | |
|
559 | |
from a terminal will give a you a lot of output, most irrelevant (to us). Scroll
|
560 | |
through this until the netlink socket creation as highlighted in Figure
|
561 | |
\ref{fig:nlsock}. You can see that a socket of type PF\_NETLINK is created and
|
562 | |
the send/receive buffers are set to 32768.
|
563 | |
\begin{center}
|
564 | |
\begin{figure}[h]
|
565 | |
\includegraphics{nlsock}
|
566 | |
\caption{Netlink socket creation}
|
567 | |
\label{fig:nlsock}
|
568 | |
\end{figure}
|
569 | |
\end{center}
|
570 | |
What we want to analyze are the messages sent and received over the netlink
|
571 | |
socket. In Figure \ref{fig:nlsock}, iw is requesting the family id for nl80211.
|
572 | |
This id will be used in subsequent requests related to nl80211 as we will see
|
573 | |
shortly. The return message gives the nl80211 family id as 26 and returns other
|
574 | |
nl80211 attributes. This is handled by the private function \_familyid\_ in
|
575 | |
pyw.py.
|
576 | |
|
577 | |
Figure \ref{fig:nlsend} shows the add interface message being sent to the kernel.
|
578 | |
\begin{center}
|
579 | |
\begin{figure}[h]
|
580 | |
\includegraphics{nlsend}
|
581 | |
\caption{Netlink sendmsg}
|
582 | |
\label{fig:nlsend}
|
583 | |
\end{figure}
|
584 | |
\end{center}
|
585 | |
We are interested in the byte sequence following msg\_iov(1). Copy this and paste
|
586 | |
into in a python variable as in Listing \ref{lst:nlparse} and pass it to the
|
587 | |
function nlmsg\_fromstream which parses the byte stream and returns the GENLMsg.\\
|
588 | |
|
589 | |
\begin{lstlisting}[caption={Parsing netlink messages},
|
590 | |
label={lst:nlparse},
|
591 | |
language=Python]
|
592 | |
>>> from pyric.lib import libnl as nl
|
593 | |
>>> sent = "\x30\x00\x00\x00\x1a...\x00\x00"
|
594 | |
>>> msg = nl.nlmsg_fromstream(sent)
|
595 | |
>>> msg
|
596 | |
nlmsghdr(len=48,type=26,flags=5,seq=1463268720,pid=10982)
|
597 | |
genlmsghdr(cmd=7)
|
598 | |
attributes:
|
599 | |
0: type=1,datatype=3
|
600 | |
value=0
|
601 | |
1: type=4,datatype=5
|
602 | |
value=test0
|
603 | |
2: type=5,datatype=3
|
604 | |
value=6
|
605 | |
\end{lstlisting}
|
606 | |
|
607 | |
The first thing to notice is nlmsghdr type = 26, which of course is nl80211 family
|
608 | |
id. The rest of the nlmsghdr components len, flags, seq, and pid are handled by
|
609 | |
libnl.py although you can supply your own flags if desired. At this time, you can
|
610 | |
manually look up what values the cmd, type and datatype correspond to in
|
611 | |
nl80211\_h.py and netlink\_h.py or you can use the tools provided in nlhelp.py.\\
|
612 | |
|
613 | |
\begin{lstlisting}[caption={Parsing netlink messages continued},
|
614 | |
label={lst:nlparse2},
|
615 | |
language=Python]
|
616 | |
>>> from pyric.net.netlink_h import NLA_DATATYPES
|
617 | |
>>> from pyric.docs import nlhelp
|
618 | |
>>> nlhelp.cmdbynum(7)
|
619 | |
u'@NL80211_CMD_NEW_INTERFACE'
|
620 | |
>>>
|
621 | |
>>> for attr in msg.attrs:
|
622 | |
... print nlhelp.attrbynum(attr[0]), NLA_DATATYPES[attr[2]], attr[1]
|
623 | |
...
|
624 | |
@NL80211_ATTR_WIPHY u32 0
|
625 | |
@NL80211_ATTR_IFNAME string test0
|
626 | |
@NL80211_ATTR_IFTYPE u32 6
|
627 | |
>>>
|
628 | |
>>> from pyric.net.wireless.nl80211_h import NL80211_IFTYPES
|
629 | |
>>> NL80211_IFTYPES[6]
|
630 | |
'monitor'
|
631 | |
\end{lstlisting}
|
632 | |
|
633 | |
In Listing \ref{lst:nlparse2} command number 7 corresponds to
|
634 | |
NL80211\_CMD\_NEW\_INTERFACE and the attributes that need to be passed to the
|
635 | |
kernel are NL80211\_ATTR\_WIPHY, NL80211\_ATTR\_IFNAME and NL80211\_ATTR\_IFTYPE.
|
636 | |
The IFTYPE is also known as the mode i.e. 'monitor' which can be found in
|
637 | |
nl80211\_h.py NL80211\_IFTYPES. We don't parse the return message from the kernel
|
638 | |
but, it follows the same SOP. In this case, it returns the attributes of the new
|
639 | |
virtual interface. \\
|
640 | |
|
641 | |
With this information, we can now code our function. Recall the fcttemplate as
|
642 | |
defined in Listing \ref{lst:template} and fill in the command execution as shown
|
643 | |
in Listing \ref{lst:coding}. \\
|
644 | |
|
645 | |
\begin{lstlisting}[caption={Coding the function},
|
646 | |
label={lst:coding},
|
647 | |
language=Python]
|
648 | |
# construct the message
|
649 | |
msg = nl.nlmsg_new(nltype=_familyid_(nlsock),
|
650 | |
cmd=nl80211h.NL80211_CMD_NEW_INTERFACE,
|
651 | |
flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
|
652 | |
nl.nla_put_u32(msg,card.phy,nl80211h.NL80211_ATTR_WIPHY)
|
653 | |
nl.nla_put_string(msg,vdev,nl80211h.NL80211_ATTR_IFNAME)
|
654 | |
nl.nla_put_u32(msg,IFTYPES.index(mode),nl80211h.NL80211_ATTR_IFTYPE)
|
655 | |
|
656 | |
# send, receive and parse return results, returning the new Card
|
657 | |
nl.nl_sendmsg(nlsock,msg)
|
658 | |
rmsg = nl.nl_recvmsg(nlsock) # success returns new device attributes
|
659 | |
return Card(card.phy,vdev,nl.nla_find(rmsg,nl80211h.NL80211_ATTR_IFINDEX))
|
660 | |
\end{lstlisting}
|
661 | |
|
662 | |
We construct a new GENLMsg passing the nl80211 family id, the command we got
|
663 | |
earlier and flags specifying that this is a request and we want to get an ACK
|
664 | |
back\footnote{libnl.py always forces an ACK and handles the underlying process
|
665 | |
of receiving it}. Now, add each attribute to the message. Note the order: value,
|
666 | |
then attribute. With the message constructed, send it to the kernel, get the
|
667 | |
results, parse and return them.\\
|
668 | |
|
669 | |
Rather simple, in fact the hardest part is figuring out what to send to the kernel.
|
670 | |
Everything else is handled behind the scenes by libnl.py.
|
671 | |
|
672 | |
\begin{appendices}
|
673 | |
\section{API: pyw.py}\label{sec:pywapi}
|
674 | |
|
675 | |
\subsection{Constants}
|
676 | |
\begin{itemize}
|
677 | |
\item \textbf{\_FAM80211ID\_}: Global netlink family id of nl80211. Do not touch
|
678 | |
\item \textbf{IFTYPES}: redefined (from nl80211\_h.py) interface modes
|
679 | |
\item \textbf{MNTRFLAGS}: redefined (from nl80211\_h.py) monitor mode flags
|
680 | |
\item \textbf{TXPOWERSETTINGS}: redefined (from nl80211\_h.py) power level settings
|
681 | |
\end{itemize}
|
682 | |
|
683 | |
\subsection{Objects/Classes}
|
684 | |
\textbf{Card} A wrapper around a tuple
|
685 | |
\texttt{t = (physical index,device name,interface index)}
|
686 | |
which exposes the following properties through '.':
|
687 | |
\begin{itemize}
|
688 | |
\item \textbf{phy}: physical index
|
689 | |
\item \textbf{dev}: device name
|
690 | |
\item \textbf{idx}: interface index (ifindex)
|
691 | |
\end{itemize}
|
692 | |
Because the underlying Netlink calls will sometimes require the physical index,
|
693 | |
sometimes the device name, and sometimes the ifindex, pyw functions accept a Card,
|
694 | |
object. This allows callers to use pyw functions without having to remember which
|
695 | |
identifier the function requires. However, in some cases the function requires
|
696 | |
a dev or accepts both. See the next section on functions.\\
|
697 | |
|
698 | |
While callers could create their own Cards, it is recommend to use one of the
|
699 | |
following
|
700 | |
\begin{itemize}
|
701 | |
\item \textbf{pyw.getcard} returns a Card object from a given dev
|
702 | |
\item \textbf{pyw.devinfo} returns the dict info where info['card'] is the Card
|
703 | |
object. This function will take either a card or a dev
|
704 | |
\item \textbf{pyw.devadd} returns a new Card object
|
705 | |
\item \textbf{pyw.devadd} returns a new Card object
|
706 | |
\item \textbf{pyw.ifaces} returns a list of tuples t = (Card,mode) sharing the
|
707 | |
same phy as a given device to do so. It is also recommended to periodically
|
708 | |
validate the Card. On some cheaper usb wireless nics, there are periodic
|
709 | |
disconnects which results in a new phy and ifindex.
|
710 | |
\end{itemize}
|
711 | |
|
712 | |
\subsection{Functions}
|
713 | |
\begin{itemize}
|
714 | |
\item interfaces(): (ifconfig), type: filesystem, returns list of all network
|
715 | |
device names
|
716 | |
\item isinterface(dev): (ifconfig <dev>) type: filesystem, checks that dev is a
|
717 | |
device name
|
718 | |
\item winterfaces(iosock=None): (iwconfig), type: ioctl, list wireless device
|
719 | |
names
|
720 | |
\item iswireless(dev,iosock=None): (iwconfig <dev>), type: ioctl, check dev is a
|
721 | |
wireless interface
|
722 | |
\item phylist(): (iw phy | grep wiphy) type: N/A, list phy indexes and phy names
|
723 | |
present on system
|
724 | |
\item regget(nlsock=None: (iw reg get), type: netlink, get regulatory domain
|
725 | |
\item regset(rd,nlsock=None): (iw reg set <rd>), type: netlink, set regulatory domain
|
726 | |
to rd
|
727 | |
\item getcard(dev,nlsock=None) (N/A), type: hybrid netlink and ioctl: get a Card
|
728 | |
object for dev
|
729 | |
\item validcard(card,nlsock=None): (N/A), type: (hyrbrid netlink and ioctl), verify
|
730 | |
card is still valid
|
731 | |
\item macget(card,iosock=None): (ifconfig), type: ioctl, determine if card is up
|
732 | |
or down
|
733 | |
\item macset(card,mac,iosock=None): (ifconfig card.<dev> hw ether <mac>), type:
|
734 | |
ioctl, set card's hw address to mac
|
735 | |
\item isup(card,iosock=None): (ifconfig card.<dev>)
|
736 | |
\item up(card,iosock=None) (ifconfig card.<dev> up), type: ioctl, bring card up
|
737 | |
\item down(card,iosock=None): (ifconfig card.<dev> down), type: ioctl, bring card
|
738 | |
down
|
739 | |
\item isblocked(card): (rfkill list <rfkill\_idx>): type N/A returns tuple
|
740 | |
(Soft Block State, Hard Block State)
|
741 | |
\item block(card): (rfkill block <rfkill\_idx>) type: N/A, soft blocks card
|
742 | |
\item unblock(card): (rfkill unblock <rfkill\_idx>) type: N/A, removes the soft
|
743 | |
block on card
|
744 | |
\item pwrsaveget(card,nlsock=None) (iw dev card.<dev> get power\_save) type: netlink
|
745 | |
get card's power save state True = on, False = off
|
746 | |
\item pwrsaveset(card,on,nlsock=None) (iw dev card.<dev> set power\_save <on>) type:
|
747 | |
netlink, set card's power save state True = on, False = off
|
748 | |
\item covclassget(card,nlsock=None) (iw phy card.<phy> get coverage <cc>) type:
|
749 | |
netlink get card's coverage class
|
750 | |
\item covclassset(card,cc,nlsock=None) (iw phy card.<phy> set coverage <cc>) type:
|
751 | |
netlink set card's coverage class
|
752 | |
\item retryshortget(card,nlsock=None) (iw phy card.<phy> info | grep 'retry short')
|
753 | |
type:netlink get card's retry short limit
|
754 | |
\item retryshortset(card,lim,nlsock=None) (iw phy card.<phy> set retry short <lim>)
|
755 | |
type:netlink set card's retry short limit. NOTE: although 255 is specified as the
|
756 | |
max limit for this and the long retry, kernel v4 will not allow it.
|
757 | |
\item retrylongget(card,nlsock=None) (iw phy card.<phy> info | grep 'retry long')
|
758 | |
type:netlink get card's retry long limit
|
759 | |
\item retrylongset(card,lim,nlsock=None) (iw phy card.<phy> set retry long <lim>)
|
760 | |
type:netlink set card's retry long limit
|
761 | |
\item rtsthreshget(card,nlsock=None) (iw phy card.<phy> info | grep rts) type:
|
762 | |
netlink set card's RTS threshold
|
763 | |
\item rtsthreshset(card,thresh,nlsock=None) (iw phy card.<phy> set rts <thresh>) type:
|
764 | |
netlink set card's RTS threshold
|
765 | |
\item fragthreshget(card,nlsock=None) (iw phy card.<phy> info | grep frag) type:
|
766 | |
netlink get card's fragmentation threshold
|
767 | |
\item fragthreshset(card,thresh,nlsock=None) (iw phy card.<phy> set frag <thresh>) type:
|
768 | |
netlink set card's fragmentation threshold
|
769 | |
\item ifaddrget(card,iosock=None): (ifconfig card.<dev>), type: ioctl, get ip4 address,
|
770 | |
netmask and broadcast address of card
|
771 | |
\item ifaddrset(card,ipaddr,netmask,broadcast,iosock=None): (ifconfig card/<dev>
|
772 | |
<ipaddr> netmask <netmask> broadcast <broadcast>), type: ioctl, set the interface
|
773 | |
addresses of the card
|
774 | |
\item inetset(card,ipaddr,iosock=None): (ifconfig card.<dev> <ipaddr>), type: ioctl,
|
775 | |
set the card's ip4 address
|
776 | |
\item maskset(card,netmask,iosock=None): (ifconfig card.<dev> netmask <netmask>),
|
777 | |
type: ioctl, set the card's netmask
|
778 | |
\item bcastset(card,broadcast,iosock=None): (ifconfig card.<dev> broadcast
|
779 | |
<broadcast>), type: ioctl, set the card's broadcast address
|
780 | |
\item devfreqs(card,nlsock=None): (iw phy card.phy info), type: netlink, get card's
|
781 | |
supported frequencies
|
782 | |
\item devchs(card,nlsock=None): (iw phy card.phy info), type: netlink, get card's
|
783 | |
supported channels
|
784 | |
\item devstds(card,nlsock=None): (iwconfig card.<dev> | grep IEEE), type: nlsock,
|
785 | |
returns a list of card's 802.11 supported standards by letter designator
|
786 | |
\item devmodes(card,nlsock=None): (iw phy card.phy info | grep interface), type:
|
787 | |
netlink, get card's supported modes
|
788 | |
\item devcmds(card,nlsock=None): (iw phy card.phy info | grep commands), type:
|
789 | |
netlink, get card's supported commands
|
790 | |
\item ifinfo(card,iosock=None): (ifconfig card.<dev>), type: ioctl, get hardware
|
791 | |
related info for card
|
792 | |
\item devinfo(card,nlsock=None): (iw dev card.<dev> info), type: netlink, get info
|
793 | |
for dev
|
794 | |
\item phyinfo(card,nlsock=None): (iw phy card.<phy> info), type: netlink, get info
|
795 | |
for phy
|
796 | |
\item ifaces(card,nlsock=None): (APX iw card.dev | grep phy\#), type: netlink, get all
|
797 | |
cards (w/ modes) of interfaces sharing the same phy as card
|
798 | |
\item txset(card,pwr,lvl,nlsock=None) (iw phy phy0 set txpower <lvl> <pwr>), type:
|
799 | |
netlink,sets the tx power to pwr (in dBm) with level setting lvl
|
800 | |
\item txget(card,iosock=None): (iwconfig card.<dev> | grep Tx-Power card), type:
|
801 | |
ioctl, get card's transmission power
|
802 | |
\item chget(card,nlsock=None): (iw dev <card.dev> info | grep channel), type:
|
803 | |
netlink, get card's current channel
|
804 | |
\item chset(card,ch,chw=None,nlsock=None): iw phy <card.phy> set channel <ch> <chw>),
|
805 | |
type: netlink, set card's current channel to ch with width chw
|
806 | |
\item freqget(card,nlsock=None): (iw dev <card.dev> info | grep channel), type:
|
807 | |
netlink, get card's current frequency
|
808 | |
\item freqset(card,rf,chw=None,nlsock=None): iw phy <card.phy> set freq <rf> <chw>),
|
809 | |
type: netlink, set card's current frequency to rf with width chw
|
810 | |
\item devmodes(card,iosock=None): (iw phy card.<phy>), type: netlink, get modes
|
811 | |
supported by card
|
812 | |
\item modeset(card,mode,flags=None,nlsock=None): (iw dev card.<dev> set type <mode>
|
813 | |
[flags]), type: netlink, set card's mode to mode with flags (if mode is monitor)
|
814 | |
\item modeget(card,nlsock=None): (iw dev card.<dev> info | grep mode), type: netlink,
|
815 | |
get card's mode
|
816 | |
\item devset(card,ndev,nlsock=None): (N/A) sets the dev (name) of card to ndev
|
817 | |
\item phyadd(phy,vnic,mode,flags=None,nlsock=None): (iw phy <phy> interface add <vnic>
|
818 | |
type <mode> flags <flags>)\footnote{There is a bug in some kernel v4.4.0-x
|
819 | |
where the given dev name is ignored and a system chosen one is used instead. See
|
820 | |
https://wraithwireless.wordpress.com. Whenever possible, use devadd to create
|
821 | |
interfaces instead.}, type: netlink, creates a new virtual interface with dev vdev,
|
822 | |
in mode and using flags. Note: flags are only supported when creating a monitor mode
|
823 | |
\item devadd(card (or ifindex),vnic,mode,[flags],nlsock=None): (iw phy card.<dev>
|
824 | |
interface add <vnic> type <mode> flags <flags>), type: netlink, creates a new virtual
|
825 | |
interface with dev vdev, in mode and using flags. Note: flags are only supported
|
826 | |
when creating a monitor mode. This function accepts either a Card object or a
|
827 | |
ifindex.
|
828 | |
\item devdel(card,nlsock=None): (iw card.<dev> del), type: netlink, deletes card
|
829 | |
\begin{itemize}
|
830 | |
\item isconnected(card,nlsock=None): (iw dev card.<dev> info | grep channel), type:
|
831 | |
netlink, determines if card is connected
|
832 | |
\item connect(card,ssid,bssid=None,rf=None,nlsock=None): (iw dev card.<dev> connect <ssid>
|
833 | |
<rf> <bssid>) connects to AP SSID with BSSID
|
834 | |
\item disconnect(card, nlsock=None): (iw dev card.<dev> disconnect), type: netlink,
|
835 | |
disconnects card from AP
|
836 | |
\item link(card, nlsock=None): (iw dev card.<dev> link), type: netlink, displays
|
837 | |
link specific details, i.e. AP details that card is connected to
|
838 | |
\item stainfo(card, mac, nlsock=None): (iw dev card.<dev> link) type: netlink, displays
|
839 | |
tx, rx metrics of the AP that card is connected to
|
840 | |
\item \_hex2mac\_(v): returns a ':' separated mac address from byte stream v
|
841 | |
\item \_mac2hex\_(v): returns a hex string corresponding to mac address v
|
842 | |
\item \_hex2ip4\_(v): returns a '.' separated ip4 address from byte stream v
|
843 | |
\item \_validip4\_(addr): determines if addr is a valid ip4 address
|
844 | |
\item \_validmac\_(addr): determines if addr is a valid mac address
|
845 | |
\item \_issetf\_(flags,flag): determines if flag is set in flags
|
846 | |
\item \_setf\_(flags,flag): set flag in flags to on
|
847 | |
\item \_unsetf\_(flags,flag): set flag in flags to off
|
848 | |
\item \_familyid\_(nlsock): returns and sets the Netlink family id for nl80211,
|
849 | |
only called once per module import
|
850 | |
\item \_ifindex\_(dev,iosock=None): returns dev's ifindex
|
851 | |
\item \_flagsget\_(dev,iosock=None): get's the dev's interface flags
|
852 | |
\item \_flagsset\_(dev,flags,iosock=None): set's the dev's interface flags
|
853 | |
\item \_iftypes\_(i): returns the mode corresponding to i
|
854 | |
\item \_bands\_(band): futher parses band attribute returns dict of bands
|
855 | |
containting rf information and rate information
|
856 | |
\item \_band\_rates\_(rs): extracts list of rates from the unpacked rates rs
|
857 | |
\item \_band\_rfs\_(rfs): extracts list of RFs (and other data) from the unpacked
|
858 | |
frequencies rfs
|
859 | |
\item \_unparsed\_rfs\_(band): (legacy) returns a list of frequencies from the
|
860 | |
unparsed byte string band
|
861 | |
\item \_commands\_(command): converts the list of numeric commands to a list of
|
862 | |
commands as strings
|
863 | |
\item \_ciphers\_(cipher): returns a list of ciphers from the packed byte string
|
864 | |
cipher
|
865 | |
\item \_rateinfo\_(ri): returns parsed rate info from the packed byte string ri
|
866 | |
\item \_iostub\_(fct,*argv): ioctl stub function, calls fct with parameter list
|
867 | |
argv and an allocated ioctl socket
|
868 | |
\item \_nlstub\_(fct,*argv): netlink stub function, calls fct with parameter list
|
869 | |
argv and an allocated netlink socket
|
870 | |
\end{itemize}
|
871 | |
\end{itemize}
|
872 | |
|
873 | |
\section{API: channels.py}\label{sec:channels.api}
|
874 | |
Channel, Frequency enumeration and conversions can be found in channels.py.
|
875 | |
|
876 | |
\subsection{Constants}
|
877 | |
\begin{enumerate}
|
878 | |
\item \textbf{CHTYPES}: imported channel types from nl80211\_h
|
879 | |
\item \textbf{CHWIDTHS}: imported channel widths from nl80211\_h
|
880 | |
\item \textbf{ISM\_24\_C2F}: Dict containing ISM channel (key) to frequency (value)
|
881 | |
pairs
|
882 | |
\item \textbf{ISM\_24\_F2C}: Dict containing ISM frequency (key) to channel (value)
|
883 | |
pairs
|
884 | |
\item \textbf{UNII\_5\_C2F}: Dict containing UNII 5Ghz channel (key) to frequency
|
885 | |
(value) pairs
|
886 | |
\item \textbf{UNII\_5\_F2C}: Dict containing UNII 5Ghz frequency (key) to channel
|
887 | |
(value) pairs
|
888 | |
\item \textbf{UNII\_4\_C2F}: Dict containing UNII upper 4Ghz channel (key) to
|
889 | |
frequency (value) pairs
|
890 | |
\item \textbf{UNII\_4\_F2C}: Dict containing UNII upper 4Ghz frequency (key) to
|
891 | |
channel (value) pairs
|
892 | |
\end{enumerate}
|
893 | |
|
894 | |
\subsection{Functions}
|
895 | |
\begin{enumerate}
|
896 | |
\item channels(): returns a list of all channels
|
897 | |
\item freqs(): returns a list of all frequencies
|
898 | |
\item ch2rf(c): convert channel c to frequency
|
899 | |
\item rf2ch(f): convert frequency f to channel
|
900 | |
\end{enumerate}
|
901 | |
|
902 | |
\section{API: hardware.py}\label{sec:hardwareapi}
|
903 | |
Hardware related: driver, chipset, manufacturer and mac address utility functions
|
904 | |
can be found in device.py.
|
905 | |
|
906 | |
\subsection{Constants}
|
907 | |
\begin{enumerate}
|
908 | |
\item \textbf{dpath}: path to system device details
|
909 | |
\item \textbf{drvpath}: path to device drivers
|
910 | |
\end{enumerate}
|
911 | |
|
912 | |
\subsection{Functions}
|
913 | |
\begin{enumerate}
|
914 | |
\item oui(mac): returns the oui portion of address <mac>
|
915 | |
\item ulm(mac): returns the ulm portion of address <mac>
|
916 | |
\item manufacturer(ouis,mac): returns the manufacturer name of <mac> given the
|
917 | |
dict of <ouis>
|
918 | |
\item randhw([ouis]): returns a random mac address. If the dict ouis is specified
|
919 | |
will select a random oui from the dict otherwise will generate one
|
920 | |
\item ifcard(dev): returns the device driver and chipset
|
921 | |
\item ifdriver(dev): returns the device driver
|
922 | |
\item ifchipset(driver): returns the chipset associated with driver
|
923 | |
\end{enumerate}
|
924 | |
|
925 | |
\section{API: ouifetch.py}
|
926 | |
The file ouifetch.py retrieves and saves a tab seperated file of oui to
|
927 | |
manufacturer name for use by hardware.py functions. From a command line, type: \\
|
928 | |
|
929 | |
\subsection{Constants}
|
930 | |
\begin{enumerate}
|
931 | |
\item \textbf{OUIURL}: url of IEEE oui file
|
932 | |
\item \textbf{OUIPATH}: path to default location PyRIC oui.txt file
|
933 | |
\end{enumerate}
|
934 | |
|
935 | |
\subsection{Functions}
|
936 | |
\begin{enumerate}
|
937 | |
\item load([opath]): returns a dict of oui:manufacturer key->value pairs stored
|
938 | |
in the text file at opath. If opath is not specified, uses the default
|
939 | |
\item fetch([opath]): retrieves oui.txt from the IEEE website, parses the files
|
940 | |
and stores the results in a PyRIC friendly format in opath. If opath is not
|
941 | |
specified, uses the default. User must have root permissions in order to write
|
942 | |
to default opath
|
943 | |
\end{enumerate}
|
944 | |
|
945 | |
\section{API: rfkill.py}\label{sec:rfkillapi}
|
946 | |
A port of the command line tool rfkill, rfkill.py writes and reads rfkill\_event
|
947 | |
structures to /dev/rfkill using fcntl providing functionality to block and unblock
|
948 | |
devices.
|
949 | |
|
950 | |
\subsection{Constants}
|
951 | |
\begin{enumerate}
|
952 | |
\item \textbf{RFKILL\_STATE}: list of boolean values corresponding to blocked,
|
953 | |
unblocked
|
954 | |
\end{enumerate}
|
955 | |
|
956 | |
\subsection{Functions}
|
957 | |
\begin{enumerate}
|
958 | |
\item rfkill\_list(): corresponds to rkill list, returns a dict of dicts name ->
|
959 | |
\{idx, type, soft, hard\}. If type is 'wireless', then name will be of the form
|
960 | |
phy<n> such that n is the physical index of the wireless card
|
961 | |
\item rfkill\_block(idx): soft blocks the device at rfkill index idx
|
962 | |
\item rfkill\_blockby(rtype): soft blocks all devices of type rtype
|
963 | |
\item rfkill\_unblock(idx): turns off the soft block at rfkill index idx
|
964 | |
\item rfkill\_unblockby(rtype): turns off the soft blocks of all devices of type
|
965 | |
rtype
|
966 | |
\item soft\_blocked{idx}: determines soft block state of device at rfkill index idx
|
967 | |
\item hard\_blocked{idx}: determines hard block state of device at rfkill index idx
|
968 | |
\item getidx(phy): returns the rfkill index of the device with physical index phy
|
969 | |
\item getname(idx): returns the name of the device at rfkill index idx
|
970 | |
\item gettype(idx): returns the type of the device at rfkill index idx
|
971 | |
\end{enumerate}
|
972 | |
|
973 | |
\section{API: libnl.py}\label{sec:libnlapi}
|
974 | |
Providing libnl similar functionality, libnl.py provides the interface between
|
975 | |
pyw and the underlying nl80211 core. It relates similarily to libnl by providing
|
976 | |
functions handling netlink messages and sockets and where possible uses similarly
|
977 | |
named functions as those libnl to ease any transitions from C to PyRIC. However,
|
978 | |
several liberties have been taken as libnl.py handles only nl80211 generic netlink
|
979 | |
messages.
|
980 | |
|
981 | |
\subsection{Constants}
|
982 | |
\begin{itemize}
|
983 | |
\item \textbf{BUFSZ} default rx and tx buffer size
|
984 | |
\end{itemize}
|
985 | |
|
986 | |
\subsection{Classes/Objects}
|
987 | |
The two classes in libnl.py, NLSocket and GENLMsg, discussed in the following
|
988 | |
sections subclass Python's builtin dict. This has been done IOT to take advantage
|
989 | |
of dict's already existing functions and primarily their mutability and Python's
|
990 | |
'pass by name' i.e. modifications in a function will be reflected in the caller.
|
991 | |
This makes the classes very similar to the use C pointers to structs in libnl.
|
992 | |
|
993 | |
\subsubsection{NLSocket}
|
994 | |
NLSocket is a wrapper around a netlink socket which exposes the following
|
995 | |
properties through '.':
|
996 | |
\begin{itemize}
|
997 | |
\item \textbf{sock}: the actual socket
|
998 | |
\item \textbf{fd}: the socket's file descriptor (deprecated)
|
999 | |
\item \textbf{tx}: size of the send buffer
|
1000 | |
\item \textbf{rx}: size of the receive buffer
|
1001 | |
\item \textbf{pid}: port id
|
1002 | |
\item \textbf{grpm}: group mask
|
1003 | |
\item \textbf{seq}: sequence number
|
1004 | |
\item \textbf{timeout}: socket timeout
|
1005 | |
\end{itemize}
|
1006 | |
and has the following methods:
|
1007 | |
\begin{itemize}
|
1008 | |
\item incr(): increment sequence number
|
1009 | |
\item send(pkt): sends pkt returning bytes sent
|
1010 | |
\item recv(): returns received message (will block unless timeout is set)
|
1011 | |
\item close(): close the socket
|
1012 | |
\end{itemize}
|
1013 | |
|
1014 | |
NLSockets are created with nl\_socket\_alloc and must be freed with nl\_socket\_free.
|
1015 | |
See Section \ref{sec:libnlfct}.
|
1016 | |
|
1017 | |
\subsubsection{GENLMsg}
|
1018 | |
GENLMsg is a wrapper around a dict with the following key->value pairs:
|
1019 | |
\begin{itemize}
|
1020 | |
\item \textbf{len}: total message length including the header
|
1021 | |
\item \textbf{nltype}: netlink type
|
1022 | |
\item \textbf{flags}: message flags
|
1023 | |
\item \textbf{seq}: seq. \#
|
1024 | |
\item \textbf{pid}: port id
|
1025 | |
\item \textbf{cmd}: generic netlink command
|
1026 | |
\item \textbf{attrs}: list of message attributes. Each attribute is a tuple t =
|
1027 | |
(attribute,value,datatype) where:
|
1028 | |
\begin{itemize}
|
1029 | |
\item \textbf{attribute}: netlink attribute type i.e. CTRL\_ATTR\_FAMILY\_ID
|
1030 | |
\item \textbf{value}: the unpacked attribute value
|
1031 | |
\item \textbf{datatype}: datatype of the attribute as defined in nelink\_h i.e.
|
1032 | |
NLA\_U8
|
1033 | |
\end{itemize}
|
1034 | |
\end{itemize}
|
1035 | |
NOTE: as discussed below, on sending, the seq. \# and port id are overridden with
|
1036 | |
values of the netlink socket.\\
|
1037 | |
|
1038 | |
GENLMsg exposes the following properties:
|
1039 | |
\begin{itemize}
|
1040 | |
\item \textbf{len}: length of the message (get only)
|
1041 | |
\item \textbf{vers}: returns 1 (default version) (get only)
|
1042 | |
\item \textbf{nltype}: message content i.e. generic or nl80211 (get or set)
|
1043 | |
\item \textbf{flags}: message flags (get or set)
|
1044 | |
\item \textbf{seq}: current sequence \# (get or set)
|
1045 | |
\item \textbf{pid}: port id (get or set)
|
1046 | |
\item \textbf{cmd}: netlink command (get or set)
|
1047 | |
\item \textbf{attrs}: attribute list (get only)
|
1048 | |
\item \textbf{numattrs}: number of attributes (get only)
|
1049 | |
\end{itemize}
|
1050 | |
|
1051 | |
GENLMsg has the following methods:
|
1052 | |
\begin{itemize}
|
1053 | |
\item \_\_repr\_\_(): returns a string representation useful for debugging
|
1054 | |
\item tostream(): returns a packed netlink message
|
1055 | |
|
1056 | |
There are two methods of creating a GENLMsg. Create a new message (to send) with
|
1057 | |
nlmsg\_new and create a message from a received packet with nlmsg\_fromstream.
|
1058 | |
These are discussed below.
|
1059 | |
|
1060 | |
\subsection{Functions}\label{sec:libnlfct}
|
1061 | |
\begin{itemize}
|
1062 | |
\item \textbf{Netlink Socket Related}
|
1063 | |
\begin{itemize}
|
1064 | |
\item nl\_socket\_alloc(pid,grps,seq,rx,tx,timeout): creates a netlink socket
|
1065 | |
with port id = pid, group mask = grps, initial seq. \# = seq, send and receive
|
1066 | |
buffer size = tx and rx respectively and blocking timeout = timeout
|
1067 | |
\item nl\_socket\_free(sock): closes the socket
|
1068 | |
\item nl\_socket\_pid(sock): (deprecated for NLSocket.pid) returns the port id
|
1069 | |
\item nl\_socket\_grpmask(sock): (deprecated for NLSocket.grpmask) returns the
|
1070 | |
group mask
|
1071 | |
\item nl\_sendmsg(sock,msg,override=False): sends the netlink msg over socket.
|
1072 | |
NOTE: NLSockets will automatically set the port id and seq. \# regardless of
|
1073 | |
their value in the message. If override is True, the message's pid and seq. \#
|
1074 | |
will be used instead.
|
1075 | |
\item nl\_recvmsg(sock): returns a GENLMsg or blocks unless the socket's timeout
|
1076 | |
is set. Should only be called once per every nl\_sendmsg.
|
1077 | |
\end{itemize}
|
1078 | |
\item \textbf{Netlink Message Related}
|
1079 | |
\begin{itemize}
|
1080 | |
\item nlmsg\_new(nltype=None,cmd=None,pid=None,flags=None,attrs=None): creates a
|
1081 | |
new GENLMsg with zero or more attributes defined.
|
1082 | |
\item nlmsg\_fromstream(stream): parses the message in stream returning the
|
1083 | |
corresponding GENLMsg
|
1084 | |
\item nla\_parse(msg,l,mtype,stream,idx): parses the attributes in stream appending
|
1085 | |
them to the attribute list of message where msg = the GENLMsg, l = the total
|
1086 | |
length of the message, mtype = the message content (i.e. netlink type) stream is
|
1087 | |
the original byte stream and idx is the index of the start of the attribute list
|
1088 | |
\item nla\_parse\_nested(nested): returns the list of packed nested attributes
|
1089 | |
extracted from the stream nested. Callers must unpack and parse the returned
|
1090 | |
attributes themselves
|
1091 | |
\item nla\_put(msg,v,a,t): appends the attribute a, with value v and datatype t
|
1092 | |
to the msg's attribute list
|
1093 | |
\item nla\_put\_<DATATYPE>(msg,v,a): eight specialized functions that append
|
1094 | |
attribute a with the value v and type <DATATYPE> to msg's attribute list
|
1095 | |
\item nla\_putat(msg,i,v,a,d): puts attribute a, with value v and datatype d at
|
1096 | |
index i in msg's attribute list.
|
1097 | |
\item nla\_pop(msg,i): removes the attribute tuple at index i, returning the popped
|
1098 | |
tuple
|
1099 | |
\item nla\_find(msg,a,value=True): returns the first attribute a in msg's attribute
|
1100 | |
list. If value returns only the value otherwise returns the attribute tuple
|
1101 | |
\item nla\_get(msg,i,value=True): returns the attribute at index i. If value returns
|
1102 | |
only the value otherwise returns the attribute tuple
|
1103 | |
\item \_nla\_strip(v): (private) strips padding bytes from the end of v
|
1104 | |
\item \_attrpack(a,v,d): (private) packs the attribute tuple
|
1105 | |
\end{itemize}
|
1106 | |
\item \_maxbufsz\_(): (private) returns the maximum allowable socket buffer size
|
1107 | |
\end{itemize}
|
1108 | |
\end{itemize}
|
1109 | |
|
1110 | |
\section{API: libio.py}\label{sec:libioapi}
|
1111 | |
A very basic interface to ioctl, libio provides socket creation, deletion and
|
1112 | |
transfer.
|
1113 | |
|
1114 | |
\subsection{Functions}
|
1115 | |
\begin{enumerate}
|
1116 | |
\item io\_socket\_alloc(): returns an ioctl socket
|
1117 | |
\item io\_socket\_free(iosock): closes the ioctl socket iosock
|
1118 | |
\item io\_transfer\_(iosock,flag,ifreq): sends the ifreq structure with sockios
|
1119 | |
control call flag to the kernel and returns the received ifreq structure
|
1120 | |
\end{enumerate}
|
1121 | |
|
1122 | |
\section{Copyright and License}\label{sec:copy}
|
1123 | |
PYRIC: Python Radio Interface Controller v0.1.6.4\\
|
1124 | |
|
1125 | |
Copyright (C) 2016 Dale V. Patterson ([email protected])\\
|
1126 | |
|
1127 | |
This program is free software: you can redistribute it and/or modify it under
|
1128 | |
the terms of the GNU General Public License\cite{gplv3} as published by the Free
|
1129 | |
Software Foundation, either version 3 of the License, or (at your option) any
|
1130 | |
later version.\\
|
1131 | |
|
1132 | |
Redistribution and use in source and binary forms, with or without modifications,
|
1133 | |
are permitted provided that the following conditions are met:
|
1134 | |
\begin{itemize}
|
1135 | |
\item Redistributions of source code must retain the above copyright notice, this
|
1136 | |
list of conditions and the following disclaimer.
|
1137 | |
\item Redistributions in binary form must reproduce the above copyright notice,
|
1138 | |
this list of conditions and the following disclaimer in the documentation and/or
|
1139 | |
other materials provided with the distribution.
|
1140 | |
\item Neither the name of the orginal author Dale V. Patterson nor the names of
|
1141 | |
any contributors may be used to endorse or promote products derived from this
|
1142 | |
software without specific prior written permission.
|
1143 | |
\end{itemize}
|
1144 | |
|
1145 | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND
|
1146 | |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
1147 | |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
1148 | |
IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
1149 | |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
1150 | |
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
1151 | |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
1152 | |
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
1153 | |
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\\
|
1154 | |
|
1155 | |
PyRIC is free software but use, duplication or disclosure by the United States
|
1156 | |
Government is subject to the restrictions set forth in DFARS 252.227-7014.\\
|
1157 | |
|
1158 | |
Use of this software is governed by all applicable federal, state and local
|
1159 | |
laws of the United States and subject to the laws of the country where you reside.
|
1160 | |
The copyright owner and contributors will be not be held liable for use of this
|
1161 | |
software in furtherance of or with intent to commit any fraudulent or other illegal
|
1162 | |
activities, or otherwise in violation of any applicable law, regulation or legal
|
1163 | |
agreement.\\
|
1164 | |
|
1165 | |
See http://www.gnu.org/licenses/licenses.html for a copy of the GNU General Public
|
1166 | |
License.
|
1167 | |
\end{appendices}
|
1168 | |
|
1169 | |
\bibliographystyle{acm}
|
1170 | |
\bibliography{PyRIC}
|
1171 | |
%\addcontentsline{toc}{chapter}{Bibliography}
|
1172 | |
|
1173 | |
\end{document}
|