# -*- coding: utf-8 -*- # vim: ts=4 ### # # Copyright (c) 2006 Mehdi Abaakouk # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA # ### import socket import sys BUFSIZE = 4096 SUCCESS_CODES = { "0000" : "OK", "0001" : "Welcome", "0002" : "Reading configuration", "0003" : "Reconfigured", "0004" : "Reconfiguration in progress", "0005" : "Reconfiguration already in progress, queueing", "0006" : "Reconfiguration ignored, shutting down", "0007" : "Shutdown ordered", "0008" : "Already disabled", "0009" : "Disabled", "0010" : "Already enabled", "0011" : "Enabled", "0012" : "Restarted", "0013" : "Status report", "0014" : "Route count", "0015" : "Reloading", "0016" : "Access restricted", } TABLES_ENTRY_CODES = { "1000" : "BIRD version", "1001" : "Interface list", "1002" : "Protocol list", "1003" : "Interface address", "1004" : "Interface flags", "1005" : "Interface summary", "1006" : "Protocol details", "1007" : "Route list", "1008" : "Route details", "1009" : "Static route list", "1010" : "Symbol list", "1011" : "Uptime", "1012" : "Route extended attribute list", "1013" : "Show ospf neighbors", "1014" : "Show ospf", "1015" : "Show ospf interface", "1016" : "Show ospf state/topology", "1017" : "Show ospf lsadb", "1018" : "Show memory", } ERROR_CODES = { "8000" : "Reply too long", "8001" : "Route not found", "8002" : "Configuration file error", "8003" : "No protocols match", "8004" : "Stopped due to reconfiguration", "8005" : "Protocol is down => cannot dump", "8006" : "Reload failed", "8007" : "Access denied", "9000" : "Command too long", "9001" : "Parse error", "9002" : "Invalid symbol type", } END_CODES = ERROR_CODES.keys() + SUCCESS_CODES.keys() global bird_sockets bird_sockets = {} def BirdSocketSingleton(host, port): global bird_sockets s = bird_sockets.get((host,port), None) if not s: s = BirdSocket(host,port) bird_sockets[(host,port)] = s return s class BirdSocket: def __init__(self, host="", port="", file=""): self.__file = file self.__host = host self.__port = port self.__sock = None def __connect(self): if self.__sock: return if not file: self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__sock.settimeout(3.0) self.__sock.connect((self.__host, self.__port)) else: self.__sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.__sock.settimeout(3.0) self.__sock.connect(self.__file) # read welcome message self.__sock.recv(1024) self.cmd("restrict") def close(self): if self.__sock: try: self.__sock.close() except: pass self.__sock = None def cmd(self, cmd): try: self.__connect() self.__sock.send(cmd + "\n") data = self.__read() return data except socket.error: why = sys.exc_info()[1] self.close() return False, "Bird connection problem: %s" % why def __read(self): code = "7000" # Not used in bird parsed_string = "" lastline = "" while code not in END_CODES: data = self.__sock.recv(BUFSIZE) lines = (lastline + data).split("\n") if len(data) == BUFSIZE: lastline = lines[-1] lines = lines[:-1] for line in lines: code = line[0:4] if not line.strip(): continue elif code == "0000": return True, parsed_string elif code in SUCCESS_CODES.keys(): return True, SUCCESS_CODES.get(code) elif code in ERROR_CODES.keys(): return False, ERROR_CODES.get(code) elif code[0] in [ "1", "2"] : parsed_string += line[5:] + "\n" elif code[0] == " ": parsed_string += line[1:] + "\n" elif code[0] == "+": parsed_string += line[1:] else: parsed_string += "<<>>\n"%line return True, parsed_string __all__ = ['BirdSocketSingleton', 'BirdSocket']