def cmdline(cmdarg): route = ''.join(cmdarg.payload).replace(' ', '') if not is_bgp(route): # parser.print_usage() sys.stdout.write('Environment values are:\n%s\n\n' % '\n'.join(' - %s' % _ for _ in Env.default())) sys.stdout.write('The BGP message must be an hexadecimal string.\n\n') sys.stdout.write('All colons or spaces are ignored, for example:\n\n') sys.stdout.write(' 001E0200000007900F0003000101\n') sys.stdout.write(' 001E:02:0000:0007:900F:0003:0001:01\n') sys.stdout.write( ' FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF001E0200000007900F0003000101\n') sys.stdout.write( ' FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:0000:0007:900F:0003:0001:01\n' ) sys.stdout.write( " FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 001E02 00000007900F0003000101\n" ) sys.stdout.flush() sys.exit(1) env = getenv() env.bgp.passive = True env.log.parser = True env.tcp.bind = '' if cmdarg.debug: env.log.all = True env.log.level = 'DEBUG' if cmdarg.pdb: env.debug.pdb = True log.init(env) trace_interceptor(env.debug.pdb) sanitized = ''.join(cmdarg.payload).replace(':', '').replace(' ', '') if cmdarg.configuration: configuration = Configuration([getconf(cmdarg.configuration)]) elif cmdarg.family: families = cmdarg.family.split() if len(families) % 2: sys.stdout.write('families provided are invalid') sys.stdout.flush() sys.exit(1) families_pair = [families[n:n + 2] for n in range(0, len(families), 2)] families_text = ';'.join([f'{a} {s}' for a, s in families_pair]) conf = conf_none.replace('[families]', families_text) configuration = Configuration([conf], text=True) else: configuration = Configuration([conf_all], text=True) valid_nlri = Reactor(configuration).check(sanitized, cmdarg.nlri) if valid_nlri: return 0 return 1
def cmdline(cmdarg): env = getenv() # Must be done before setting the logger as it modify its behaviour if cmdarg.verbose: env.log.all = True env.log.level = syslog.LOG_DEBUG log.init() if cmdarg.pdb: env.debug.pdb = True if cmdarg.verbose: env.log.parser = True for configuration in cmdarg.configuration: log.notice(f'loading {configuration}', 'configuration') location = getconf(configuration) if not location: log.critical(f'{configuration} is not an exabgp config file', 'configuration') sys.exit(1) config = Reactor([location]).configuration if not config.reload(): log.critical(f'{configuration} is not a valid config file', 'configuration') sys.exit(1) log.info(f'\u2713 loading', 'configuration') if cmdarg.neighbor: log.notice(f'checking neighbors', 'configuration') for name, neighbor in config.neighbors.items(): reparsed = neighbor.string() for line in reparsed.split('\n'): log.debug(line, configuration) log.info(f'\u2713 neighbor {name.split()[1]}', 'configuration') if cmdarg.route: log.notice(f'checking routes', 'configuration') if not check_generation(config.neighbors): log.critical(f'{configuration} has an invalid route', 'configuration') sys.exit(1) log.info(f'\u2713 routes', 'configuration')
def cmdline(cmdarg): route = ''.join(cmdarg.payload).replace(' ', '') if not is_bgp(route): # parser.print_usage() sys.stdout.write('Environment values are:\n%s\n\n' % '\n'.join(' - %s' % _ for _ in Env.default())) sys.stdout.write('The BGP message must be an hexadecimal string.\n\n') sys.stdout.write('All colons or spaces are ignored, for example:\n\n') sys.stdout.write(' 001E0200000007900F0003000101\n') sys.stdout.write(' 001E:02:0000:0007:900F:0003:0001:01\n') sys.stdout.write( ' FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF001E0200000007900F0003000101\n') sys.stdout.write( ' FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:0000:0007:900F:0003:0001:01\n' ) sys.stdout.write( " FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 001E02 00000007900F0003000101\n" ) sys.stdout.flush() sys.exit(1) env = getenv() env.bgp.passive = True env.log.parser = True env.tcp.bind = '' if cmdarg.debug: env.log.all = True env.log.level = 'DEBUG' if cmdarg.pdb: env.debug.pdb = True log.init(env) trace_interceptor(env.debug.pdb) sanitized = ''.join(cmdarg.payload).replace(':', '').replace(' ', '') Reactor([getconf(cmdarg.configuration)]).check(sanitized)
def cmdline(cmdarg): route = ''.join(cmdarg.payload).replace(' ', '') if not is_bgp(route): # parser.print_usage() sys.stdout.write('Environment values are:\n%s\n\n' % '\n'.join(' - %s' % _ for _ in Env.default())) sys.stdout.write('The BGP message must be an hexadecimal string.\n\n') sys.stdout.write('All colons or spaces are ignored, for example:\n\n') sys.stdout.write(' 001E0200000007900F0003000101\n') sys.stdout.write(' 001E:02:0000:0007:900F:0003:0001:01\n') sys.stdout.write( ' FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF001E0200000007900F0003000101\n') sys.stdout.write( ' FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:0000:0007:900F:0003:0001:01\n' ) sys.stdout.write( " FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 001E02 00000007900F0003000101\n" ) sys.stdout.flush() sys.exit(1) env = getenv() env.log.parser = True env.debug.route = route env.tcp.bind = '' if cmdarg.debug: env.log.all = True env.log.level = syslog.LOG_DEBUG if cmdarg.pdb: env.debug.pdb = True log.init() Reactor([cmdarg.configuration]).run(False, ROOT)
def run(self): self.daemon.daemonise() # Make sure we create processes once we have closed file descriptor # unfortunately, this must be done before reading the configuration file # so we can not do it with dropped privileges self.processes = Processes() # we have to read the configuration possibly with root privileges # as we need the MD5 information when we bind, and root is needed # to bind to a port < 1024 # this is undesirable as : # - handling user generated data as root should be avoided # - we may not be able to reload the configuration once the privileges are dropped # but I can not see any way to avoid it for ip in self._ips: if not self.listener.listen_on(ip, None, self._port, None, False, None): return self.Exit.listening if not self.reload(): return self.Exit.configuration for neighbor in self.configuration.neighbors.values(): if neighbor['listen']: if not self.listener.listen_on( neighbor['md5-ip'], neighbor['peer-address'], neighbor['listen'], neighbor['md5-password'], neighbor['md5-base64'], neighbor['incoming-ttl'], ): return self.Exit.listening if not self.early_drop: self.processes.start(self.configuration.processes) if not self.daemon.drop_privileges(): log.critical( 'could not drop privileges to \'%s\' refusing to run as root' % self.daemon.user, 'reactor') log.critical( 'set the environmemnt value exabgp.daemon.user to change the unprivileged user', 'reactor') return self.Exit.privileges if self.early_drop: self.processes.start(self.configuration.processes) # This is required to make sure we can write in the log location as we now have dropped root privileges log.init(getenv()) if not self.daemon.savepid(): return self.Exit.pid wait = getenv().tcp.delay if wait: sleeptime = (wait * 60) - int(time.time()) % (wait * 60) log.debug('waiting for %d seconds before connecting' % sleeptime, 'reactor') time.sleep(float(sleeptime)) workers = {} peers = set() api_fds = [] ms_sleep = int(self._sleep_time * 1000) while True: try: if self.signal.received: signaled = self.signal.received # report that we received a signal for key in self._peers: if self._peers[key].neighbor.api['signal']: self._peers[key].reactor.processes.signal( self._peers[key].neighbor, self.signal.number) self.signal.rearm() # we always want to exit if signaled == Signal.SHUTDOWN: self.exit_code = self.Exit.normal self.shutdown() break # it does mot matter what we did if we are restarting # as the peers and network stack are replaced by new ones if signaled == Signal.RESTART: self.restart() continue # did we complete the run of updates caused by the last SIGUSR1/SIGUSR2 ? if self._pending_adjribout(): continue if signaled == Signal.RELOAD: self.reload() self.processes.start(self.configuration.processes, False) continue if signaled == Signal.FULL_RELOAD: self.reload() self.processes.start(self.configuration.processes, True) continue if self.listener.incoming(): # check all incoming connection self.asynchronous.schedule( str(uuid.uuid1()), 'checking for new connection(s)', self.listener.new_connections()) sleep = ms_sleep # do not attempt to listen on closed sockets even if the peer is still here for io in list(workers.keys()): if io == -1: self._poller.unregister(io) del workers[io] peers = self.active_peers() # give a turn to all the peers for key in list(peers): peer = self._peers[key] # limit the number of message handling per second if self._rate_limited(key, peer.neighbor['rate-limit']): peers.discard(key) continue # handle the peer action = peer.run() # .run() returns an ACTION enum: # * immediate if it wants to be called again # * later if it should be called again but has no work atm # * close if it is finished and is closing down, or restarting if action == ACTION.CLOSE: if key in self._peers: del self._peers[key] peers.discard(key) # we are loosing this peer, not point to schedule more process work elif action == ACTION.LATER: io = peer.socket() if io != -1: self._poller.register( io, select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLNVAL | select.POLLERR) workers[io] = key # no need to come back to it before a a full cycle peers.discard(key) elif action == ACTION.NOW: sleep = 0 if not peers: break # read at least on message per process if there is some and parse it for service, command in self.processes.received(): self.api.text(self, service, command) sleep = 0 self.asynchronous.run() if api_fds != self.processes.fds: for fd in api_fds: if fd == -1: continue if fd not in self.processes.fds: self._poller.unregister(fd) for fd in self.processes.fds: if fd == -1: continue if fd not in api_fds: self._poller.register( fd, select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLNVAL | select.POLLERR) api_fds = self.processes.fds for io in self._wait_for_io(sleep): if io not in api_fds: peers.add(workers[io]) if self._stopping and not self._peers.keys(): self._termination('exiting on peer termination', self.Exit.normal) except KeyboardInterrupt: self._termination('^C received', self.Exit.normal) except SystemExit: self._termination('exiting', self.Exit.normal) # socket.error is a subclass of IOError (so catch it first) except socket.error: self._termination('socket error received', self.Exit.socket) except IOError: self._termination( 'I/O Error received, most likely ^C during IO', self.Exit.io_error) except ProcessError: self._termination( 'Problem when sending message(s) to helper program, stopping', self.Exit.process) except select.error: self._termination('problem using select, stopping', self.Exit.select) return self.exit_code
from exabgp.bgp.message import Open from exabgp.bgp.message.open import Version from exabgp.bgp.message.open import ASN from exabgp.bgp.message.open import RouterID from exabgp.bgp.message.open import HoldTime from exabgp.bgp.message.open.capability import Capabilities from exabgp.bgp.message.open.capability import Capability from exabgp.bgp.message.open.capability import Negotiated from exabgp.bgp.message.update.nlri import NLRI from exabgp.bgp.message.direction import Direction from exabgp.logger import log from exabgp.environment import getenv log.init(getenv()) bodies = [] # fmt: off body = [ 0x0, 0x0, # len withdrawn routes # No routes to remove # Attributes 0x0, 0x30, # len attributes (48) 0x40, # Flag Transitive 0x1, # Code : Attribute ID Origin 0x1, # len 0x0, # Origin : IGP
def cmdline(cmdarg): if not os.path.isfile(ENVFILE): comment = 'environment file missing\ngenerate it using "exabgp env --fi > %s"' % ENVFILE else: comment = '' env = getenv() # Must be done before setting the logger as it modify its behaviour if cmdarg.debug: env.log.all = True env.log.level = syslog.LOG_DEBUG log.init() if cmdarg.profile: env.profile.enable = True env.profile.file = cmdarg.profile if cmdarg.once: env.tcp.once = True if cmdarg.pdb: env.debug.pdb = True if cmdarg.test: env.log.parser = True if cmdarg.memory: env.debug.memory = True if env.cache.attributes: Attribute.caching = env.cache.attributes configurations = [] for configuration in cmdarg.configuration: location = getconf(configuration) if not location: log.critical(f'{configuration} is not an exabgp config file', 'configuration') sys.exit(1) configurations.append(configuration) delay = cmdarg.signal _delayed_signal(delay, signal.SIGUSR1) if env.debug.rotate or len(configurations) == 1: run(comment, configurations, cmdarg.validate) if not (env.log.destination in ('syslog', 'stdout', 'stderr') or env.log.destination.startswith('host:')): log.error('can not log to files when running multiple configuration (as we fork)', 'configuration') sys.exit(1) try: # run each configuration in its own process pids = [] for configuration in configurations: pid = os.fork() if pid == 0: run(comment, [configuration], cmdarg.validate, os.getpid()) else: pids.append(pid) # If we get a ^C / SIGTERM, ignore just continue waiting for our child process signal.signal(signal.SIGINT, signal.SIG_IGN) # wait for the forked processes for pid in pids: os.waitpid(pid, 0) except OSError as exc: log.critical('can not fork, errno %d : %s' % (exc.errno, exc.strerror), 'reactor') sys.exit(1)
from exabgp.bgp.message.open.holdtime import HoldTime from exabgp.bgp.message import Update from exabgp.bgp.message import Open from exabgp.bgp.message.open import Version from exabgp.bgp.message.open import ASN from exabgp.bgp.message.open import RouterID from exabgp.bgp.message.open import HoldTime from exabgp.bgp.message.open.capability import Capabilities from exabgp.bgp.message.open.capability import Capability from exabgp.bgp.message.open.capability import Negotiated from exabgp.bgp.message.update.nlri import NLRI from exabgp.logger import log log.init() bodies = [] # fmt: off body = [ 0x0, 0x0, # len withdrawn routes # No routes to remove # Attributes 0x0, 0x30, # len attributes (48) 0x40, # Flag Transitive 0x1, # Code : Attribute ID Origin 0x1, # len 0x0, # Origin : IGP