Exemplo n.º 1
0
 def _write_as_topos(self):
     for topo_id, as_topo, base in _srv_iter(
             self.topo_dicts, self.out_dir, common=True):
         path = os.path.join(base, TOPO_FILE)
         contents_json = json.dumps(self.topo_dicts[topo_id],
                                    default=_json_default, indent=2)
         write_file(path, contents_json + '\n')
         # Test if topo file parses cleanly
         Topology.from_file(path)
Exemplo n.º 2
0
 def _write_as_topos(self):
     for topo_id, as_topo, base in _srv_iter(self.topo_dicts,
                                             self.out_dir,
                                             common=True):
         path = os.path.join(base, TOPO_FILE)
         contents = yaml.dump(self.topo_dicts[topo_id],
                              default_flow_style=False)
         write_file(path, contents)
         # Test if topo file parses cleanly
         Topology.from_file(path)
Exemplo n.º 3
0
 def __init__(self, server_id, conf_dir, public=None, bind=None):
     """
     :param str server_id: server identifier.
     :param str conf_dir: configuration directory.
     :param list public:
         (host_addr, port) of the element's public address
         (i.e. the address visible to other network elements).
     :param list bind:
         (host_addr, port) of the element's bind address, if any
         (i.e. the address the element uses to identify itself to the local
         operating system, if it differs from the public address due to NAT).
     """
     self.id = server_id
     self.conf_dir = conf_dir
     self.ifid2br = {}
     self.topology = Topology.from_file(
         os.path.join(self.conf_dir, TOPO_FILE))
     self.config = Config.from_file(
         os.path.join(self.conf_dir, AS_CONF_FILE))
     # Must be over-ridden by child classes:
     self.CTRL_PLD_CLASS_MAP = {}
     self.SCMP_PLD_CLASS_MAP = {}
     self.public = public
     self.bind = bind
     if self.SERVICE_TYPE:
         own_config = self.topology.get_own_config(self.SERVICE_TYPE,
                                                   server_id)
         if public is None:
             self.public = own_config.public
         if bind is None:
             self.bind = own_config.bind
     self.init_ifid2br()
     self.trust_store = TrustStore(self.conf_dir)
     self.total_dropped = 0
     self._core_ases = defaultdict(
         list)  # Mapping ISD_ID->list of core ASes
     self.init_core_ases()
     self.run_flag = threading.Event()
     self.run_flag.set()
     self.stopped_flag = threading.Event()
     self.stopped_flag.clear()
     self._in_buf = queue.Queue(MAX_QUEUE)
     self._socks = SocketMgr()
     self._startup = time.time()
     if self.USE_TCP:
         self._DefaultMeta = TCPMetadata
     else:
         self._DefaultMeta = UDPMetadata
     self.unverified_segs = set()
     self.unv_segs_lock = threading.RLock()
     self.requested_trcs = {}
     self.req_trcs_lock = threading.Lock()
     self.requested_certs = {}
     self.req_certs_lock = threading.Lock()
     # TODO(jonghoonkwon): Fix me to setup sockets for multiple public addresses
     host_addr, self._port = self.public[0]
     self.addr = SCIONAddr.from_values(self.topology.isd_as, host_addr)
     self._setup_sockets(True)
Exemplo n.º 4
0
def _load_credentials(as_path, isd_as):
    print("Updating AS%s" % isd_as)
    # The element to get the credentials from.
    # We assume that the beacon server exists in every AS configuration.
    key_dict = {}
    core_key_dict = {}
    as_path = os.path.join(PROJECT_ROOT, GEN_PATH, 'ISD%s/AS%s' % (isd_as.isd_str(), isd_as.as_file_fmt()))
    instance_id = "bs%s-%s-1" % (isd_as.isd_str(), isd_as.as_file_fmt())
    instance_path = os.path.join(as_path, instance_id)
    topo_path = os.path.join(instance_path, TOPO_FILE)

    # Credential files for all ASes
    as_key_path = {
        'cert_path': get_cert_chain_file_path(instance_path, isd_as, INITIAL_CERT_VERSION),
        'trc_path': get_trc_file_path(instance_path, isd_as[0], INITIAL_TRC_VERSION),
        'enc_key_path': get_enc_key_file_path(instance_path),
        'sig_key_path': get_sig_key_file_path(instance_path),
        'sig_key_raw_path': get_sig_key_raw_file_path(instance_path),
        'as_config_path': os.path.join(instance_path, AS_CONF_FILE),
    }

    # Credential files for core ASes
    core_key_path = {
        'core_sig_key_path': get_core_sig_key_file_path(instance_path),
        'core_sig_key_raw_path': get_core_sig_key_raw_file_path(instance_path),
        'online_key_path': get_online_key_file_path(instance_path),
        'online_key_raw_path': get_online_key_raw_file_path(instance_path),
        'offline_key_path': get_offline_key_file_path(instance_path),
        'offline_key_raw_path': get_offline_key_raw_file_path(instance_path),
    }

    for key, path in as_key_path.items():
        try:
            if key.startswith('cert'):
                cert = _json_file_to_str(path)
            elif key.startswith('trc'):
                trc = _json_file_to_str(path)
            elif key.startswith('as'):
                as_config_dict = _yaml_file_to_dict(path)
                key_dict['master_as_key'] = as_config_dict['MasterASKey']
            else:
                key_name = key[:len(key)-5]
                key_dict[key_name] = read_file(path)[:-1]
        except IOError as err:
            print("IOError({0}): {1}" % (err, path))
            exit(1)
    tp = Topology.from_file(topo_path)
    if tp.is_core_as:
        for key, path in core_key_path.items():
            try:
                key_name = key[:len(key)-5]
                core_key_dict[key_name] = read_file(path)[:-1]
            except IOError as err:
                print("IOError({0}): {1}" % (err, path))
                exit(1)

    return ASCredential(cert, trc, key_dict, core_key_dict)
Exemplo n.º 5
0
def main_default(type_, local_type=None, trace_=False, **kwargs):
    """
    Default main() method. Parses cmdline args, setups up signal handling,
    logging, creates the appropriate object and runs it.

    :param type type_: Primary type to instantiate.
    :param type local_type:
        If not `None`, load the topology to check if this is a core or local AS.
        If it's a core AS, instantiate the primary type, otherwise the local
        type.
    :param bool trace_: Should a periodic thread stacktrace report be created?
    """
    handle_signals()
    parser = argparse.ArgumentParser()
    parser.add_argument('--log_dir',
                        default="logs/",
                        help='Log dir (Default: logs/)')
    parser.add_argument(
        '--spki_cache_dir',
        default="gen-cache/",
        help='Cache dir for SCION TRCs and cert chains (Default: gen-cache/)')
    parser.add_argument('--prom',
                        type=str,
                        help='Address to export prometheus metrics on')
    parser.add_argument('server_id', help='Server identifier')
    parser.add_argument('conf_dir',
                        nargs='?',
                        default='.',
                        help='Configuration directory (Default: ./)')
    args = parser.parse_args()
    init_logging(os.path.join(args.log_dir, args.server_id))

    if local_type is None:
        inst = type_(args.server_id,
                     args.conf_dir,
                     prom_export=args.prom,
                     spki_cache_dir=args.spki_cache_dir,
                     **kwargs)
    else:
        # Load the topology to check if this is a core AD or not
        topo = Topology.from_file(os.path.join(args.conf_dir, TOPO_FILE))
        if topo.is_core_as:
            inst = type_(args.server_id,
                         args.conf_dir,
                         prom_export=args.prom,
                         spki_cache_dir=args.spki_cache_dir,
                         **kwargs)
        else:
            inst = local_type(args.server_id,
                              args.conf_dir,
                              prom_export=args.prom,
                              spki_cache_dir=args.spki_cache_dir,
                              **kwargs)
    if trace_:
        trace(inst.id)
    logging.info("Started %s", args.server_id)
    inst.run()
Exemplo n.º 6
0
 def __init__(self,
              server_id: str,
              conf_dir: str,
              host_addr: HostAddrBase = None,
              port: int = None) -> None:
     """
     :param str server_id: server identifier.
     :param str conf_dir: configuration directory.
     :param `HostAddrBase` host_addr:
         the interface to bind to. Overrides the address in the topology
         config.
     :param int port:
         the port to bind to. Overrides the address in the topology config.
     """
     self.id = server_id
     self.conf_dir = conf_dir
     self.ifid2br = {}  # type: Dict[int, RouterElement]
     self._port = port
     self.topology = Topology.from_file(
         os.path.join(self.conf_dir, TOPO_FILE))
     self.config = Config.from_file(
         os.path.join(self.conf_dir, AS_CONF_FILE))
     # Must be over-ridden by child classes:
     # self.CTRL_PLD_CLASS_MAP = {}  # type: Dict[str, Dict[Optional[int], Callable[[object, object, object], None]]]
     # self.SCMP_PLD_CLASS_MAP = {}  # type: Dict[int, Dict[Optional[int], Callable[[object, object], None]]]
     if self._service_type():
         own_config = self.topology.get_own_config(self._service_type(),
                                                   server_id)
         if host_addr is None:
             host_addr = own_config.addr
         if self._port is None:
             self._port = own_config.port
     self.addr = SCIONAddr.from_values(self.topology.isd_as,
                                       host_addr)  # type: SCIONAddr
     self.init_ifid2br()
     self.trust_store = TrustStore(self.conf_dir)
     self.total_dropped = 0
     self._core_ases = defaultdict(
         list_object
     )  # type: defaultdict[int, List[object]] # Mapping ISD_ID->list of core ASes
     self.init_core_ases()
     self.run_flag = threading.Event()
     self.run_flag.set()
     self.stopped_flag = threading.Event()
     self.stopped_flag.clear()
     self._in_buf = queue.Queue(MAX_QUEUE)  # type: queue.Queue[object]
     self._socks = SocketMgr()
     self._setup_sockets(True)
     self._startup = time.time()
     if SCIONElement.USE_TCP:
         self.DefaultMeta = TCPMetadata  # type: Type[MetadataBase]
     else:
         self.DefaultMeta = UDPMetadata
Exemplo n.º 7
0
 def __init__(self, server_id, conf_dir, host_addr=None, port=None):
     """
     :param str server_id: server identifier.
     :param str conf_dir: configuration directory.
     :param `HostAddrBase` host_addr:
         the interface to bind to. Overrides the address in the topology
         config.
     :param int port:
         the port to bind to. Overrides the address in the topology config.
     """
     self.id = server_id
     self.conf_dir = conf_dir
     self.ifid2br = {}
     self._port = port
     self.topology = Topology.from_file(
         os.path.join(self.conf_dir, TOPO_FILE))
     self.config = Config.from_file(
         os.path.join(self.conf_dir, AS_CONF_FILE))
     # Must be over-ridden by child classes:
     self.CTRL_PLD_CLASS_MAP = {}
     self.SCMP_PLD_CLASS_MAP = {}
     if self.SERVICE_TYPE:
         own_config = self.topology.get_own_config(self.SERVICE_TYPE,
                                                   server_id)
         if host_addr is None:
             host_addr = own_config.addr
         if self._port is None:
             self._port = own_config.port
     self.addr = SCIONAddr.from_values(self.topology.isd_as, host_addr)
     self.init_ifid2br()
     self.trust_store = TrustStore(self.conf_dir)
     self.total_dropped = 0
     self._core_ases = defaultdict(list)  # Mapping ISD_ID->list of core ASes
     self.init_core_ases()
     self.run_flag = threading.Event()
     self.run_flag.set()
     self.stopped_flag = threading.Event()
     self.stopped_flag.clear()
     self._in_buf = queue.Queue(MAX_QUEUE)
     self._socks = SocketMgr()
     self._setup_sockets(True)
     self._startup = time.time()
     if self.USE_TCP:
         self.DefaultMeta = TCPMetadata
     else:
         self.DefaultMeta = UDPMetadata
     self.unverified_segs = set()
     self.unv_segs_lock = threading.RLock()
     self.requested_trcs = set()
     self.req_trcs_lock = threading.Lock()
     self.requested_certs = set()
     self.req_certs_lock = threading.Lock()
Exemplo n.º 8
0
 def __init__(self,
              server_id,
              conf_dir,
              host_addr=None,
              port=SCION_UDP_PORT):
     """
     :param str server_id: server identifier.
     :param str conf_dir: configuration directory.
     :param `HostAddrBase` host_addr:
         the interface to bind to. Overrides the address in the topology
         config.
     :param int port: the port to bind to.
     """
     self.id = server_id
     self.conf_dir = conf_dir
     self.ifid2er = {}
     self._port = port
     self.topology = Topology.from_file(
         os.path.join(self.conf_dir, TOPO_FILE))
     self.config = Config.from_file(
         os.path.join(self.conf_dir, AS_CONF_FILE))
     # Must be over-ridden by child classes:
     self.CTRL_PLD_CLASS_MAP = {}
     self.SCMP_PLD_CLASS_MAP = {}
     if host_addr is None:
         own_config = self.topology.get_own_config(self.SERVICE_TYPE,
                                                   server_id)
         host_addr = own_config.addr
     self.addr = SCIONAddr.from_values(self.topology.isd_as, host_addr)
     self._dns = DNSCachingClient(
         [str(s.addr) for s in self.topology.dns_servers],
         self.topology.dns_domain)
     self.init_ifid2er()
     self.trust_store = TrustStore(self.conf_dir)
     self.total_dropped = 0
     self._core_ases = defaultdict(
         list)  # Mapping ISD_ID->list of core ASes
     self.init_core_ases()
     self.run_flag = threading.Event()
     self.run_flag.set()
     self.stopped_flag = threading.Event()
     self.stopped_flag.clear()
     self._in_buf = queue.Queue(MAX_QUEUE)
     self._socks = SocketMgr()
     self._setup_socket(True)
     self._startup = time.time()
Exemplo n.º 9
0
    def test(self):
        """
        Create a certificate chain and verify it with a TRC file. Sign a message
        with the private key of the last certificate in the chain and verify it.
        """
        cert10 = CertificateChain(get_cert_chain_file_path(1, 10, 1, 10, 0))
        trc = TRC(get_trc_file_path(1, 10, 1, 0))
        print('TRC verification', trc.verify())
        print('Cert Chain verification:', cert10.verify('ISD:1-AD:10', trc, 0))

        sig_priv10 = read_file(get_sig_key_file_path(1, 10))
        sig_priv10 = base64.b64decode(sig_priv10)
        msg = b'abcd'
        sig = sign(msg, sig_priv10)
        print('Sig test:', verify_sig_chain_trc(msg, sig, 'ISD:1-AD:10', cert10,
                                                trc, 0))

        sig_priv13 = read_file(get_sig_key_file_path(1, 13))
        sig_priv13 = base64.b64decode(sig_priv13)
        msg = b'abd'
        sig = sign(msg, sig_priv13)
        CertificateChain.from_values([])
        print('Sig test 2:', verify_sig_chain_trc(msg, sig, 'ISD:1-AD:13',
                                                  cert10, trc, 0), '\n')

        topology = Topology.from_file(
            "topology/ISD1/topologies/ISD:1-AD:10.json")
        src_addr = SCIONAddr.from_values(topology.isd_id, topology.ad_id,
                                         IPv4Address("127.0.0.1"))
        dst_addr = topology.certificate_servers[0].addr
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind((str(src_addr.host_addr), SCION_UDP_PORT))

        print("Sending TRC request (ISD:1-V:0) to local CS.")
        msg = TRCRequest.from_values(
            PT.TRC_REQ_LOCAL, src_addr,
            topology.parent_border_routers[0].interface.if_id,
            topology.isd_id, topology.ad_id, 1, 0).pack()
        sock.sendto(msg, (str(dst_addr), SCION_UDP_PORT))

        temp_file = './temp.txt'
        timeout = 5

        ready = select.select([sock], [], [], timeout)
        if not ready[0]:
            print("Error: no TRC reply was received!")
            sock.close()
            return

        data, _ = sock.recvfrom(SCION_BUFLEN)
        print("Received TRC reply from local CS.")
        trc_reply = TRCReply(data)
        write_file(temp_file, trc_reply.trc.decode('utf-8'))
        trc = TRC(temp_file)
        assert trc.verify()

        print("Sending cert chain request (ISD:1-AD:16-V:0) to local CS.")
        msg = CertChainRequest.from_values(
            PT.CERT_CHAIN_REQ_LOCAL, src_addr,
            topology.parent_border_routers[0].interface.if_id,
            topology.isd_id, topology.ad_id, 1, 16, 0).pack()
        sock.sendto(msg, (str(dst_addr), SCION_UDP_PORT))

        ready = select.select([sock], [], [], timeout)
        if not ready[0]:
            print("Error: no cert chain reply was received!")
            sock.close()
            return

        data, _ = sock.recvfrom(SCION_BUFLEN)
        print("Received cert chain reply from local CS.")
        cert_chain_reply = CertChainReply(data)
        write_file(temp_file, cert_chain_reply.cert_chain.decode('utf-8'))
        cert_chain = CertificateChain(temp_file)
        assert cert_chain.verify('ISD:1-AD:16', trc, 0)

        os.remove(temp_file)
        sock.close()
Exemplo n.º 10
0
def index(request):
    '''
    Main index handler for index.html for main visualization page.
    Validates parameters, request scion data, returns formatted response.
    :param request: HTML request object containing url parameters.
    '''
    p = {}  # return param dictionary
    p['tab'] = set_param(request, 'tab', 'tab-pathtopo')
    p['data'] = set_param(request, 'data', 'sdapi')
    p['addr'] = set_param(request, 'addr', '')
    p['src'] = set_param(request, 'src', '')
    p['dst'] = set_param(request, 'dst', '')
    p['mp'] = set_param(request, 'mp', '5')
    p['err'] = ''
    if (p['src'] == '' and p['dst'] == ''):
        # use endhost gen/ia if no host specified
        if (p['src'] == ''):
            ia_file = "%s/%s/ia" % (SCION_ROOT, GEN_PATH)
            try:
                with open(ia_file, 'r') as fin:
                    # load and reformat
                    p['src'] = str(ISD_AS(fin.read().strip()))
            except (FileNotFoundError) as err:
                logging.warning("%s: %s" % (err.__class__.__name__, err))
        return fmt_err(request, p)
    s_isd_as = ISD_AS(p['src'])
    d_isd_as = ISD_AS(p['dst'])
    p['src'], p['dst'] = str(s_isd_as), str(d_isd_as)  # reformat
    csegs = dsegs = usegs = []
    paths = ''
    logging.info("Requesting sciond data from %s to %s" % (s_isd_as, d_isd_as))
    conf_dir = "%s/%s/ISD%s/AS%s/endhost" % (
        SCION_ROOT, GEN_PATH, s_isd_as.isd_str(), s_isd_as.as_file_fmt())
    sock_file = get_default_sciond_path(s_isd_as)
    if not pathlib.Path(sock_file).exists():
        sock_file = get_default_sciond_path(None)
    try:
        if (p['data'] == 'sdapi'):
            connector[s_isd_as] = lib_sciond.init(sock_file)
            logging.info(connector[s_isd_as]._api_addr)
            try:  # test if sciond is already running for this AS
                logging.info("Testing sciond at %s" % sock_file)
                lib_sciond.get_as_info(connector=connector[s_isd_as])
            except (SCIONDResponseError) as err:
                p['err'] = "%s: %s" % (err.__class__.__name__, err)
                return fmt_err(request, p)
            except (SCIONDConnectionError, FileNotFoundError) as err:
                logging.warning("%s: %s" % (err.__class__.__name__, err))
                # need to launch sciond, wait for uptime
                launch_sciond(sock_file, conf_dir, p['addr'], s_isd_as)

            if (p['dst'] != ''):  # PATHS
                try:
                    # get paths and keep segments
                    flags = lib_sciond.PathRequestFlags(flush=False,
                                                        sibra=False)
                    paths = lib_sciond.get_paths(d_isd_as,
                                                 max_paths=int(p['mp']),
                                                 flags=flags,
                                                 connector=connector[s_isd_as])
                    csegs = lib_sciond.get_segtype_hops(
                        PST.CORE, connector=connector[s_isd_as])
                    dsegs = lib_sciond.get_segtype_hops(
                        PST.DOWN, connector=connector[s_isd_as])
                    usegs = lib_sciond.get_segtype_hops(
                        PST.UP, connector=connector[s_isd_as])
                    # refresh old segments for next call
                    flags = lib_sciond.PathRequestFlags(flush=True,
                                                        sibra=False)
                    lib_sciond.get_paths(d_isd_as,
                                         max_paths=int(p['mp']),
                                         flags=flags,
                                         connector=connector[s_isd_as])
                except (SCIONDResponseError, SCIONDConnectionError,
                        AttributeError) as err:
                    # AttributeError handles backward-compatability
                    logging.error("%s: %s" % (err.__class__.__name__, err))
                    p['err'] = str(err)
            p['json_as_topo'] = json.dumps(
                get_json_as_topology_sciond(connector[s_isd_as], paths))
            p['json_trc'] = ("TRC information for sciond not yet implemented.")
            p['json_crt'] = (
                "Certificate information for sciond not yet implemented.")
        elif (p['data'] == 'file'):
            t = Topology.from_file(os.path.join(conf_dir, TOPO_FILE))
            topo = organize_topo(t)
            p['json_as_topo'] = json.dumps(get_json_as_topology(t, topo))
            p['json_trc'] = html_jsonfile(findCerts(conf_dir, ".trc"))
            p['json_crt'] = html_jsonfile(findCerts(conf_dir, ".crt"))
        p['path_info'] = get_as_view_html(paths, csegs, usegs, dsegs)
        p['json_path_topo'] = json.dumps(
            get_json_path_segs(paths, csegs, usegs, dsegs))
        p['json_seg_topo'] = json.dumps(
            get_json_all_segments(csegs, usegs, dsegs))
        p['json_paths'] = json.dumps(get_json_paths(paths))
    except (SCIONBaseError) as err:
        p['err'] = "%s: %s" % (err.__class__.__name__, err)
        return fmt_err(request, p)
    return render(request, 'asviz/index.html', p)
Exemplo n.º 11
0
 def __init__(self, server_id, conf_dir, public=None, bind=None, spki_cache_dir=GEN_CACHE_PATH,
              prom_export=None):
     """
     :param str server_id: server identifier.
     :param str conf_dir: configuration directory.
     :param list public:
         (host_addr, port) of the element's public address
         (i.e. the address visible to other network elements).
     :param list bind:
         (host_addr, port) of the element's bind address, if any
         (i.e. the address the element uses to identify itself to the local
         operating system, if it differs from the public address due to NAT).
     :param str spki_cache_dir:
         Path for caching TRCs and certificate chains.
     :param str prom_export:
         String of the form 'addr:port' specifying the prometheus endpoint.
         If no string is provided, no metrics are exported.
     """
     self.id = server_id
     self.conf_dir = conf_dir
     self.ifid2br = {}
     self.topology = Topology.from_file(
         os.path.join(self.conf_dir, TOPO_FILE))
     # Labels attached to every exported metric.
     self._labels = {"server_id": self.id, "isd_as": str(self.topology.isd_as)}
     # Must be over-ridden by child classes:
     self.CTRL_PLD_CLASS_MAP = {}
     self.SCMP_PLD_CLASS_MAP = {}
     self.public = public
     self.bind = bind
     if self.SERVICE_TYPE:
         own_config = self.topology.get_own_config(self.SERVICE_TYPE,
                                                   server_id)
         if public is None:
             self.public = own_config.public
         if bind is None:
             self.bind = own_config.bind
     self.init_ifid2br()
     self.trust_store = TrustStore(self.conf_dir, spki_cache_dir, self.id, self._labels)
     self.total_dropped = 0
     self._core_ases = defaultdict(list)  # Mapping ISD_ID->list of core ASes
     self.init_core_ases()
     self.run_flag = threading.Event()
     self.run_flag.set()
     self.stopped_flag = threading.Event()
     self.stopped_flag.clear()
     self._in_buf = queue.Queue(MAX_QUEUE)
     self._socks = SocketMgr()
     self._startup = time.time()
     if self.USE_TCP:
         self._DefaultMeta = TCPMetadata
     else:
         self._DefaultMeta = UDPMetadata
     self.unverified_segs = ExpiringDict(500, 60 * 60)
     self.unv_segs_lock = threading.RLock()
     self.requested_trcs = {}
     self.req_trcs_lock = threading.Lock()
     self.requested_certs = {}
     self.req_certs_lock = threading.Lock()
     # TODO(jonghoonkwon): Fix me to setup sockets for multiple public addresses
     host_addr, self._port = self.public[0]
     self.addr = SCIONAddr.from_values(self.topology.isd_as, host_addr)
     if prom_export:
         self._export_metrics(prom_export)
         self._init_metrics()
     self._setup_sockets(True)
     lib_sciond.init(os.path.join(SCIOND_API_SOCKDIR, "sd%s.sock" % self.addr.isd_as))