Module: OpenASN::BinaryFormat
- Defined in:
- lib/openasn/binary_format.rb
Overview
Reader for the OASN v1 artifact format and the OORG v1 org-names sidecar. The byte-exact spec lives in the data repo: https://github.com/openasn/openasn/blob/main/FORMAT.md — this file is an independent implementation of that document and must never drift from it. All integers big-endian. Readers REJECT unknown format versions on purpose: half-understanding an artifact is worse than keeping last-good data.
Defined Under Namespace
Modules: BaseLayer, OverlayLayer Classes: ArraysBase, ArraysOverlay, OrgIndex, PackedBase, PackedOverlay
Constant Summary collapse
- MAGIC =
"OASN"- ORG_MAGIC =
"OORG"- FORMAT_VERSION =
0x01- HEADER_SIZE =
32- ORG_HEADER_SIZE =
16- FLAG_BAD_ASN =
flags (u16) bit layout — see FORMAT.md
1 << 8
- FLAG_VPN_PROVIDER =
1 << 9
- FLAG_MOBILE =
1 << 10
- FLAG_ENTERPRISE_GW =
1 << 11
- FLAG_CDN =
1 << 12
- FLAG_HOSTING_EXTRA =
1 << 13
- CATEGORY_MASK =
0x000F- ROLE_SHIFT =
4- ROLE_MASK =
0x00F0- CATEGORIES =
[nil, "isp", "hosting", "business", "education_research", "government_admin"].freeze
- ROLES =
[nil, "tier1_transit", "major_transit", "midsize_transit", "access_provider", "content_network", "stub"].freeze
- FLAG_NAMES =
{ FLAG_BAD_ASN => :bad_asn, FLAG_VPN_PROVIDER => :vpn_provider, FLAG_MOBILE => :mobile_carrier, FLAG_ENTERPRISE_GW => :enterprise_gw, FLAG_CDN => :cdn, FLAG_HOSTING_EXTRA => :hosting_extra }.freeze
Class Method Summary collapse
- .addr_size(family) ⇒ Object
- .base_rec_size(family) ⇒ Object
- .category_name(flags) ⇒ Object
- .flag_names(flags) ⇒ Object
- .overlay_rec_size(family) ⇒ Object
- .pack_addr(int, family) ⇒ Object
-
.parse_artifact(bytes, mode: :packed) ⇒ Object
Parse a full OASN artifact into its layers.
- .role_name(flags) ⇒ Object
Class Method Details
.addr_size(family) ⇒ Object
52 |
# File 'lib/openasn/binary_format.rb', line 52 def addr_size(family) = family == :ipv4 ? 4 : 16 |
.base_rec_size(family) ⇒ Object
53 |
# File 'lib/openasn/binary_format.rb', line 53 def base_rec_size(family) = family == :ipv4 ? 14 : 38 |
.category_name(flags) ⇒ Object
45 |
# File 'lib/openasn/binary_format.rb', line 45 def category_name(flags) = CATEGORIES[flags & CATEGORY_MASK] |
.flag_names(flags) ⇒ Object
48 49 50 |
# File 'lib/openasn/binary_format.rb', line 48 def flag_names(flags) FLAG_NAMES.filter_map { |bit, name| name if flags.anybits?(bit) } end |
.overlay_rec_size(family) ⇒ Object
54 |
# File 'lib/openasn/binary_format.rb', line 54 def (family) = family == :ipv4 ? 8 : 32 |
.pack_addr(int, family) ⇒ Object
56 57 58 59 60 61 62 |
# File 'lib/openasn/binary_format.rb', line 56 def pack_addr(int, family) if family == :ipv4 [int].pack("N") else [int >> 64, int & 0xFFFF_FFFF_FFFF_FFFF].pack("Q>Q>") end end |
.parse_artifact(bytes, mode: :packed) ⇒ Object
Parse a full OASN artifact into its layers. -> { family:, build_ts:, base: BaseLayer, vpn: OverlayLayer, dc: OverlayLayer, relay: OverlayLayer }
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/openasn/binary_format.rb', line 66 def parse_artifact(bytes, mode: :packed) raise FormatError, "not an OASN artifact (bad magic)" unless bytes[0, 4] == MAGIC version = bytes.getbyte(4) raise FormatError, "unsupported OASN format_version #{version} (this gem speaks v#{FORMAT_VERSION}); update the openasn gem" unless version == FORMAT_VERSION family = bytes.getbyte(5) == 0x04 ? :ipv4 : :ipv6 build_ts = bytes[8, 8].unpack1("Q>") base_n, vpn_n, dc_n, relay_n = bytes[16, 16].unpack("NNNN") brec = base_rec_size(family) orec = (family) expected = HEADER_SIZE + base_n * brec + (vpn_n + dc_n + relay_n) * orec raise FormatError, "artifact truncated or padded: #{bytes.bytesize} bytes, header implies #{expected}" unless bytes.bytesize == expected offset = HEADER_SIZE base = bytes[offset, base_n * brec]; offset += base_n * brec vpn = bytes[offset, vpn_n * orec]; offset += vpn_n * orec dc = bytes[offset, dc_n * orec]; offset += dc_n * orec relay = bytes[offset, relay_n * orec] { family: family, build_ts: build_ts, base: BaseLayer.build(base, family, mode), vpn: OverlayLayer.build(vpn, family, mode), dc: OverlayLayer.build(dc, family, mode), relay: OverlayLayer.build(relay, family, mode) } end |
.role_name(flags) ⇒ Object
46 |
# File 'lib/openasn/binary_format.rb', line 46 def role_name(flags) = ROLES[(flags & ROLE_MASK) >> ROLE_SHIFT] |