def run(self): """ switch channels based on associted dwell times """ while not self._done.is_set(): # wait on connection for channel's dwell time. If no token, switch # to next channel. If token & it is a hold, block on the connection # until we get another token (assumes dyskt will not send consecutive # holds) which should be a resme or stop if self._tC.poll(self._ds[self._i]): token = self._tC.recv() if token == '!STOP!': self._eQ.put(('!STOP!',time.time(),' ')) elif token == '!HOLD!': self._eQ.put(('!HOLD!',time.time(),' ')) token = self._tC.recv() if token == '!RESUME!': self._eQ.put(('!RESUME!',time.time(),' ')) elif token == '!STOP!': self._eQ.put(('!STOP!',time.time(),' ')) else: # no token, go to next channel try: self._i = (self._i+1) % len(self._chs) iw.chset(self._vnic, str(self._chs[self._i][0]), self._chs[self._i][1]) except iw.IWException as e: # iw related exception, set event token and stop execution self._eQ.put(('!FAIL!',time.time(),e)) except Exception as e: # catch all self._eQ.put(('!FAIL!',time.time(),e))
def run(self): """ switch channels based on associted dwell times """ # starting paused or scanning? if self._state == TUNE_PAUSE: # notify rdoctl we are paused then hold on dyskt token q self._qR.put(('!PAUSE!',time.time(),(-1,' '))) self._conn.poll(None) else: self._qR.put(('!SCAN!',time.time(),(-1,self._chs))) # execution loop # wait on the internal connection for each channels dwell time. IOT # avoid a state where we would continue to scan the same channel, i.e. # receiving repeated state commands, use a remaining time counter remaining = 0 while not self._done.is_set(): # set the dwell time to remaining if we need to finish this scan dwell = self._ds[self._i] if not remaining else remaining ts1 = time.time() # mark time if self._conn.poll(dwell): # get token and timestamp tkn = self._conn.recv() ts = time.time() # tokens will have 2 flavor's '!STOP!' and 'cmd:cmdid:params' # where params is empty or a '-' separated list if tkn == '!STOP!': self._qR.put(('!STOP!',ts,(-1,' '))) else: # calculate time remaining for this channel remaining = self._ds[self._i] - (ts-ts1) # parse the requested command try: cmd,cid,ps = tkn.split(':') # force into 3 components cid = int(cid) except: # should never happen but just in case self._qR.put(('!ERR!',ts,(-1,"invalid command format"))) else: # for hold, pause & listen, notify rdoctl & then block # on DySKT until we get another token (assumes DySKT wont # send consecutive holds etc) if cmd == 'state': self._qR.put(('!STATE!',ts,(cid,TUNE_DESC[self._state]))) continue elif cmd == 'scan': if self._state != TUNE_SCAN: self._state = TUNE_SCAN self._qR.put(('!SCAN!',ts,(cid,self._chs))) continue else: self._qR.put(('!ERR!',ts,(cid,'redundant command'))) elif cmd == 'txpwr': pass elif cmd == 'spoof': pass elif cmd == 'hold': if self._state != TUNE_HOLD: self._state = TUNE_HOLD self._qR.put(('!HOLD!',ts,(cid,self.currch))) self._conn.poll(None) # block until a new token continue else: self._qR.put(('!ERR!',ts,(cid,'redundant command'))) elif cmd == 'pause': if self._state != TUNE_PAUSE: self._state = TUNE_PAUSE self._qR.put(('!PAUSE!',ts,(cid,' '))) self._conn.poll(None) # block until a new token continue else: self._qR.put(('!ERR!',ts,(cid,'redundant command'))) elif cmd == 'listen': # for listen, we ignore reduandacies as some other # (external) process may have changed the channel try: ch,chw = ps.split('-') iw.chset(self._vnic,ch,chw) self._state = TUNE_LISTEN self._qR.put(('!LISTEN',ts,(cid,"%s:%s" % (ch,chw)))) self._conn.poll(None) # block until a new token continue except ValueError: self._qR.put(('!ERR!',ts,(cid,'invalid param format'))) except iw.IWException as e: self._qR.put(('!ERR',ts,(cid,e))) else: self._qR.put(('!ERR!',ts,(cid,"invalid command %s" % cmd))) else: # no token, go to next channel try: self._i = (self._i+1) % len(self._chs) iw.chset(self._vnic, str(self._chs[self._i][0]), self._chs[self._i][1]) remaining = 0 # reset remaining except iw.IWException as e: self._qR.put(('!FAIL!',time.time(),(-1,e))) except Exception as e: # blanket exception self._qR.put(('!FAIL!',time.time(),(-1,e)))
def _setup(self,conf): """ 1) sets radio properties as specified in conf 2) prepares specified nic for monitoring and binds it 3) creates a scan list and compile statistics """ # if the nic specified in conf is present, set it if conf['nic'] not in iwt.wifaces(): raise RuntimeError("%s:iwtools.wifaces:not found" % conf['role']) self._nic = conf['nic'] self._role = conf['role'] # get the phy and associated interfaces try: (self._phy,ifaces) = iw.dev(self._nic) self._mac = ifaces[0]['addr'] except (KeyError, IndexError): raise RuntimeError("%s:iw.dev:error getting interfaces" % self._role) except iw.IWException as e: raise RuntimeError("%s:iw.dev:failed to get phy <%s>" % (self._role,e)) # get properties (the below will return None rather than throw exception) self._chs = iw.chget(self._phy) self._std = iwt.iwconfig(self._nic,'Standards') self._txpwr = iwt.iwconfig(self._nic,'Tx-Power') self._driver = iwt.getdriver(self._nic) self._chipset = iwt.getchipset(self._driver) # spoof the mac address ?? if conf['spoofed']: mac = None if conf['spoofed'].lower() == 'random' else conf['spoofed'] try: iwt.ifconfig(self._nic,'down') self._spoofed = iwt.sethwaddr(self._nic,mac) except iwt.IWToolsException as e: raise RuntimeError("%s:iwtools.sethwaddr:%s" % (self._role,e)) # delete all associated interfaces - we want full control for iface in ifaces: iw.devdel(iface['nic']) # determine virtual interface name ns = [] for wiface in iwt.wifaces(): cs = wiface.split('dyskt') try: if len(cs) > 1: ns.append(int(cs[1])) except ValueError: pass n = 0 if not 0 in ns else max(ns)+1 self._vnic = "dyskt%d" % n # sniffing interface try: iw.phyadd(self._phy,self._vnic,'monitor') # create a monitor, iwt.ifconfig(self._vnic,'up') # and turn it on except iw.IWException as e: # never added virtual nic, restore nic errMsg = "%s:iw.phyadd:%s" % (self._role,e) try: iwt.ifconfig(self._nic,'up') except iwt.IWToolsException: errMsg += " Failed to restore %s" % self._nic raise RuntimeError(errMsg) except iwt.IWToolsException as e: # failed to 'raise' virtual nic, remove vnic and add nic errMsg = "%s:iwtools.ifconfig:%s" % (self._role,e) try: iw.phyadd(self._phy,self._nic,'managed') iw.devdel(self._vnic) iwt.ifconfig(self._nic,'up') except (iw.IWException,iwt.IWToolsException): errMsg += " Failed to restore %s" % self._nic raise RuntimeError(errMsg) # wrap remaining in a try block, we must attempt to restore card and # release the socket after any failures ATT self._s = None try: # bind socket w/ a timeout of 5 just in case there is no wireless traffic self._s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003)) self._s.settimeout(5) self._s.bind((self._vnic,0x0003)) uptime = time.time() # read in antenna details and radio description if conf['antennas']['num'] > 0: self._antenna['num'] = conf['antennas']['num'] self._antenna['type'] = conf['antennas']['type'] self._antenna['gain'] = conf['antennas']['gain'] self._antenna['loss'] = conf['antennas']['loss'] self._antenna['x'] = [v[0] for v in conf['antennas']['xyz']] self._antenna['y'] = [v[1] for v in conf['antennas']['xyz']] self._antenna['z'] = [v[2] for v in conf['antennas']['xyz']] self._desc = conf['desc'] # compile initial scan pattern from config scan = [t for t in conf['scan'] if str(t[0]) in self._chs and not t in conf['pass']] # sum hop times with side effect of removing any invalid channel tuples # i.e. Ch 14, Width HT40+ and channels the card cannot tune to i = 0 hop = 0 while scan: try: t = time.time() iw.chset(self._vnic,str(scan[i][0]),scan[i][1]) hop += (time.time() - t) i += 1 except iw.IWException as e: # if invalid argument, drop the channel otherwise reraise error if iw.ecode(str(e)) == iw.IW_INVALIDARG: del scan[i] else: raise except IndexError: # all channels checked break if not scan: raise ValueError("Empty scan pattern") # calculate avg hop time, and interval time # NOTE: these are not currently used but may be useful later hop /= len(scan) interval = len(scan) * conf['dwell'] + len(scan) * hop # create list of dwell times ds = [conf['dwell']] * len(scan) # get start ch & set the initial channel try: ch_i = scan.index(conf['scan_start']) except ValueError: ch_i = 0 iw.chset(self._vnic,str(scan[ch_i][0]),scan[ch_i][1]) # initialize tuner thread self._qT = Queue() self._tuner = Tuner(self._qT,self._conn,self._vnic,scan,ds,ch_i,conf['paused']) # notify RTO we are good self._icomms.put((self._vnic,uptime,'!UP!',self.radio)) except socket.error as e: try: iw.devdel(self._vnic) iw.phyadd(self._phy,self._nic) iwt.ifconfig(self._nic,'up') except (iw.IWException,iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:Raw Socket:%s" % (self._role,e)) except iw.IWException as e: try: iw.devdel(self._vnic) iw.phyadd(self._phy,self._nic) iwt.ifconfig(self._nic,'up') except (iw.IWException,iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:iw.chset:Failed to set channel: %s" % (self._role,e)) except (ValueError,TypeError) as e: try: iw.devdel(self._vnic) iw.phyadd(self._phy,self._nic) iwt.ifconfig(self._nic,'up') except (iw.IWException,iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:config:%s" % (self._role,e)) except Exception as e: # blanket exception try: iw.devdel(self._vnic) iw.phyadd(self._phy,self._nic) iwt.ifconfig(self._nic,'up') except (iw.IWException,iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:Unknown:%s" % (self._role,e))
def run(self): """ switch channels based on associted dwell times """ # starting paused or scanning? if self._state == TUNE_PAUSE: # notify rdoctl we are paused then hold on dyskt token q self._qR.put(('!PAUSE!', time.time(), (-1, ' '))) self._conn.poll(None) else: self._qR.put(('!SCAN!', time.time(), (-1, self._chs))) # execution loop # wait on the internal connection for each channels dwell time. IOT # avoid a state where we would continue to scan the same channel, i.e. # receiving repeated state commands, use a remaining time counter remaining = 0 while not self._done.is_set(): # set the dwell time to remaining if we need to finish this scan dwell = self._ds[self._i] if not remaining else remaining ts1 = time.time() # mark time if self._conn.poll(dwell): # get token and timestamp tkn = self._conn.recv() ts = time.time() # tokens will have 2 flavor's '!STOP!' and 'cmd:cmdid:params' # where params is empty or a '-' separated list if tkn == '!STOP!': self._qR.put(('!STOP!', ts, (-1, ' '))) else: # calculate time remaining for this channel remaining = self._ds[self._i] - (ts - ts1) # parse the requested command try: cmd, cid, ps = tkn.split( ':') # force into 3 components cid = int(cid) except: # should never happen but just in case self._qR.put( ('!ERR!', ts, (-1, "invalid command format"))) else: # for hold, pause & listen, notify rdoctl & then block # on DySKT until we get another token (assumes DySKT wont # send consecutive holds etc) if cmd == 'state': self._qR.put( ('!STATE!', ts, (cid, TUNE_DESC[self._state]))) continue elif cmd == 'scan': if self._state != TUNE_SCAN: self._state = TUNE_SCAN self._qR.put(('!SCAN!', ts, (cid, self._chs))) continue else: self._qR.put( ('!ERR!', ts, (cid, 'redundant command'))) elif cmd == 'txpwr': pass elif cmd == 'spoof': pass elif cmd == 'hold': if self._state != TUNE_HOLD: self._state = TUNE_HOLD self._qR.put( ('!HOLD!', ts, (cid, self.currch))) self._conn.poll( None) # block until a new token continue else: self._qR.put( ('!ERR!', ts, (cid, 'redundant command'))) elif cmd == 'pause': if self._state != TUNE_PAUSE: self._state = TUNE_PAUSE self._qR.put(('!PAUSE!', ts, (cid, ' '))) self._conn.poll( None) # block until a new token continue else: self._qR.put( ('!ERR!', ts, (cid, 'redundant command'))) elif cmd == 'listen': # for listen, we ignore reduandacies as some other # (external) process may have changed the channel try: ch, chw = ps.split('-') iw.chset(self._vnic, ch, chw) self._state = TUNE_LISTEN self._qR.put(('!LISTEN', ts, (cid, "%s:%s" % (ch, chw)))) self._conn.poll( None) # block until a new token continue except ValueError: self._qR.put(('!ERR!', ts, (cid, 'invalid param format'))) except iw.IWException as e: self._qR.put(('!ERR', ts, (cid, e))) else: self._qR.put(('!ERR!', ts, (cid, "invalid command %s" % cmd))) else: # no token, go to next channel try: self._i = (self._i + 1) % len(self._chs) iw.chset(self._vnic, str(self._chs[self._i][0]), self._chs[self._i][1]) remaining = 0 # reset remaining except iw.IWException as e: self._qR.put(('!FAIL!', time.time(), (-1, e))) except Exception as e: # blanket exception self._qR.put(('!FAIL!', time.time(), (-1, e)))
def _setup(self, conf): """ 1) sets radio properties as specified in conf 2) prepares specified nic for monitoring and binds it 3) creates a scan list and compile statistics """ # if the nic specified in conf is present, set it if conf['nic'] not in iwt.wifaces(): raise RuntimeError("%s:iwtools.wifaces:not found" % conf['role']) self._nic = conf['nic'] self._role = conf['role'] # get the phy and associated interfaces try: (self._phy, ifaces) = iw.dev(self._nic) self._mac = ifaces[0]['addr'] except (KeyError, IndexError): raise RuntimeError("%s:iw.dev:error getting interfaces" % self._role) except iw.IWException as e: raise RuntimeError("%s:iw.dev:failed to get phy <%s>" % (self._role, e)) # get properties (the below will return None rather than throw exception) self._chs = iw.chget(self._phy) self._std = iwt.iwconfig(self._nic, 'Standards') self._txpwr = iwt.iwconfig(self._nic, 'Tx-Power') self._driver = iwt.getdriver(self._nic) self._chipset = iwt.getchipset(self._driver) # spoof the mac address ?? if conf['spoofed']: mac = None if conf['spoofed'].lower( ) == 'random' else conf['spoofed'] try: iwt.ifconfig(self._nic, 'down') self._spoofed = iwt.sethwaddr(self._nic, mac) except iwt.IWToolsException as e: raise RuntimeError("%s:iwtools.sethwaddr:%s" % (self._role, e)) # delete all associated interfaces - we want full control for iface in ifaces: iw.devdel(iface['nic']) # determine virtual interface name ns = [] for wiface in iwt.wifaces(): cs = wiface.split('dyskt') try: if len(cs) > 1: ns.append(int(cs[1])) except ValueError: pass n = 0 if not 0 in ns else max(ns) + 1 self._vnic = "dyskt%d" % n # sniffing interface try: iw.phyadd(self._phy, self._vnic, 'monitor') # create a monitor, iwt.ifconfig(self._vnic, 'up') # and turn it on except iw.IWException as e: # never added virtual nic, restore nic errMsg = "%s:iw.phyadd:%s" % (self._role, e) try: iwt.ifconfig(self._nic, 'up') except iwt.IWToolsException: errMsg += " Failed to restore %s" % self._nic raise RuntimeError(errMsg) except iwt.IWToolsException as e: # failed to 'raise' virtual nic, remove vnic and add nic errMsg = "%s:iwtools.ifconfig:%s" % (self._role, e) try: iw.phyadd(self._phy, self._nic, 'managed') iw.devdel(self._vnic) iwt.ifconfig(self._nic, 'up') except (iw.IWException, iwt.IWToolsException): errMsg += " Failed to restore %s" % self._nic raise RuntimeError(errMsg) # wrap remaining in a try block, we must attempt to restore card and # release the socket after any failures ATT self._s = None try: # bind socket w/ a timeout of 5 just in case there is no wireless traffic self._s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003)) self._s.settimeout(5) self._s.bind((self._vnic, 0x0003)) uptime = time.time() # read in antenna details and radio description if conf['antennas']['num'] > 0: self._antenna['num'] = conf['antennas']['num'] self._antenna['type'] = conf['antennas']['type'] self._antenna['gain'] = conf['antennas']['gain'] self._antenna['loss'] = conf['antennas']['loss'] self._antenna['x'] = [v[0] for v in conf['antennas']['xyz']] self._antenna['y'] = [v[1] for v in conf['antennas']['xyz']] self._antenna['z'] = [v[2] for v in conf['antennas']['xyz']] self._desc = conf['desc'] # compile initial scan pattern from config scan = [ t for t in conf['scan'] if str(t[0]) in self._chs and not t in conf['pass'] ] # sum hop times with side effect of removing any invalid channel tuples # i.e. Ch 14, Width HT40+ and channels the card cannot tune to i = 0 hop = 0 while scan: try: t = time.time() iw.chset(self._vnic, str(scan[i][0]), scan[i][1]) hop += (time.time() - t) i += 1 except iw.IWException as e: # if invalid argument, drop the channel otherwise reraise error if iw.ecode(str(e)) == iw.IW_INVALIDARG: del scan[i] else: raise except IndexError: # all channels checked break if not scan: raise ValueError("Empty scan pattern") # calculate avg hop time, and interval time # NOTE: these are not currently used but may be useful later hop /= len(scan) interval = len(scan) * conf['dwell'] + len(scan) * hop # create list of dwell times ds = [conf['dwell']] * len(scan) # get start ch & set the initial channel try: ch_i = scan.index(conf['scan_start']) except ValueError: ch_i = 0 iw.chset(self._vnic, str(scan[ch_i][0]), scan[ch_i][1]) # initialize tuner thread self._qT = Queue() self._tuner = Tuner(self._qT, self._conn, self._vnic, scan, ds, ch_i, conf['paused']) # notify RTO we are good self._icomms.put((self._vnic, uptime, '!UP!', self.radio)) except socket.error as e: try: iw.devdel(self._vnic) iw.phyadd(self._phy, self._nic) iwt.ifconfig(self._nic, 'up') except (iw.IWException, iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:Raw Socket:%s" % (self._role, e)) except iw.IWException as e: try: iw.devdel(self._vnic) iw.phyadd(self._phy, self._nic) iwt.ifconfig(self._nic, 'up') except (iw.IWException, iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:iw.chset:Failed to set channel: %s" % (self._role, e)) except (ValueError, TypeError) as e: try: iw.devdel(self._vnic) iw.phyadd(self._phy, self._nic) iwt.ifconfig(self._nic, 'up') except (iw.IWException, iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:config:%s" % (self._role, e)) except Exception as e: # blanket exception try: iw.devdel(self._vnic) iw.phyadd(self._phy, self._nic) iwt.ifconfig(self._nic, 'up') except (iw.IWException, iwt.IWToolsException): pass if self._s: self._s.shutdown(socket.SHUT_RD) self._s.close() raise RuntimeError("%s:Unknown:%s" % (self._role, e))