def test_fileno(self): require_python(3) ip1 = IPRoute() ip2 = IPRoute(fileno=ip1.fileno()) ip2.bind() try: ip1.bind() except OSError as e: if e.errno != 22: # bind -> Invalid argument raise ip1.close() try: ip2.get_links() except OSError as e: if e.errno != 9: # sendto -> Bad file descriptor raise try: ip2.close() except OSError as e: if e.errno != 9: # close -> Bad file descriptor raise
class Blinker(Thread): def __init__(self): Thread.__init__(self) self.ch = { 'A': '._', 'B': '_...', 'C': '_._.', 'D': '_..', 'E': '.', 'F': '.._.', 'G': '__.', 'H': '....', 'I': '..', 'J': '.___', 'K': '_._', 'L': '._..', 'M': '__', 'N': '_.', 'O': '___', 'P': '.__.', 'Q': '__._', 'R': '._.', 'S': '...', 'T': '_', 'U': '.._', 'V': '..._', 'W': '.__', 'X': '_.._', 'Y': '_.__', 'Z': '__..', '0': '_____', '1': '.____', '2': '..___', '3': '...__', '4': '...._', '5': '.....', '6': '_....', '7': '__...', '8': '___..', '9': '____.', } with open(LEDDEV, "w") as f: f.write("none") with warnings.catch_warnings(): warnings.simplefilter("ignore") self.activity = LED(47, active_high=False) self.activity.off() self.currentStatus = None self.lanConfig = {} self.ipr = IPRoute() self.ipAddr = None self.eth = None self.wlan = None self.curDev = None #parse ip address from dhcpcd.conf #these are expected static ip addresses #self.dev = 'wlan0' #self.devl = 'eth0' with open("/etc/wpa_supplicant/wpa_supplicant.conf", "r") as f: re1 = re.compile('ssid\s*=\s*"?(\w*?)"?$') re2 = re.compile('key_mgmt\s*=\s*"?([\w_\-]*?)"?$') txt = f.read() for line in txt.split('\n'): line = line.strip() if len(line) > 0 and line[0] != '#': rr1 = re1.search(line) rr2 = re2.search(line) if rr1: self.expectedWifi = rr1.group(1) print "WIFI config name: %s" % self.expectedWifi elif rr2: self.expectedWifiType = rr2.group(1) print "WIFI config type: %s" % self.expectedWifiType else: #print line pass with open("/etc/dhcpcd.conf", "r") as f: txt = f.read() re1 = re.compile('^interface\s+(.+)$') re2 = re.compile('^static\s+(\w+)\s*=\s*(.+)$') intf = '' for line in txt.split('\n'): if intf: #other interface mm1 = re1.search(line) if mm1: intf = mm1.group(1) self.lanConfig[intf] = {} if intf.startswith("wlan"): self.wlan = intf elif intf.startswith("eth"): self.eth = intf if len(line) > 7 and line[0] != '#': zz = re2.search(line) if zz: self.lanConfig[intf][zz.group(1)] = zz.group( 2).split('/') else: mm1 = re1.search(line) if mm1: intf = mm1.group(1) if intf.startswith("wlan"): self.wlan = intf elif intf.startswith("eth"): self.eth = intf self.lanConfig[intf] = {} #actual name server set to resolv.conf self.actualNameServer = None with open("/etc/resolv.conf", "r") as f: txt = f.read() re1 = re.compile('^nameserver\s+([\.\d]+)$') intf = '' for line in txt.split('\n'): r = re1.search(line) if r: self.actualNameserver = r.group(1) self.curDev = None self.terminate = Event() self.setCurrentStatus('OK') def getCurrentStatusOK(self): return self.currentStatus == 'OK' def setCurrentStatus(self, st): if self.currentStatus != st: if self.currentStatus != None: print "%s - status %s set" % (asctime(), st) self.currentStatus = st return (st == 'OK') def end(self): if self.terminate.wait(0): return print "Ctrl-C pressed - will exit in few seconds" self.activity.off() with open(LEDDEV, "w") as f: f.write("mmc0") self.terminate.set() self.ipr.close() self.ipr = None def checkStatus(self): #if eth is up, then use treat it as main i/f self.curDev = None self.ipAddr = None self.setCurrentStatus('OK') if self.eth and self.lanConfig[self.eth]: ret = self.ifconfig(self.eth) #see check eth i/f is up if ret: if self.lanConfig[self.eth]['ip_address'][0] == ret[0]: #got right ip address print "Got LAN ip address: %s" % ret[0] self.ipAddr = ret[0] self.curDev = self.eth self.setCurrentStatus('OK') else: print "wrong ip address for dev %s: %s" % (self.eth, ret[0]) self.setCurrentStatus('X') #if eth is not up and wlan is configured if self.wlan and self.lanConfig[self.wlan] and not self.ipAddr: #if LAN is not up, check wifi device status ret = self.iwconfig(self.wlan) #see if wifi is connected if not ret: return self.curDev = self.wlan #print "WIFI = OK (%s:%s)" % (self.wlan,self.currentWifi) ret = self.ifconfig(self.wlan) #see check wlan i/f is up if ret: self.curDev = self.wlan if self.lanConfig[self.wlan]['ip_address'][0] == ret[0]: print "Got WIFI ip address: %s" % ret[0] self.ipAddr = ret[0] self.setCurrentStatus('OK') else: print "wrong ip address for dev %s: %s" % (self.wlan, ret[0]) self.setCurrentStatus('X') if not self.ipAddr: print "both eth and wlan are down, status=%s" % self.currentStatus return #check IP conflict if not self.arp(): return if self.terminate.wait(0): return self.gw = self.lanConfig[self.curDev]['routers'][0] self.dns = self.lanConfig[self.curDev]['domain_name_servers'][0] self.setCurrentStatus('OK') ret = self.route(self.curDev) if not ret: return print "Got default route, %s" % self.gw if self.terminate.wait(0): return #print self.lanConfig[self.curDev] #ret = self.ping(self.actualNameServer) #ping dns #print ret ret = self.ping(self.gw) #ping g/w if not ret: print "G/W ping failed" self.setCurrentStatus('P') return self.setCurrentStatus('OK') #print "All OK" def runCmd(self, cmd, re1=None): p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) ok = False for i in range(0, 5): if p.poll() is not None: ok = True out, err = p.communicate() break sleep(1) if not ok: p.kill() print "failed 1 %s" % cmd return None if not re1: return out if type(re1).__name__ == 'SRE_Pattern': re1 = [re1] for rrr in re1: for line in out.split("\n"): rr1 = rrr.search(line.strip()) #print line if rr1: return rr1 #print ">> " + line #print re1.pattern #print "failed 2 " + cmd return None def iwconfig(self, dev): cmd = "/sbin/iwconfig %s | grep SSID" % dev r = re.compile('SSID:"(.+?)"') ret = self.runCmd(cmd, r) self.currentWifi = ret.group(1) if ret else None print "WIFI connected: %s" % self.currentWifi if self.currentWifi is not None: return True return self.setCurrentStatus( 'W') # wifi is configured but not connected def arp(self): #check IP conflict for n in self.ipr.get_neighbours(): attrs = Attrs(n['attrs'] if 'attrs' in n else None) if attrs and attrs.NDA_LLADDR == '00:00:00:00:00:00': continue if attrs.NDA_DST == self.ipAddr: print "detect conflict with with mac addr %s" % (NDA_LLADDR) return self.setCurrentStatus('D') print "ip address %s has no conflict" % self.ipAddr return True def route(self, dev): gwmatch = False for n in self.ipr.get_routes(): if 'family' in n and n['family'] != 2: #ipv4 only continue attrs = Attrs(n['attrs'] if 'attrs' in n else None) #print attrs if attrs and attrs.RTA_GATEWAY == self.gw: gwmatch = True if not gwmatch: print "default g/w doesn't match with config: %s" % attrs.RTA_GATEWAY self.setCurrentStatus('G') return self.getCurrentStatusOK() def ifconfig(self, dev): for dd in self.ipr.get_links(): #filter may not work always attrs = Attrs(dd['attrs'] if 'attrs' in dd else None) if attrs and attrs.IFLA_IFNAME == dev: #print "dev:%s,index: %s" % (dev,dd['index']) aa = self.ipr.get_addr(index=dd['index']) if aa: attrs = Attrs(aa[0]['attrs'] if 'attrs' in aa[0] else None) return (attrs.IFA_ADDRESS, attrs.IFA_BROADCAST) if attrs else None return None def ping(self, ipaddr=None): cmd = "/bin/ping -t1 -c3 %s" % ipaddr r = re.compile( '^rtt min/avg/max/mdev = ([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms$' ) ret = self.runCmd(cmd, r) return ret.groups() if ret else None def run(self): self.blink() #print "blinker thread ended" def changeDetector(self): if not self.ipr: return try: self.ipr.bind() except: print "Exception: %s" % traceback.format_exc() return self.checkerTimer = None def checker(): print "%s - checker invoked" % asctime() self.checkerTimer = None self.checkStatus() def checkerInvoker(): if not self.checkerTimer: print "%s - network state changed" % asctime() self.checkerTimer = Timer(8, checker) self.checkerTimer.start() while not self.terminate.wait(.1): if not self.ipr: return try: ret = select([self.ipr], [], [], 5) if len(ret[0]) == 0: continue for msg in self.ipr.get(): if 'family' in msg and msg['family'] != 2: #ipv4 only continue attrs = Attrs(msg['attrs'] if 'attrs' in msg else None) event = msg['event'] #print 'change detected: %s' % event msg.pop('event', None) msg.pop('attrs', None) msg.pop('header', None) if event in ("RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR"): #print "%s - %s" % (asctime(),event) checkerInvoker() elif event in ("RTM_NEWROUTE", "RTM_DELROUTE", "RTM_GETROUTE"): #print "%s - %s" % (asctime(),event) checkerInvoker() elif event in ("RTM_NEWNEIGH"): if attrs.NDA_LLADDR == '00:00:00:00:00:00': continue if attrs.NDA_DST == self.ipAddr: print "detect conflict with with mac addr %s" % ( NDA_LLADDR) self.setCurrentStatus('D') except selerr, e: if e[0] != 4: print "Exception: %s" % e break except:
from pyroute2 import IPRoute with IPRoute() as ipr: print([x.get_attr('IFLA_IFNAME') for x in ipr.get_links()]) # create RTNL socket ipr = IPRoute() # subscribe to broadcast messages ipr.bind() n = ipr.sendto([1,2],{'1':1,'2':2}) print(n) # wait for data (do not parse it) data = ipr.recv(65535) # parse received data messages = ipr.marshal.parse(data) # shortcut: recv() + parse() # # (under the hood is much more, but for # simplicity it's enough to say so) # messages = ipr.get()
class Monitor(object): """Network status change monitor Monitor is an event drive network status monitor, it will trigger a read signal only if network has any change. This is a netlink API wrapper for fluxmonitord watcher. We implement a fake netlink API for darwin.""" def __init__(self, cb=None): self.callback = cb self.ipr = IPRoute() self.ipr.bind(groups=BIND_GROUPS) def fileno(self): return self.ipr.fileno() # Trigger when self.ipr has data in buffer (Call by event looper) def on_read(self, sender): # Read all message and drop it. Because it is hard to analyze incomming # message, we will query full information and collect it instead. for item in self.ipr.get(): if item.get('event') not in [ "RTM_NEWNEIGH", "RTM_NEWROUTE", "RTM_DELROUTE", "RTM_GETROUTE", ]: # Update status only if event is not RTM_NEWNEIGH or we will # get many dummy messages. status = self.full_status() self.callback(status) return def read(self): for change in self.ipr.get(): if change.get('event') not in [ "RTM_NEWNEIGH", "RTM_NEWROUTE", "RTM_DELROUTE", "RTM_GETROUTE", ]: logger.debug("NW EVENT: %s", change["event"]) return True return False # Query full network information and collect it to flux internal pattern. def full_status(self): status = {} for nic in self.ipr.get_links(): info = dict(nic['attrs']) ifname = info.get('IFLA_IFNAME', 'lo') if ifname.startswith('lo') or ifname.startswith("mon."): continue ifindex = nic.get('index', -1) ifmac = info.get('IFLA_ADDRESS', '??') ifstatus = info.get('IFLA_OPERSTATE', '??') ifcarrier = info.get('IFLA_CARRIER', 0) == 1 st = { 'ifindex': ifindex, 'ifmac': ifmac, 'ifstatus': ifstatus, 'ifcarrier': ifcarrier, 'ipaddr': [] } status[ifname] = st for addr in self.ipr.get_addr(): info = dict(addr['attrs']) ifname = info.get('IFA_LABEL', 'lo') ifname = ifname.split(':')[0] if ifname in status: status[ifname]['ipaddr'].append([ info.get('IFA_ADDRESS', '0.0.0.0'), addr.get('prefixlen', 32) ]) return status def get_ipaddresses(self, ifname="wlan0"): addresses = [] for addr in self.ipr.get_addr(): info = dict(addr['attrs']) if info.get("IFA_LABEL") == ifname: addr = info.get('IFA_ADDRESS') if addr and addr != "127.0.0.1" and addr != "::1": addresses.append(addr) return addresses def get_all_ipaddresses(self): addresses = {} for addr in self.ipr.get_addr(): info = dict(addr['attrs']) ifname = info.get("IFA_LABEL") if ifname and ifname != "lo": addr = info.get('IFA_ADDRESS') if addr and addr != "127.0.0.1" and addr != "::1": addresses[ifname] = addr return addresses def get_all_links(self): linkaddr = {} for addr in self.ipr.get_links(): info = dict(addr['attrs']) ifname = info.get("IFLA_IFNAME") if ifname and ifname != "lo": addr = info.get('IFLA_ADDRESS') if addr: linkaddr[ifname] = addr return linkaddr def close(self): self.ipr.close()