Modules in progress¶
There are several modules in the very initial development state, and the help with them will be particularly valuable. You are more than just welcome to help with:
IPSet module¶
ipset support.
This module is tested with hash:ip, hash:net, list:set and several other ipset structures (like hash:net,iface). There is no guarantee that this module is working with all available ipset modules.
It supports almost all kernel commands (create, destroy, flush, rename, swap, test…)
-
class
pyroute2.ipset.
IPSet
(version=6, attr_revision=None, nfgen_family=2)¶ NFNetlink socket (family=NETLINK_NETFILTER).
Implements API to the ipset functionality.
-
add
(name, entry, family=2, exclusive=True, comment=None, timeout=None, etype='ip', skbmark=None, skbprio=None, skbqueue=None, **kwargs)¶ Add a member to the ipset.
etype is the entry type that you add to the ipset. It’s related to the ipset type. For example, use “ip” for one hash:ip or bitmap:ip ipset.
When your ipset store a tuple, like “hash:net,iface”, you must use a comma a separator (etype=”net,iface”)
entry is a string for “ip” and “net” objects. For ipset with several dimensions, you must use a tuple (or a list) of objects.
“port” type is specific, since you can use integer of specialized containers like
PortEntry
andPortRange
Examples:
ipset = IPSet() ipset.create("foo", stype="hash:ip") ipset.add("foo", "198.51.100.1", etype="ip") ipset = IPSet() ipset.create("bar", stype="bitmap:port", bitmap_ports_range=(1000, 2000)) ipset.add("bar", 1001, etype="port") ipset.add("bar", PortRange(1500, 2000), etype="port") ipset = IPSet() import socket protocol = socket.getprotobyname("tcp") ipset.create("foobar", stype="hash:net,port") port_entry = PortEntry(80, protocol=protocol) ipset.add("foobar", ("198.51.100.0/24", port_entry), etype="net,port")
-
create
(name, stype='hash:ip', family=2, exclusive=True, counters=False, comment=False, maxelem=65536, forceadd=False, hashsize=None, timeout=None, bitmap_ports_range=None, size=None, skbinfo=False)¶ Create an ipset name of type stype, by default hash:ip.
Common ipset options are supported:
- exclusive – if set, raise an error if the ipset exists
- counters – enable data/packets counters
- comment – enable comments capability
- maxelem – max size of the ipset
- forceadd – you should refer to the ipset manpage
- hashsize – size of the hashtable (if any)
- timeout – enable and set a default value for entries (if not None)
- bitmap_ports_range – set the specified inclusive portrange for
- the bitmap ipset structure (0, 65536)
- size – Size of the list:set, the default is 8
- skbinfo – enable skbinfo capability
-
delete
(name, entry, family=2, exclusive=True, etype='ip')¶ Delete a member from the ipset.
See
add()
method for more information on etype.
-
destroy
(name=None)¶ Destroy one (when name is set) or all ipset (when name is None)
-
flush
(name=None)¶ Flush all ipsets. When name is set, flush only this ipset.
-
get_supported_revisions
(stype, family=2)¶ Return minimum and maximum of revisions supported by the kernel.
Each ipset module (like hash:net, hash:ip, etc) has several revisions. Newer revisions often have more features or more performances. Thanks to this call, you can ask the kernel the list of supported revisions.
You can manually set/force revisions used in IPSet constructor.
Example:
ipset = IPSet() ipset.get_supported_revisions("hash:net") ipset.get_supported_revisions("hash:net,port,net")
-
headers
(name)¶ Get headers of the named ipset. It can be used to test if one ipset exists, since it returns a no such file or directory.
-
list
(*argv, **kwarg)¶ List installed ipsets. If name is provided, list the named ipset or return an empty list.
Be warned: netlink does not return an error if given name does not exit, you will receive an empty list.
-
rename
(name_src, name_dst)¶ Rename the ipset.
-
swap
(set_a, set_b)¶ Swap two ipsets. They must have compatible content type.
-
-
class
pyroute2.ipset.
PortEntry
(port, protocol=None)¶ A simple container for port entry with optional protocol
-
class
pyroute2.ipset.
PortRange
(begin, end, protocol=None)¶ A simple container for port range with optional protocol
Note that optional protocol parameter is not supported by all kernel ipset modules using ports. On the other hand, it’s sometimes mandatory to set it (like for hash:net,port ipsets)
Example:
udp_proto = socket.getprotobyname("udp") port_range = PortRange(1000, 2000, protocol=udp_proto) ipset.create("foo", stype="hash:net,port") ipset.add("foo", ("192.0.2.0/24", port_range), etype="net,port") ipset.test("foo", ("192.0.2.0/24", port_range), etype="net,port")
IW module¶
Experimental wireless module — nl80211 support.
Disclaimer¶
Unlike IPRoute, which is mostly usable, though is far from complete yet, the IW module is in the very initial state. Neither the module itself, nor the message class cover the nl80211 functionality reasonably enough. So if you’re going to use it, brace yourself — debug is coming.
Messages¶
nl80211 messages are defined here:
pyroute2/netlink/nl80211/__init__.py
Pls notice NLAs of type hex. On the early development stage hex allows to inspect incoming data as a hex dump and, occasionally, even make requests with such NLAs. But it’s not a production way.
The type hex in the NLA definitions means that this particular NLA is not handled yet properly. If you want to use some NLA which is defined as hex yet, pls find out a specific type, patch the message class and submit your pull request on github.
If you’re not familiar with NLA types, take a look at RTNL definitions:
pyroute2/netlink/rtnl/ndmsg.py
and so on.
Communication with the kernel¶
There are several methods of the communication with the kernel.
- sendto() — lowest possible, send a raw binary data
- put() — send a netlink message
- nlm_request() — send a message, return the response
- get() — get a netlink message
- recv() — get a raw binary data from the kernel
There are no errors on put() usually. Any permission denied, any invalid value errors are returned from the kernel with netlink also. So if you do put(), but don’t do get(), be prepared to miss errors.
The preferred method for the communication is nlm_request(). It tracks the message ID, returns the corresponding response. In the case of errors nlm_request() raises an exception. To get the response on any operation with nl80211, use flag NLM_F_ACK.
Reverse it¶
If you’re too lazy to read the kernel sources, but still need something not implemented here, you can use reverse engineering on a reference implementation. E.g.:
# strace -e trace=network -f -x -s 4096 \
iw phy phy0 interface add test type monitor
Will dump all the netlink traffic between the program iw and the kernel. Three first packets are the generic netlink protocol discovery, you can ignore them. All that follows, is the nl80211 traffic:
sendmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ... },
msg_iov(1)=[{"\x30\x00\x00\x00\x1b\x00\x05 ...", 48}],
msg_controllen=0, msg_flags=0}, 0) = 48
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ... },
msg_iov(1)=[{"\x58\x00\x00\x00\x1b\x00\x00 ...", 16384}],
msg_controllen=0, msg_flags=0}, 0) = 88
...
With -s 4096 you will get the full dump. Then copy the strings from msg_iov to a file, let’s say data, and run the decoder:
$ pwd
/home/user/Projects/pyroute2
$ export PYTHONPATH=`pwd`
$ python scripts/decoder.py pyroute2.netlink.nl80211.nl80211cmd data
You will get the session decoded:
{'attrs': [['NL80211_ATTR_WIPHY', 0],
['NL80211_ATTR_IFNAME', 'test'],
['NL80211_ATTR_IFTYPE', 6]],
'cmd': 7,
'header': {'flags': 5,
'length': 48,
'pid': 3292542647,
'sequence_number': 1430426434,
'type': 27},
'reserved': 0,
'version': 0}
{'attrs': [['NL80211_ATTR_IFINDEX', 23811],
['NL80211_ATTR_IFNAME', 'test'],
['NL80211_ATTR_WIPHY', 0],
['NL80211_ATTR_IFTYPE', 6],
['NL80211_ATTR_WDEV', 4],
['NL80211_ATTR_MAC', 'a4:4e:31:43:1c:7c'],
['NL80211_ATTR_GENERATION', '02:00:00:00']],
'cmd': 7,
'header': {'flags': 0,
'length': 88,
'pid': 3292542647,
'sequence_number': 1430426434,
'type': 27},
'reserved': 0,
'version': 1}
Now you know, how to do a request and what you will get as a response. Sample collected data is in the scripts directory.
Submit changes¶
Please do not hesitate to submit the changes on github. Without your patches this module will not evolve.
-
class
pyroute2.iwutil.
IW
(*argv, **kwarg)¶ -
add_interface
(ifname, iftype, dev=None, phy=0)¶ Create a virtual interface
- ifname — name of the interface to create
- iftype — interface type to create
- dev — device index
- phy — phy index
One should specify dev (device index) or phy (phy index). If no one specified, phy == 0.
iftype can be integer or string:
- adhoc
- station
- ap
- ap_vlan
- wds
- monitor
- mesh_point
- p2p_client
- p2p_go
- p2p_device
- ocb
-
associate
(ifindex, bssid, ssid, freq, info_elements=None)¶ Send an Association request frame.
-
authenticate
(ifindex, bssid, ssid, freq, auth_type=0)¶ Send an Authentication management frame.
-
connect
(ifindex, ssid, bssid=None)¶ Connect to the ap with ssid and bssid
-
deauthenticate
(ifindex, bssid, reason_code=1)¶ Send a Deauthentication management frame.
-
del_interface
(dev)¶ Delete a virtual interface
- dev — device index
-
disassociate
(ifindex, bssid, reason_code=3)¶ Send a Disassociation management frame.
-
disconnect
(ifindex)¶ Disconnect the device
-
get_associated_bss
(ifindex)¶ Returns the same info like scan() does, but only about the currently associated BSS.
Unlike scan(), it returns immediately and doesn’t require root.
-
get_interface_by_ifindex
(ifindex)¶ Get interface by ifindex ( use x.get_attr(‘NL80211_ATTR_IFINDEX’)
-
get_interface_by_phy
(attr)¶ Get interface by phy ( use x.get_attr(‘NL80211_ATTR_WIPHY’) )
-
get_interfaces_dict
()¶ Get interfaces dictionary
-
get_interfaces_dump
()¶ Get interfaces dump
-
get_stations
(ifindex)¶ Get stations by ifindex
-
join_ibss
(ifindex, ssid, freq, bssid=None, channel_fixed=False, width=None, center=None, center2=None)¶ - Connect to network by ssid
- ifindex - IFINDEX of the interface to perform the connection
- ssid - Service set identification
- freq - Frequency in MHz
- bssid - The MAC address of target interface
- channel_fixed: Boolean flag
- width - Channel width
- center - Central frequency of the 40/80/160 MHz channel
- center2 - Center frequency of second segment if 80P80
If the flag of channel_fixed is True, one should specify both the width and center of the channel
width can be integer of string:
- 20_noht
- 20
- 40
- 80
- 80p80
- 160
- 5
- 10
-
leave_ibss
(ifindex)¶ Leave the IBSS – the IBSS is determined by the network interface
-
list_dev
()¶ Get list of all wifi network interfaces
-
list_wiphy
()¶ Get list of all phy devices
-
scan
(ifindex, ssids=None, flush_cache=False)¶ Trigger scan and get results.
Triggering scan usually requires root, and can take a couple of seconds.
-
Network settings daemon – pyrouted¶
Pyrouted is a standalone project of a system service, that utilizes the pyroute2 library. It consists of a daemon controlled by systemd and a CLI utility that communicates with the daemon via UNIX socket.
- home: https://github.com/svinota/pyrouted
- bugs: https://github.com/svinota/pyrouted/issues
- pypi: https://pypi.python.org/pypi/pyrouted
It is an extremely simple and basic network interface setup tool.