-
Notifications
You must be signed in to change notification settings - Fork 23
/
mame82_util.py
executable file
·703 lines (567 loc) · 23.4 KB
/
mame82_util.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
#!/usr/bin/python
# This file is part of P4wnP1.
#
# Copyright (c) 2017, Marcus Mengs.
#
# P4wnP1 is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# P4wnP1 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with P4wnP1. If not, see <http://www.gnu.org/licenses/>.
# The python classes are used to configure the MaMe82 nexmon firmware mod
# while an access point is up and running
import fcntl
import socket
import os
from ctypes import *
import struct
class struct_mame82_probe_resp_arg(Structure):
_fields_ = [("da", c_ubyte*6),
("bssid", c_ubyte*6)]
class struct_mame82_deauth_arg(Structure):
_fields_ = [("da", c_ubyte*6),
("bssid", c_ubyte*6),
("reason", c_ushort)]
class struct_ssid_list(Structure):
# we define the fields afterwards to allow creating a pointer to this struct
# which only is declared here (no fields defined so far)
pass
struct_ssid_list._fields_ = [("next", POINTER(struct_ssid_list)),
("ssid", c_ubyte*33),
("len_ssid", c_ubyte),
("assoc_req", c_uint),
("bcn_send", c_uint)]
class struct_mame82_config(Structure):
_fields_ = [("karma_probes", c_bool),
("karma_assocs", c_bool),
("karma_beacons", c_bool),
("custom_beacons", c_bool),
("debug_out", c_bool),
("ssids_custom", c_void_p),
("ssids_karma", c_void_p),
("karma_beacon_autoremove", c_uint),
("custom_beacon_autoremove", c_uint),
("max_karma_beacon_ssids", c_ubyte),
("max_custom_beacon_ssids", c_ubyte)]
class struct_mame82_config(Structure):
_fields_ = [("karma_probes", c_bool),
("karma_assocs", c_bool),
("karma_beacons", c_bool),
("custom_beacons", c_bool),
("debug_out", c_bool),
("ssids_custom", POINTER(struct_ssid_list)),
("ssids_karma", POINTER(struct_ssid_list)),
("karma_beacon_autoremove", c_uint),
("custom_beacon_autoremove", c_uint),
("max_karma_beacon_ssids", c_ubyte),
("max_custom_beacon_ssids", c_ubyte)]
class struct_nlmsghdr(Structure):
_fields_ = [("nlmsg_len", c_uint),
("nlmsg_type", c_ushort),
("nlmsg_flags", c_ushort),
("nlmsg_seq", c_uint),
("nlmsg_pid", c_uint)]
class struct_IOCTL(Structure):
_fields_ = [("cmd", c_uint),
("buf", c_void_p),
("len", c_uint),
("set", c_bool),
("used", c_uint),
("needed", c_uint),
("driver", c_uint)]
class struct_IFREQ(Structure):
_fields_ = [("ifr_name", c_char*16),
("ifr_data", c_void_p)]
class struct_nexudp_hdr(Structure):
_fields_ = [("nex", c_char * 3),
("type", c_char),
("securitycookie", c_int)]
class struct_nexudp_ioctl_hdr(Structure):
_fields_ = [("nexudphdr", struct_nexudp_hdr),
("cmd", c_uint),
("set", c_uint),
("payload", c_byte * 1)]
def mac2bstr(mac):
res = ""
for v in mac.split(":"):
res += chr(int(v,16))
return res
class nexconf:
NLMSG_ALIGNTO = 4
RTMGRP_LINK = 1
# IFLA_IFNAME = 3
# NLM_F_REQUEST = 0x0001
# NLM_F_ROOT = 0x0100
# NLMSG_NOOP = 0x0001
# NLMSG_ERROR = 0x0002
# NLMSG_DONE = 0x0003
NEXUDP_IOCTL = 0
NETLINK_USER = 31
@staticmethod
def create_cmd_ioctl(cmd, buf, set_val=False):
ioctl = struct_IOCTL()
ioctl.cmd = cmd
ioctl.buf = cast(c_char_p(buf), c_void_p)
ioctl.len = len(buf)
ioctl.set = set_val
ioctl.driver = 0x14e46c77
return ioctl
@staticmethod
def create_ifreq(ifr_name, ifr_data):
ifr = struct_IFREQ()
ifr.ifr_name = struct.pack("16s", ifr_name) # padded with zeroes (maybe utf-8 conversion should be assured ?!?!)
ifr.ifr_data = cast(pointer(ifr_data), c_void_p)
return ifr
@staticmethod
def c_struct2str(c_struct):
return string_at(addressof(c_struct), sizeof(c_struct))
@staticmethod
def ptr2str(ptr, length):
return string_at(ptr, length)
@staticmethod
def ctype2pystr(ct):
return buffer(ct)[:]
@staticmethod
def print_struct(struct, pre=""):
for field_name, field_type in struct._fields_:
print pre, field_name, field_type, getattr(struct, field_name)
@staticmethod
def NLMSG_ALIGN(length):
return ((length + nexconf.NLMSG_ALIGNTO-1) & ~(nexconf.NLMSG_ALIGNTO - 1))
@staticmethod
def NLMSG_HDRLEN():
return nexconf.NLMSG_ALIGN(sizeof(struct_nlmsghdr))
@staticmethod
def NLMSG_LENGTH(length):
return length + nexconf.NLMSG_ALIGN(nexconf.NLMSG_HDRLEN())
@staticmethod
def NLMSG_SPACE(length):
return nexconf.NLMSG_ALIGN(nexconf.NLMSG_LENGTH(length))
@staticmethod
def NLMSG_DATA(nlh):
c = cast(nlh, c_void_p)
c.value += nexconf.NLMSG_LENGTH(0) # inc is only possible for void ptr, we don't need to cast to char first as incrementation is done in single bytes (by adding to value)
return c
@staticmethod
def openNL_sock():
try:
s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, nexconf.NETLINK_USER)
except socket.error:
print "No Netlink IOCTL connection possible"
return None
# bind to kernel
s.bind((os.getpid(), 0))
return s
def closeNL_sock(s):
s.close()
@staticmethod
def sendNL_IOCTL(ioc, debug=False, rawresult=False, nl_socket_fd=None):
### NETLINK test ####
if debug:
print "Sending NL IOCTL\n\tcmd: {0}\n\tset_enabled: {1}\n\tpayload: {2}".format(ioc.cmd, ioc.set, repr(nexconf.ptr2str(ioc.buf, ioc.len)))
frame_len = ioc.len + sizeof(struct_nexudp_ioctl_hdr) - sizeof(c_char)
frame = struct_nexudp_ioctl_hdr()
nlhbuf = create_string_buffer(nexconf.NLMSG_SPACE(frame_len))
nlh = cast(pointer(nlhbuf), POINTER(struct_nlmsghdr))
nlh.contents.nlmsg_len = nexconf.NLMSG_SPACE(frame_len)
nlh.contents.nlmsg_pid = os.getpid();
nlh.contents.nlmsg_flags = 0;
pdata = nexconf.NLMSG_DATA(nlh)
frame = cast(pdata, POINTER(struct_nexudp_ioctl_hdr))
frame.contents.nexudphdr.nex = 'NEX'
frame.contents.nexudphdr.type = chr(nexconf.NEXUDP_IOCTL)
frame.contents.nexudphdr.securitycookie = 0;
frame.contents.cmd = ioc.cmd
frame.contents.set = ioc.set
#frame.contents.payload = nexconf.ptr2str(ioc.buf, ioc.len)
memmove(addressof(frame.contents.payload), ioc.buf, ioc.len)
# frame to string
fstr = nexconf.ptr2str(frame, nexconf.NLMSG_SPACE(frame_len) - nexconf.NLMSG_LENGTH(0))
#full buf to string (including nlhdr)
p_nlhbuf = pointer(nlhbuf)
bstr = nexconf.ptr2str(p_nlhbuf, nexconf.NLMSG_SPACE(frame_len))
'''
print "NL HEADER"
print type(p_nlhbuf)
print repr(bstr)
print repr(buffer(p_nlhbuf.contents)[:])
print "NL MESSAGE DATA"
print type(frame)
print repr(fstr)
print repr(buffer(frame.contents)[:])
'''
sfd = None
s = None
if nl_socket_fd == None:
try:
s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, nexconf.NETLINK_USER)
except socket.error:
print "No Netlink IOCTL connection possible"
return None
# bind to kernel
s.bind((os.getpid(), 0))
sfd = os.fdopen(s.fileno(), 'w+b')
else:
sfd = nl_socket_fd
sfd.write(bstr)
sfd.flush()
ret = ""
if (ioc.set == 0):
# read back result (CAUTION THERE'S NO SOCKET TIMEOUT IN USE, SO THIS COULD STALL)
if debug:
print "Reading back NETLINK answer ..."
res_frame = sfd.read(nlh.contents.nlmsg_len)
res_frame_len = len(res_frame)
if rawresult:
# don't cast and parse headers
sfd.close()
s.close()
return res_frame
# pointer to result buffer
p_res_frame = cast(c_char_p(res_frame), c_void_p)
# point struct nlmsghdr to p_res_frame
p_nlh = cast(p_res_frame, POINTER(struct_nlmsghdr))
# grab pointer to data part of nlmsg
p_nld_void = nexconf.NLMSG_DATA(p_nlh)
# convert to: struct nexudp_ioctl_hdr*
p_nld = cast(p_nld_void, POINTER(struct_nexudp_ioctl_hdr))
# calculate offset to payload from p_res_frame
offset_payload = addressof(p_nld.contents.payload) - p_res_frame.value
payload = res_frame[offset_payload:]
if debug:
nexconf.print_struct(p_nlh.contents, "\t")
nexconf.print_struct(p_nld.contents, "\t")
nexconf.print_struct(p_nld.contents.nexudphdr, "\t")
print "\tpayload:\t" + repr(payload)
#return only payload part of res frame
ret = payload
if nl_socket_fd == None:
sfd.close()
s.close()
return ret
@staticmethod
def send_IOCTL(ioc, device_name = "wlan0"):
# This code is untested, because our target (BCM43430a1) talks NETLINK
# so on Pi0w sendNL_IOCTL should be used
SIOCDEVPRIVATE = 0x89F0
# create ioctl ifreq
ifr = nexconf.create_ifreq(device_name, ioc)
# debug out
'''
print repr(nexconf.c_struct2str(ifr))
print len(nexconf.c_struct2str(ifr))
print repr(string_at(ifr.ifr_data, sizeof(ioc)))
'''
# send ioctl to kernel via UDP socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
fcntl.ioctl(s.fileno(), SIOCDEVPRIVATE, ifr)
s.close()
class MaMe82_IO:
CMD=666
CMD_RETRIEVE_CAP = 400
KARMA_CAP = (1 << 7)
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_PROBE = 1
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_ASSOC = 2
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA = 3
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_BEACON = 4
MAME82_IOCTL_ARG_TYPE_SET_KARMA_BEACON_AUTO_REMOVE_COUNT = 5
MAME82_IOCTL_ARG_TYPE_SET_CUSTOM_BEACON_AUTO_REMOVE_COUNT = 6
MAME82_IOCTL_ARG_TYPE_ADD_CUSTOM_SSID = 7
MAME82_IOCTL_ARG_TYPE_DEL_CUSTOM_SSID = 8
MAME82_IOCTL_ARG_TYPE_CLEAR_CUSTOM_SSIDS = 9
MAME82_IOCTL_ARG_TYPE_CLEAR_KARMA_SSIDS = 10
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_CUSTOM_BEACONS = 11
MAME82_IOCTL_ARG_TYPE_SEND_DEAUTH = 20
MAME82_IOCTL_ARG_TYPE_SEND_PROBE_RESP = 21
MAME82_IOCTL_ARG_TYPE_GET_CONFIG = 100
MAME82_IOCTL_ARG_TYPE_GET_MEM = 101
@staticmethod
def s2hex(s):
return "".join(map("0x%2.2x ".__mod__, map(ord, s)))
@staticmethod
def send_probe_resp(bssid, da="ff:ff:ff:ff:ff:ff", ie_ssid_data="TEST_SSID", ie_vendor_data=None):
arr_bssid = mac2bstr(bssid)
arr_da = mac2bstr(da)
ie_ssid_type = 0
ie_ssid_len = 32
ie_vendor_type = 221
ie_vendor_len = 238
buf = ""
if ie_vendor_data == None:
buf = struct.pack("<II6s6sBB32s",
MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SEND_PROBE_RESP,
48, # 6 + 6 + 1 + 1 +32 + 1 + 1 + 238
arr_da,
arr_bssid,
ie_ssid_type,
ie_ssid_len,
ie_ssid_data)
else:
buf = struct.pack("<II6s6sBB32sBB238s",
MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SEND_PROBE_RESP,
286, # 6 + 6 + 1 + 1 +32 + 1 + 1 + 238
arr_da,
arr_bssid,
ie_ssid_type,
ie_ssid_len,
ie_ssid_data,
# insert additional IEs here
ie_vendor_type,
ie_vendor_len,
ie_vendor_data)
#print repr(buf)
ioctl_sendprbrsp = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, buf, True)
nexconf.sendNL_IOCTL(ioctl_sendprbrsp)
@staticmethod
def send_deauth(bssid, da="ff:ff:ff:ff:ff:ff", reason=0x0007):
arr_bssid = mac2bstr(bssid)
arr_da = mac2bstr(da)
buf = struct.pack("<II6s6sH", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SEND_DEAUTH, sizeof(struct_mame82_deauth_arg), arr_da, arr_bssid, reason)
print repr(buf)
ioctl_senddeauth = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, buf, True)
nexconf.sendNL_IOCTL(ioctl_senddeauth)
@staticmethod
def set_ch(channel):
ioctl = nexconf.create_cmd_ioctl(30, struct.pack("<I", channel), True)
res = nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def get_ch():
ioctl = nexconf.create_cmd_ioctl(29, "", False)
res = nexconf.sendNL_IOCTL(ioctl)
return struct.unpack("<I", res[:4])[0]
@staticmethod
def add_custom_ssid(ssid):
if len(ssid) > 32:
print "SSID too long, 32 chars max"
return
ioctl_addssid = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II{0}s".format(len(ssid)), MaMe82_IO.MAME82_IOCTL_ARG_TYPE_ADD_CUSTOM_SSID, len(ssid), ssid), True)
nexconf.sendNL_IOCTL(ioctl_addssid)
@staticmethod
def rem_custom_ssid(ssid):
if len(ssid) > 32:
print "SSID too long, 32 chars max"
return
ioctl_addssid = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II{0}s".format(len(ssid)), MaMe82_IO.MAME82_IOCTL_ARG_TYPE_DEL_CUSTOM_SSID, len(ssid), ssid), True)
nexconf.sendNL_IOCTL(ioctl_addssid)
@staticmethod
def set_enable_karma_probe(on=True):
if on:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_PROBE, 1, 1), True)
else:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_PROBE, 1, 0), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def set_enable_karma_assoc(on=True):
if on:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_ASSOC, 1, 1), True)
else:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_ASSOC, 1, 0), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def set_enable_karma_beaconing(on=True):
if on:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_BEACON, 1, 1), True)
else:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_BEACON, 1, 0), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def set_enable_custom_beaconing(on=True):
if on:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_CUSTOM_BEACONS, 1, 1), True)
else:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_CUSTOM_BEACONS, 1, 0), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def set_enable_karma(on=True):
if on:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA, 1, 1), True)
else:
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA, 1, 0), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def clear_custom_ssids():
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_CLEAR_CUSTOM_SSIDS, 0), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def clear_karma_ssids():
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_CLEAR_KARMA_SSIDS, 0), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def set_autoremove_custom_ssids(beacon_count):
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("III", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_CUSTOM_BEACON_AUTO_REMOVE_COUNT, 4, beacon_count), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def set_autoremove_karma_ssids(beacon_count):
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("III", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_KARMA_BEACON_AUTO_REMOVE_COUNT, 4, beacon_count), True)
nexconf.sendNL_IOCTL(ioctl)
@staticmethod
def check_for_karma_cap():
ioctl = nexconf.create_cmd_ioctl(400, "", False) # there's a length check for the CAPs ioctl, forcing size to 4 (only command, no arg buffer)
res = nexconf.sendNL_IOCTL(ioctl)
if res == None:
return False
else:
cap = struct.unpack("I", res[:4])[0]
# print "Cap: {0}".format(MaMe82_IO.s2hex(res))
if (cap & MaMe82_IO.KARMA_CAP == 0):
return False
return True
@staticmethod
def dump_conf(print_res=True, dump_ssids=True):
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II40s", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_GET_CONFIG, 4, ""), False)
res = nexconf.sendNL_IOCTL(ioctl)
if res == None:
print "Couldn't retrieve config"
return None
mame82_config = struct_mame82_config()
memmove(addressof(mame82_config), res, min(len(res), sizeof(struct_mame82_config)))
if dump_ssids:
mame82_config.ssids_karma = MaMe82_IO.dump_ssid_list(cast(mame82_config.ssids_karma, c_void_p).value)
mame82_config.ssids_custom = MaMe82_IO.dump_ssid_list(cast(mame82_config.ssids_custom, c_void_p).value)
else:
mame82_config.ssids_karma = None
mame82_config.ssids_custom = None
if print_res:
print "KARMA PROBES - Answer probe requests for foreign SSIDs [{0}]".format("On" if mame82_config.karma_probes else "Off")
print "KARMA ASSOCS - Answer association requests for foreign SSIDs [{0}]".format("On" if mame82_config.karma_assocs else "Off")
print "KARMA SSIDs - Broadcast beacons for foreigin SSIDs after probe request [{0}]".format("On" if mame82_config.karma_beacons else "Off")
print "CUSTOM SSIDs - Broadcast beacons for custom SSIDs (added by user) [{0}]".format("On" if mame82_config.custom_beacons else "Off")
print "(unused for now) Print debug messages to BCM43430a1 internal console [{0}]".format("On" if mame82_config.debug_out else "Off")
print "\nStop sending more beacons for KARMA SSIDs if no association request is received\nafter [{0}] beacons (0 send forever)".format(mame82_config.karma_beacon_autoremove)
print "\nStop sending more beacons for CUSTOM SSIDs if no association request is received\nafter [{0}] beacons (0 send forever)".format(mame82_config.custom_beacon_autoremove)
print "\nMaximum allowed KARMA SSIDs for beaconing (no influence on assocs / probes): [{0}]".format(mame82_config.max_karma_beacon_ssids)
print "Maximum allowed CUSTOM SSIDs: [{0}]".format(mame82_config.max_custom_beacon_ssids)
print ""
if cast(mame82_config.ssids_karma, c_void_p).value != None:
print "Beaconed SSIDs from probes (KARMA SSIDs), right now:\n{0}".format(MaMe82_IO.ssid_list2str(mame82_config.ssids_karma))
print ""
if cast(mame82_config.ssids_karma, c_void_p).value != None:
print "Beaconed SSIDs defined by user, right now:\n{0}".format(MaMe82_IO.ssid_list2str(mame82_config.ssids_custom))
# fetch structs for SSID list
return mame82_config
@staticmethod
def ssid_list2str(head):
ssids = []
cur = head.contents
while cast(cur.next, c_void_p).value != None:
cur = cur.next.contents
str_ssid = "".join(chr(c) for c in cur.ssid[0:cur.len_ssid])
ssids.append(str_ssid)
return ssids
@staticmethod
def dump_mem(dump_addr, dump_len, print_res=True):
# valid 0x80 - 0x07ffff
# valid 0x800000 - 0x89ffff
if dump_len < 16:
printf("Minimum length for dumping is 16 bytes")
return ""
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("III{0}s".format(dump_len - 16), MaMe82_IO.MAME82_IOCTL_ARG_TYPE_GET_MEM, 4, dump_addr, ""), False)
res = nexconf.sendNL_IOCTL(ioctl)
if print_res:
print MaMe82_IO.s2hex(res)
return res
@classmethod
def dump_ssid_list_entry(cls, address):
headdata = cls.dump_mem(address, sizeof(struct_ssid_list), print_res=False)
head = struct_ssid_list()
memmove(addressof(head), headdata, len(headdata))
return head
@classmethod
def dump_ssid_list(cls, address):
cur = cls.dump_ssid_list_entry(address)
head = cur
p_next = cast(cur.next, c_void_p)
while p_next.value != None:
#print "p_next {0}".format(hex(p_next.value))
next_entry = cls.dump_ssid_list_entry(p_next.value)
cur.next = pointer(next_entry) # replace pointer to next element with a one valid in py
cur = cur.next.contents # advance cur to next element (dreferenced)
p_next = cast(cur.next, c_void_p) # update pointer to next and cast to void*
# return pointer to head element
return pointer(head)
@classmethod
def set_defaults(cls):
cls.add_custom_ssid("linksys")
cls.add_custom_ssid("NETGEAR")
cls.add_custom_ssid("dlink")
cls.add_custom_ssid("AndroidAP")
cls.add_custom_ssid("default")
cls.add_custom_ssid("cablewifi")
cls.add_custom_ssid("asus")
cls.add_custom_ssid("Guest")
cls.add_custom_ssid("Telekom")
cls.add_custom_ssid("xerox")
cls.add_custom_ssid("tmobile")
cls.add_custom_ssid("Telekom_FON")
cls.add_custom_ssid("freifunk")
cls.set_enable_karma(True) # send probe responses and association responses for foreign SSIDs
cls.set_enable_karma_beaconing(False) # send beacons for SSIDs seen in probe requests (we better don't enable this by default)
cls.set_autoremove_karma_ssids(600) # remove SSIDs from karma beaconing, which didn't received an assoc request after 600 beacons (1 minute)
cls.set_enable_custom_beaconing(True) # send beacons for the custom SSIDs set with 'add_custom_ssid'
cls.set_autoremove_custom_ssids(0) # never remove custom SSIDs from beaconing list, if they didn't receive an assoc request
#cls.dump_conf(print_res=True)
def ioctl_get_test():
### Send ioctl comand via netlink: test of GET (cmd 262, value 'bsscfg:ssid' in a buffer large enough to receive the response) ######
# test to read a IO var for bsscfg:ssid (resp buffer: 4 bytes for uint32 ssid_len, 32 bytes for max len SSID)
# Note:
# The payload buffer size for send and recv are te same (36 in this test case), although the payload sent
# has only 11 bytes ("bsscfg:ssid") which are used. This has no impact for parsing the request for SSID on
# driver/firmware end. This means: We are free to choose the response buffer size, by adjusting the request buffer size.
# In case of the SSID request, the buffer is only partially overwritten with the response (for SSID 'test' only the first 8 bytes).
# The rest of the buffer isn't cleared to 0x00, but the response is prepended with an uint32 length field, which could be used
# to scrape out the relevant part of the response string.
# As I haven't dived into the inner workings of NETLINK, I haven't tested for responses which don't fit in a single message,
# but it is likely that those responses are fragmented over multiple NL messages and the nlmsg_seq header field is used to
# distinguish them. Anyway, this code DOESN'T ACCOUNT FOR THIS AND DOESN'T RECEIVE FRAGMENTED RESPONSES. NOR DOES THIS CODE ACCOUNT
# FOR MAXIMUM MESSAGE SIZE WHEN IT COMES TO SENDING (USING BUFFER WHICH ARE TOO LARGE).
# So this is considered experimental, the correct tool to use is nexutil written by the creators of nexmon ;-)
ioctl_readvar_ssid = nexconf.create_cmd_ioctl(262, struct.pack("36s", "bsscfg:ssid"), False)
res = nexconf.sendNL_IOCTL(ioctl_readvar_ssid)
# clamp result string
res_len = struct.unpack("I", res[:4])[0]
res_str = res[4:4+res_len]
print res_str
# As soon as an AP is running with hostapd (and backed by the customized nexmon firmware)
# the IOCTL to set up karma could be received.
#
# The hardcoded example commands below bring up a KARMA hotspot (responds to every probe/association
# request which the STA wants to see), with 13 additional SSIDs and BEACONING enabled for probed SSIDs
# Additionally the autoremove feature is enabled, for SSIDs not receiving an assoc request in timely
# manner.
#
# Each of this commands could be use to interactively manipulate the firmware from a python console.
#
# Example to disable KARMA:
# --------------------------------
# >>> from mame82_util import *
# >>> MaMe82_IO.set_enable_karma(False)
# Sending NL IOCTL
# cmd: 666
# set_enabled: True
# payload: '\x03\x00\x00\x00\x01\x00\x00\x00\x00'
#
#
# Example to enable KARMA + Beaconing for SSIDs from probe requests:
# ------------------------------------------------------------------
# >>> from mame82_util import *
# >>> MaMe82_IO.set_enable_karma(True)
# Sending NL IOCTL
# cmd: 666
# set_enabled: True
# payload: '\x03\x00\x00\x00\x01\x00\x00\x00\x01'
# >>> MaMe82_IO.set_enable_karma_beaconing(True)
# Sending NL IOCTL
# cmd: 666
# set_enabled: True
# payload: '\x04\x00\x00\x00\x01\x00\x00\x00\x01'
#
#
### Example configuration for MaMe82 KARMA nexmon firmware mod ###
#MaMe82_IO.set_defaults()