Esempio n. 1
0
    def _start(self, process):
        try:
            if process in self._process:
                self.logger.debug('process already running', 'process')
                return
            if process not in self._configuration:
                self.logger.debug(
                    'can not start process, no configuration for it',
                    'process')
                return
            # Prevent some weird termcap data to be created at the start of the PIPE
            # \x1b[?1034h (no-eol) (esc)
            os.environ['TERM'] = 'dumb'

            configuration = self._configuration[process]

            run = configuration.get('run', '')
            if run:
                api = configuration.get('encoder', '')
                self._encoder[process] = Response.Text(
                    text_version) if api == 'text' else Response.JSON(
                        json_version)

                self._process[process] = subprocess.Popen(
                    run,
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    preexec_fn=preexec_helper
                    # This flags exists for python 2.7.3 in the documentation but on on my MAC
                    # creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
                )
                self._update_fds()
                fcntl.fcntl(self._process[process].stdout.fileno(),
                            fcntl.F_SETFL, os.O_NONBLOCK)

                self.logger.debug('forked process %s' % process, 'process')

                around_now = int(time.time()) & self.respawn_timemask
                if process in self._respawning:
                    if around_now in self._respawning[process]:
                        self._respawning[process][around_now] += 1
                        # we are respawning too fast
                        if self._respawning[process][
                                around_now] > self.respawn_number:
                            self.logger.critical(
                                'Too many death for %s (%d) terminating program'
                                % (process, self.respawn_number), 'process')
                            raise ProcessError()
                    else:
                        # reset long time since last respawn
                        self._respawning[process] = {around_now: 1}
                else:
                    # record respawing
                    self._respawning[process] = {around_now: 1}

        except (subprocess.CalledProcessError, OSError, ValueError) as exc:
            self._broken.append(process)
            self.logger.debug('could not start process %s' % process,
                              'process')
            self.logger.debug('reason: %s' % str(exc), 'process')
Esempio n. 2
0
 def parsed(_):
     # we need the import in the function as otherwise we have an cyclic loop
     # as this function currently uses Update..
     from exabgp.reactor.api.response import Response
     from exabgp.version import json as json_version
     return 'json %s' % Response.JSON(json_version).update(
         negotiated.neighbor, 'in', update, None, '', '')
Esempio n. 3
0
def check_update(neighbor, raw):
    option.enabled['parser'] = True
    negotiated = _negotiated(neighbor)

    while raw:
        if raw.startswith(b'\xff' * 16):
            kind = raw[18]
            size = (raw[16] << 16) + raw[17]

            injected, raw = raw[19:size], raw[size:]

            if kind == 2:
                log.debug('the message is an update', 'parser')
                decoding = 'update'
            else:
                log.debug(
                    'the message is not an update (%d) - aborting' % kind,
                    'parser')
                return False
        else:
            log.debug('header missing, assuming this message is ONE update',
                      'parser')
            decoding = 'update'
            injected, raw = raw, ''

        try:
            # This does not take the BGP header - let's assume we will not break that :)
            update = Update.unpack_message(injected, Direction.IN, negotiated)
        except Notify:
            import traceback

            log.error('could not parse the message', 'parser')
            log.error(traceback.format_exc(), 'parser')
            if getenv().debug.pdb:
                raise
            return False
        except Exception:
            import traceback

            log.error('could not parse the message', 'parser')
            log.error(traceback.format_exc(), 'parser')
            if getenv().debug.pdb:
                raise
            return False

        log.debug('', 'parser')  # new line
        for number in range(len(update.nlris)):
            change = Change(update.nlris[number], update.attributes)
            log.info(
                'decoded %s %s %s' %
                (decoding, change.nlri.action, change.extensive()), 'parser')
        log.info(
            'update json %s' % Response.JSON(json_version).update(
                neighbor, 'in', update, None, '', ''), 'parser')

    return True
Esempio n. 4
0
File: bmp.py Progetto: qoke/exabgp
 def setup(self, environ, ip, port):
     self.handle = {
         Message.ROUTE_MONITORING: self._route,
         Message.STATISTICS_REPORT: self._statistics,
         Message.PEER_DOWN_NOTIFICATION: self._peer,
     }
     self.asn4 = environ.bmp.asn4
     self.use_json = environ.bmp.json
     self.fd = environ.fd
     self.ip = ip
     self.port = port
     self.json = Response.JSON(json_version)
     return self
Esempio n. 5
0
class Transcoder(object):
    seen_open = {
        'send': None,
        'receive': None,
    }
    negotiated = None

    json = Response.JSON(json_version)

    def __init__(self, src='json', dst='json'):
        if src != 'json':
            raise RuntimeError('left as an exercise to the reader')

        if dst != 'json':
            raise RuntimeError('left as an exercise to the reader')

        self.convert = self._from_json
        self.encoder = self.json

    def _state(self):
        self.seen_open['send'] = None
        self.seen_open['receive'] = None
        self.negotiated = None

    def _open(self, direction, message):
        self.seen_open[direction] = message

        if all(self.seen_open.values()):
            self.negotiated = Negotiated(None)
            self.negotiated.sent(self.seen_open['send'])
            self.negotiated.received(self.seen_open['receive'])

    def _from_json(self, direction, json_string):
        try:
            parsed = json.loads(json_string)
        except ValueError:
            print('invalid JSON message', file=sys.stderr)
            sys.exit(1)

        if parsed.get('exabgp', '0.0.0') != json_version:
            print('invalid json version', json_string, file=sys.stderr)
            sys.exit(1)

        content = parsed.get('type', '')

        if not content:
            print('invalid json content', json_string, file=sys.stderr)
            sys.exit(1)

        neighbor = _FakeNeighbor(
            parsed['neighbor']['address']['local'],
            parsed['neighbor']['address']['peer'],
            parsed['neighbor']['asn']['local'],
            parsed['neighbor']['asn']['peer'],
        )

        if content == 'state':
            self._state()
            return json_string

        direction = parsed['neighbor']['direction']
        category = parsed['neighbor']['message']['category']
        header = parsed['neighbor']['message']['header']
        body = parsed['neighbor']['message']['body']
        data = b''.join(bytes([int(body[_ : _ + 2], 16)]) for _ in range(0, len(body), 2))

        if content == 'open':
            message = Open.unpack_message(data)
            self._open(direction, message)
            return self.encoder.open(neighbor, direction, message, None, header, body)

        if content == 'keepalive':
            return self.encoder.keepalive(neighbor, direction, None, header, body)

        if content == 'notification':
            # XXX: Use the code of the Notifcation class here ..
            message = Notification.unpack_message(data)

            if (message.code, message.subcode) != (6, 2):
                message.data = data if not len([_ for _ in data if _ not in string.printable]) else hexstring(data)
                return self.encoder.notification(neighbor, direction, message, None, header, body)

            if len(data) == 0:
                # shutdown without shutdown communication (the old fashioned way)
                message.data = ''
                return self.encoder.notification(neighbor, direction, message, None, header, body)

            # draft-ietf-idr-shutdown or the peer was using 6,2 with data

            shutdown_length = data[0]
            data = data[1:]

            if shutdown_length == 0:
                message.data = "empty Shutdown Communication."
                # move offset past length field
                return self.encoder.notification(neighbor, direction, message, None, header, body)

            if len(data) < shutdown_length:
                message.data = "invalid Shutdown Communication (buffer underrun) length : %i [%s]" % (
                    shutdown_length,
                    hexstring(data),
                )
                return self.encoder.notification(neighbor, direction, message, None, header, body)

            if shutdown_length > 128:
                message.data = "invalid Shutdown Communication (too large) length : %i [%s]" % (
                    shutdown_length,
                    hexstring(data),
                )
                return self.encoder.notification(neighbor, direction, message, None, header, body)

            try:
                message.data = 'Shutdown Communication: "%s"' % data[:shutdown_length].decode('utf-8').replace(
                    '\r', ' '
                ).replace('\n', ' ')
            except UnicodeDecodeError:
                message.data = "invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % (
                    shutdown_length,
                    hexstring(data),
                )
                return self.encoder.notification(neighbor, direction, message, None, header, body)

            trailer = data[shutdown_length:]
            if trailer:
                message.data += ", trailing data: " + hexstring(trailer)

            return self.encoder.notification(neighbor, direction, message, None, header, body)

        if not self.negotiated:
            print('invalid message sequence, open not exchange not complete', json_string, file=sys.stderr)
            sys.exit(1)

        message = Message.unpack(category, data, direction, self.negotiated)

        if content == 'update':
            return self.encoder.update(neighbor, direction, message, None, header, body)

        if content == 'eor':  # XXX: Should not be required
            return self.encoder.update(neighbor, direction, message, None, header, body)

        if content == 'refresh':
            return self.json.refresh(neighbor, direction, message, None, header, body)

        if content == 'operational':
            return self.json.refresh(neighbor, direction, message, None, header, body)

        raise RuntimeError('the programer is a monkey and forgot a JSON message type')
Esempio n. 6
0
def check_update(neighbor, raw):
    option.enabled['parser'] = True

    neighbor = neighbor[list(neighbor)[0]]

    path = {}
    for f in NLRI.known_families():
        if neighbor['capability']['add-path']:
            path[f] = neighbor['capability']['add-path']

    capa = Capabilities().new(neighbor, False)
    capa[Capability.CODE.ADD_PATH] = path
    capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families()
    # capa[Capability.CODE.FOUR_BYTES_ASN] = True

    routerid_1 = str(neighbor['router-id'])
    routerid_2 = '.'.join(
        str((int(_) + 1) % 250)
        for _ in str(neighbor['router-id']).split('.', -1))

    o1 = Open(Version(4), ASN(neighbor['local-as']), HoldTime(180),
              RouterID(routerid_1), capa)
    o2 = Open(Version(4), ASN(neighbor['peer-as']), HoldTime(180),
              RouterID(routerid_2), capa)
    negotiated = Negotiated(neighbor)
    negotiated.sent(o1)
    negotiated.received(o2)
    # grouped = False

    while raw:
        if raw.startswith(b'\xff' * 16):
            kind = raw[18]
            size = (raw[16] << 16) + raw[17]

            injected, raw = raw[19:size], raw[size:]

            if kind == 2:
                log.debug('the message is an update', 'parser')
                decoding = 'update'
            else:
                log.debug(
                    'the message is not an update (%d) - aborting' % kind,
                    'parser')
                return False
        else:
            log.debug('header missing, assuming this message is ONE update',
                      'parser')
            decoding = 'update'
            injected, raw = raw, ''

        try:
            # This does not take the BGP header - let's assume we will not break that :)
            update = Update.unpack_message(injected, negotiated)
        except Notify:
            import traceback

            log.error('could not parse the message', 'parser')
            log.error(traceback.format_exc(), 'parser')
            return False
        except Exception:
            import traceback

            log.error('could not parse the message', 'parser')
            log.error(traceback.format_exc(), 'parser')
            return False

        log.debug('', 'parser')  # new line
        for number in range(len(update.nlris)):
            change = Change(update.nlris[number], update.attributes)
            log.info(
                'decoded %s %s %s' %
                (decoding, change.nlri.action, change.extensive()), 'parser')
        log.info(
            'update json %s' % Response.JSON(json_version).update(
                neighbor, 'in', update, None, '', ''), 'parser')

    return True
Esempio n. 7
0
class Transcoder(object):
    seen_open = {
        'send': None,
        'receive': None,
    }
    negotiated = None

    json = Response.JSON(json_version)

    def __init__(self, src='json', dst='json'):
        if src != 'json':
            raise RuntimeError('left as an exercise to the reader')

        if dst != 'json':
            raise RuntimeError('left as an exercise to the reader')

        self.convert = self._from_json
        self.encoder = self.json

    def _state(self):
        self.seen_open['send'] = None
        self.seen_open['receive'] = None
        self.negotiated = None

    def _open(self, direction, message):
        self.seen_open[direction] = message

        if all(self.seen_open.values()):
            self.negotiated = Negotiated(None)
            self.negotiated.sent(self.seen_open['send'])
            self.negotiated.received(self.seen_open['receive'])

    def _from_json(self, string):
        try:
            parsed = json.loads(string)
        except ValueError:
            print >> sys.stderr, 'invalid JSON message'
            sys.exit(1)

        if parsed.get('exabgp', '0.0.0') != json_version:
            print >> sys.stderr, 'invalid json version', string
            sys.exit(1)

        content = parsed.get('type', '')

        if not content:
            print >> sys.stderr, 'invalid json content', string
            sys.exit(1)

        neighbor = _FakeNeighbor(
            parsed['neighbor']['address']['local'],
            parsed['neighbor']['address']['peer'],
            parsed['neighbor']['asn']['local'],
            parsed['neighbor']['asn']['peer'],
        )

        if content == 'state':
            self._state()
            return string

        direction = parsed['neighbor']['direction']
        category = parsed['neighbor']['message']['category']
        header = parsed['neighbor']['message']['header']
        body = parsed['neighbor']['message']['body']
        raw = ''.join(
            chr(int(body[_:_ + 2], 16)) for _ in range(0, len(body), 2))

        if content == 'open':
            message = Open.unpack_message(raw)
            self._open(direction, message)
            return self.encoder.open(neighbor, direction, message, header,
                                     body)

        if content == 'keapalive':
            return self.encoder.keepalive(neighbor, direction, header, body)

        if content == 'notification':
            message = Notification.unpack_message(raw)
            return self.encoder.notification(neighbor, direction, message,
                                             header, body)

        if not self.negotiated:
            print >> sys.stderr, 'invalid message sequence, open not exchange not complete', string
            sys.exit(1)

        message = Message.unpack(category, raw, self.negotiated)

        if content == 'update':
            return self.encoder.update(neighbor, direction, message, header,
                                       body)

        if content == 'eor':  # XXX: Should not be required
            return self.encoder.update(neighbor, direction, message, header,
                                       body)

        if content == 'refresh':
            return self.json.refresh(neighbor, direction, message, header,
                                     body)

        if content == 'operational':
            return self.json.refresh(neighbor, direction, message, header,
                                     body)

        raise RuntimeError(
            'the programer is a monkey and forgot a JSON message type')
Esempio n. 8
0
        except Notify, exc:
            logger.parser('could not parse the message')
            logger.parser(str(exc))
            return False
        except Exception, exc:
            logger.parser('could not parse the message')
            logger.parser(str(exc))
            return False

        logger.parser('')  # new line
        for number in range(len(update.nlris)):
            change = Change(update.nlris[number], update.attributes)
            logger.parser('decoded %s %s %s' %
                          (decoding, change.nlri.action, change.extensive()))
        logger.parser(
            'update json %s' %
            Response.JSON(json_version).update(neighbor, 'in', update, '', ''))

    return True


# ================================================================= check_update
#


def check_notification(raw):
    notification = Notification.unpack_message(raw[18:], None)
    # XXX: FIXME: should be using logger here
    print notification
    return True
Esempio n. 9
0
def check_update(neighbor, raw):
    logger = Logger()
    logger._option.parser = True
    logger.parser('\ndecoding routes in configuration')

    neighbor = neighbor[neighbor.keys()[0]]

    path = {}
    for f in NLRI.known_families():
        if neighbor.add_path:
            path[f] = neighbor.add_path

    capa = Capabilities().new(neighbor, False)
    capa[Capability.CODE.ADD_PATH] = path
    capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families()
    # capa[Capability.CODE.FOUR_BYTES_ASN] = True

    routerid_1 = str(neighbor.router_id)
    routerid_2 = '.'.join(
        str((int(_) + 1) % 250)
        for _ in str(neighbor.router_id).split('.', -1))

    o1 = Open(Version(4), ASN(neighbor.local_as), HoldTime(180),
              RouterID(routerid_1), capa)
    o2 = Open(Version(4), ASN(neighbor.peer_as), HoldTime(180),
              RouterID(routerid_2), capa)
    negotiated = Negotiated(neighbor)
    negotiated.sent(o1)
    negotiated.received(o2)
    # grouped = False

    while raw:
        if raw.startswith('\xff' * 16):
            kind = ord(raw[18])
            size = (ord(raw[16]) << 16) + (ord(raw[17]))

            injected, raw = raw[19:size], raw[size:]

            if kind == 2:
                logger.parser('the message is an update')
                decoding = 'update'
            else:
                logger.parser('the message is not an update (%d) - aborting' %
                              kind)
                return False
        else:
            logger.parser(
                'header missing, assuming this message is ONE update')
            decoding = 'update'
            injected, raw = raw, ''

        try:
            # This does not take the BGP header - let's assume we will not break that :)
            update = Update.unpack_message(injected, negotiated)
        except KeyboardInterrupt:
            raise
        except Notify:
            logger.parser('could not parse the message', 'error')
            logger.parser(traceback.format_exc(), 'error')
            return False
        except StandardError:
            logger.parser('could not parse the message', 'error')
            logger.parser(traceback.format_exc(), 'error')
            return False

        logger.parser('')  # new line
        for number in range(len(update.nlris)):
            change = Change(update.nlris[number], update.attributes)
            logger.parser('decoded %s %s %s' %
                          (decoding, change.nlri.action, change.extensive()))
        logger.parser(
            'update json %s' %
            Response.JSON(json_version).update(neighbor, 'in', update, '', ''))

    return True
Esempio n. 10
0
    def _start(self, process):
        events = self.reactor.configuration.processes[process]
        for event, present in events.iteritems():
            if event in ('run', 'encoder'):
                continue
            if present:
                self._events.setdefault(process, []).append(event)

        try:
            if process in self._process:
                self.logger.processes("process already running")
                return
            if process not in self.reactor.configuration.processes:
                self.logger.processes(
                    "Can not start process, no configuration for it (anymore ?)"
                )
                return

            # Prevent some weird termcap data to be created at the start of the PIPE
            # \x1b[?1034h (no-eol) (esc)
            os.environ['TERM'] = 'dumb'

            run = self.reactor.configuration.processes[process].get('run', '')
            if run:
                api = self.reactor.configuration.processes[process]['encoder']
                self._encoder[process] = Response.Text(
                    text_version) if api == 'text' else Response.JSON(
                        json_version, self.highres)

                self._process[process] = subprocess.Popen(
                    run,
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    preexec_fn=preexec_helper
                    # This flags exists for python 2.7.3 in the documentation but on on my MAC
                    # creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
                )
                fcntl.fcntl(self._process[process].stdout.fileno(),
                            fcntl.F_SETFL, os.O_NONBLOCK)

                self.logger.processes("Forked process %s" % process)

                around_now = int(time.time()) & self.respawn_timemask
                if process in self._respawning:
                    if around_now in self._respawning[process]:
                        self._respawning[process][around_now] += 1
                        # we are respawning too fast
                        if self._respawning[process][
                                around_now] > self.respawn_number:
                            self.logger.processes(
                                "Too many respawn for %s (%d) terminating program"
                                % (process, self.respawn_number), 'critical')
                            raise ProcessError()
                    else:
                        # reset long time since last respawn
                        self._respawning[process] = {around_now: 1}
                else:
                    # record respawing
                    self._respawning[process] = {around_now: 1}

            neighbor = self.reactor.configuration.processes[process][
                'neighbor']
            self._neighbor_process.setdefault(neighbor, []).append(process)
        except (subprocess.CalledProcessError, OSError, ValueError), exc:
            self._broken.append(process)
            self.logger.processes("Could not start process %s" % process)
            self.logger.processes("reason: %s" % str(exc))