CrackedRuby CrackedRuby

Overview

MAC addresses (Media Access Control addresses) serve as unique identifiers for network interface controllers at the data link layer (Layer 2) of the OSI model. Each network interface card possesses a MAC address burned into its hardware during manufacturing, creating a globally unique identifier for device communication on local networks.

Software developers encounter MAC addresses in network programming, device management, security implementations, and system administration tasks. Applications that monitor network traffic, manage DHCP leases, implement MAC filtering, or track devices across networks require MAC address parsing, validation, and manipulation capabilities.

MAC addresses consist of 48 bits (6 bytes) typically represented as six groups of two hexadecimal digits. The IEEE assigns the first three bytes as the Organizationally Unique Identifier (OUI) to hardware manufacturers, while manufacturers assign the last three bytes to create unique addresses within their allocation.

00:1A:2B:3C:4D:5E
└──┬──┘ └───┬───┘
  OUI    Device ID

Network protocols like Ethernet, Wi-Fi, and Bluetooth rely on MAC addresses for frame delivery between devices on the same network segment. Unlike IP addresses that route packets across networks, MAC addresses facilitate direct communication between devices sharing a broadcast domain.

Key Principles

MAC addresses follow the IEEE 802 standard specification, defining both the structure and assignment methodology. The 48-bit address space provides approximately 281 trillion unique addresses, though certain addresses serve reserved purposes and cannot appear on network interfaces.

The address structure divides into two components. The first 24 bits form the Organizationally Unique Identifier, assigned by the IEEE Registration Authority to manufacturers and vendors. The remaining 24 bits represent the Network Interface Controller specific identifier, managed by the OUI holder to guarantee uniqueness within their allocation.

Individual bits within the MAC address carry specific meanings. The least significant bit of the first byte indicates whether the address is unicast (0) or multicast (1). The second least significant bit of the first byte distinguishes between universally administered addresses (0) assigned by manufacturers and locally administered addresses (1) configured by network administrators.

01:23:45:67:89:AB
└─ First byte: 0x01 = 00000001 binary
                        │    │
                        │    └─ Unicast/Multicast bit
                        └────── Universal/Local bit

Universally administered addresses guarantee global uniqueness through IEEE coordination. Manufacturers obtain OUI blocks and assign unique addresses within their range. Locally administered addresses allow network administrators to override manufacturer assignments, useful for virtualization, testing, or specific network configurations.

Broadcast addresses represent a special case where all 48 bits are set to one (FF:FF:FF:FF:FF:FF), directing frames to all devices on the network segment. Multicast addresses begin with specific bit patterns that network hardware recognizes for efficient group communication.

Address representation varies across systems and applications. Colon-separated hexadecimal pairs (00:1A:2B:3C:4D:5E) dominate Unix-like systems. Hyphen-separated notation (00-1A-2B-3C-4D-5E) appears in Windows environments. Cisco equipment often uses dot-separated quadruplets (001A.2B3C.4D5E). Some systems omit delimiters entirely (001A2B3C4D5E).

Case sensitivity in hexadecimal representation does not affect address interpretation. The address 00:1a:2b:3c:4d:5e equals 00:1A:2B:3C:4D:5E functionally, though applications typically normalize to uppercase or lowercase for consistency.

Ruby Implementation

Ruby lacks native MAC address types but provides string manipulation, regular expressions, and binary operations for working with MAC addresses. Applications typically represent MAC addresses as strings, byte arrays, or integer values depending on the operation context.

Parsing MAC addresses from various formats requires flexible regular expressions that accommodate different delimiter styles and case variations:

def parse_mac_address(input)
  # Remove common delimiters and whitespace
  cleaned = input.to_s.strip.gsub(/[\s:.\-]/, '')
  
  # Validate hexadecimal and length
  return nil unless cleaned.match?(/^[0-9A-Fa-f]{12}$/)
  
  # Convert to standard colon-separated format
  cleaned.upcase.scan(/.{2}/).join(':')
end

parse_mac_address('00:1A:2B:3C:4D:5E')
# => "00:1A:2B:3C:4D:5E"

parse_mac_address('00-1a-2b-3c-4d-5e')
# => "00:1A:2B:3C:4D:5E"

parse_mac_address('001a.2b3c.4d5e')
# => "00:1A:2B:3C:4D:5E"

Validation extends beyond format checking to verify address characteristics and detect invalid configurations:

class MacAddress
  VALID_FORMAT = /^([0-9A-Fa-f]{2}[:\-.]?){5}[0-9A-Fa-f]{2}$/
  BROADCAST = 'FF:FF:FF:FF:FF:FF'
  
  attr_reader :address
  
  def initialize(address)
    @address = normalize(address)
    raise ArgumentError, 'Invalid MAC address format' unless valid?
  end
  
  def valid?
    return false if @address.nil?
    return false if broadcast?
    return false if null?
    true
  end
  
  def broadcast?
    @address == BROADCAST
  end
  
  def null?
    @address == '00:00:00:00:00:00'
  end
  
  def multicast?
    # Check least significant bit of first byte
    first_byte = @address[0..1].to_i(16)
    (first_byte & 1) == 1
  end
  
  def locally_administered?
    # Check second least significant bit of first byte
    first_byte = @address[0..1].to_i(16)
    (first_byte & 2) == 2
  end
  
  def oui
    @address[0..7]
  end
  
  private
  
  def normalize(input)
    cleaned = input.to_s.strip.gsub(/[\s:.\-]/, '')
    return nil unless cleaned.match?(/^[0-9A-Fa-f]{12}$/)
    cleaned.upcase.scan(/.{2}/).join(':')
  end
end

mac = MacAddress.new('00:1A:2B:3C:4D:5E')
mac.multicast?
# => false

mac.locally_administered?
# => false

mac.oui
# => "00:1A:2B"

Generating MAC addresses for testing or virtualization requires careful attention to bit flags. Test environments often use locally administered addresses to avoid conflicts with physical hardware:

def generate_local_mac
  # Set locally administered bit (bit 1 of first byte)
  # Clear multicast bit (bit 0 of first byte)
  bytes = 6.times.map { rand(256) }
  bytes[0] = (bytes[0] & 0xFE) | 0x02
  
  bytes.map { |b| format('%02X', b) }.join(':')
end

5.times { puts generate_local_mac }
# => 02:A3:4F:1B:8C:D2
# => 06:7E:2A:9F:4B:1C
# => 0A:5D:8B:3E:F7:29
# => 0E:91:6C:2D:A8:4F
# => 02:4C:7A:E3:5B:96

Converting between representations supports integration with different systems and protocols:

class MacAddress
  def to_cisco_format
    @address.gsub(':', '').scan(/.{4}/).join('.')
  end
  
  def to_windows_format
    @address.tr(':', '-')
  end
  
  def to_compact
    @address.gsub(':', '')
  end
  
  def to_integer
    @address.gsub(':', '').to_i(16)
  end
  
  def self.from_integer(value)
    raise ArgumentError, 'Value too large' if value > 0xFFFFFFFFFFFF
    hex_string = format('%012X', value)
    new(hex_string.scan(/.{2}/).join(':'))
  end
end

mac = MacAddress.new('00:1A:2B:3C:4D:5E')
mac.to_cisco_format
# => "001A.2B3C.4D5E"

mac.to_integer
# => 7124049582

MacAddress.from_integer(7124049582).address
# => "00:1A:2B:3C:4D:5E"

Reading MAC addresses from system interfaces requires platform-specific approaches. Unix-like systems provide interface information through network commands:

require 'open3'

def get_interface_mac(interface = 'eth0')
  case RbConfig::CONFIG['host_os']
  when /linux/
    output, = Open3.capture2('cat', "/sys/class/net/#{interface}/address")
    output.strip.upcase
  when /darwin/
    output, = Open3.capture2('ifconfig', interface)
    output[/ether ([0-9a-f:]+)/i, 1]&.upcase
  else
    raise NotImplementedError, 'Platform not supported'
  end
rescue Errno::ENOENT
  nil
end

get_interface_mac('eth0')
# => "00:1A:2B:3C:4D:5E"

Practical Examples

Network device inventory systems track hardware by MAC address, requiring parsing from diverse data sources and format normalization:

class DeviceInventory
  def initialize
    @devices = {}
  end
  
  def add_device(mac, device_info)
    normalized_mac = MacAddress.new(mac).address
    @devices[normalized_mac] = device_info
  end
  
  def find_device(mac)
    normalized_mac = MacAddress.new(mac).address
    @devices[normalized_mac]
  end
  
  def import_from_arp_table(arp_output)
    arp_output.each_line do |line|
      # Parse ARP table format: "192.168.1.100 at 00:1a:2b:3c:4d:5e on eth0"
      if line =~ /(\d+\.\d+\.\d+\.\d+)\s+at\s+([\da-f:]+)/i
        ip_address = $1
        mac_address = $2
        
        add_device(mac_address, { ip: ip_address, discovered_at: Time.now })
      end
    end
  end
end

inventory = DeviceInventory.new
inventory.add_device('00:1A:2B:3C:4D:5E', { hostname: 'server-01', location: 'rack-3' })

# Finding device works with any MAC format
inventory.find_device('00-1a-2b-3c-4d-5e')
# => { hostname: 'server-01', location: 'rack-3' }

DHCP server implementations associate IP addresses with MAC addresses, requiring address validation and lease management:

class DhcpLeaseManager
  def initialize
    @leases = {}
  end
  
  def assign_lease(mac, ip_address, duration: 86400)
    mac_obj = MacAddress.new(mac)
    
    # Reject multicast and broadcast addresses
    if mac_obj.multicast? || mac_obj.broadcast?
      raise ArgumentError, 'Cannot assign lease to multicast or broadcast MAC'
    end
    
    @leases[mac_obj.address] = {
      ip: ip_address,
      assigned_at: Time.now,
      expires_at: Time.now + duration,
      renewals: 0
    }
  end
  
  def renew_lease(mac)
    mac_obj = MacAddress.new(mac)
    lease = @leases[mac_obj.address]
    
    return nil unless lease
    return nil if lease[:expires_at] < Time.now
    
    lease[:expires_at] = Time.now + 86400
    lease[:renewals] += 1
    lease
  end
  
  def active_leases
    now = Time.now
    @leases.select { |_, lease| lease[:expires_at] > now }
  end
end

manager = DhcpLeaseManager.new
manager.assign_lease('00:1A:2B:3C:4D:5E', '192.168.1.100')
manager.renew_lease('00:1A:2B:3C:4D:5E')
# => { ip: '192.168.1.100', assigned_at: ..., expires_at: ..., renewals: 1 }

Network security applications implement MAC address filtering and monitoring for access control:

class MacAddressFilter
  def initialize
    @whitelist = Set.new
    @blacklist = Set.new
  end
  
  def add_to_whitelist(mac_addresses)
    mac_addresses.each do |mac|
      normalized = MacAddress.new(mac).address
      @whitelist.add(normalized)
      @blacklist.delete(normalized)
    end
  end
  
  def add_to_blacklist(mac_addresses)
    mac_addresses.each do |mac|
      normalized = MacAddress.new(mac).address
      @blacklist.add(normalized)
      @whitelist.delete(normalized)
    end
  end
  
  def allowed?(mac)
    normalized = MacAddress.new(mac).address
    
    # Whitelist takes precedence
    return true if @whitelist.include?(normalized)
    return false if @blacklist.include?(normalized)
    
    # Default policy when neither list matches
    @whitelist.empty? # Allow all if no whitelist configured
  end
  
  def vendor_allowed?(mac, allowed_vendors)
    mac_obj = MacAddress.new(mac)
    allowed_vendors.include?(mac_obj.oui)
  end
end

filter = MacAddressFilter.new
filter.add_to_whitelist(['00:1A:2B:3C:4D:5E', '00:1A:2B:11:22:33'])
filter.allowed?('00:1A:2B:3C:4D:5E')
# => true

filter.allowed?('AA:BB:CC:DD:EE:FF')
# => false

Log file analysis requires extracting MAC addresses from unstructured text and aggregating statistics:

class MacAddressLogParser
  def initialize
    @mac_pattern = /\b([0-9A-Fa-f]{2}[:\-.]){5}[0-9A-Fa-f]{2}\b/
  end
  
  def extract_macs(log_content)
    addresses = Set.new
    
    log_content.scan(@mac_pattern) do
      match = Regexp.last_match(0)
      begin
        normalized = MacAddress.new(match).address
        addresses.add(normalized)
      rescue ArgumentError
        # Skip invalid addresses
      end
    end
    
    addresses.to_a
  end
  
  def analyze_log_file(file_path)
    macs = Hash.new(0)
    
    File.foreach(file_path) do |line|
      extract_macs(line).each do |mac|
        macs[mac] += 1
      end
    end
    
    macs.sort_by { |_, count| -count }
  end
end

parser = MacAddressLogParser.new
log_text = <<~LOG
  2025-01-15 10:23:45 Device 00:1A:2B:3C:4D:5E connected
  2025-01-15 10:24:12 Traffic from 00-1a-2b-3c-4d-5e to gateway
  2025-01-15 10:25:33 Device AA:BB:CC:DD:EE:FF connected
LOG

parser.extract_macs(log_text)
# => ["00:1A:2B:3C:4D:5E", "AA:BB:CC:DD:EE:FF"]

Common Patterns

Address normalization establishes a canonical representation for consistent storage and comparison operations:

module MacAddressNormalizer
  def self.normalize(address, format: :colon, case_style: :upper)
    # Strip all delimiters and whitespace
    cleaned = address.to_s.gsub(/[\s:.\-]/, '')
    
    # Validate length and characters
    raise ArgumentError, 'Invalid MAC address' unless cleaned.match?(/^[0-9A-Fa-f]{12}$/)
    
    # Apply case transformation
    cleaned = case_style == :upper ? cleaned.upcase : cleaned.downcase
    
    # Apply format
    case format
    when :colon
      cleaned.scan(/.{2}/).join(':')
    when :hyphen
      cleaned.scan(/.{2}/).join('-')
    when :cisco
      cleaned.scan(/.{4}/).join('.')
    when :compact
      cleaned
    else
      raise ArgumentError, "Unknown format: #{format}"
    end
  end
end

MacAddressNormalizer.normalize('00-1a-2b-3c-4d-5e', format: :colon, case_style: :upper)
# => "00:1A:2B:3C:4D:5E"

MacAddressNormalizer.normalize('00:1A:2B:3C:4D:5E', format: :cisco, case_style: :lower)
# => "001a.2b3c.4d5e"

Address range generation supports testing and allocation management:

class MacAddressRange
  def initialize(base_address, count)
    @base = MacAddress.new(base_address).to_integer
    @count = count
  end
  
  def each
    return enum_for(__method__) unless block_given?
    
    @count.times do |offset|
      address_int = @base + offset
      raise RangeError, 'MAC address overflow' if address_int > 0xFFFFFFFFFFFF
      
      yield MacAddress.from_integer(address_int).address
    end
  end
  
  def to_a
    each.to_a
  end
end

range = MacAddressRange.new('00:1A:2B:3C:4D:5E', 5)
range.to_a
# => [
#   "00:1A:2B:3C:4D:5E",
#   "00:1A:2B:3C:4D:5F",
#   "00:1A:2B:3C:4D:60",
#   "00:1A:2B:3C:4D:61",
#   "00:1A:2B:3C:4D:62"
# ]

Vendor identification uses OUI lookups to determine hardware manufacturers:

class OuiDatabase
  def initialize
    @oui_map = {}
    load_database
  end
  
  def lookup(mac_address)
    mac_obj = MacAddress.new(mac_address)
    oui = mac_obj.oui.gsub(':', '')
    @oui_map[oui]
  end
  
  def load_database
    # Load from IEEE OUI database file
    # Format: OUI/Organization/Address
    File.foreach('oui.txt') do |line|
      if line =~ /^([0-9A-F]{6})\s+\(hex\)\s+(.+)$/
        oui = $1
        vendor = $2.strip
        @oui_map[oui] = vendor
      end
    end
  rescue Errno::ENOENT
    # Database file not found
  end
end

# Example usage with mock data
db = OuiDatabase.new
db.instance_variable_get(:@oui_map)['001A2B'] = 'Example Corporation'
db.lookup('00:1A:2B:3C:4D:5E')
# => "Example Corporation"

Address anonymization protects privacy while maintaining analytical value:

module MacAddressAnonymizer
  def self.anonymize(address, preserve_oui: true)
    mac_obj = MacAddress.new(address)
    
    if preserve_oui
      # Keep OUI, randomize device identifier
      oui = mac_obj.oui
      device_bytes = 3.times.map { rand(256) }
      "#{oui}:#{device_bytes.map { |b| format('%02X', b) }.join(':')}"
    else
      # Generate completely random locally-administered address
      bytes = 6.times.map { rand(256) }
      bytes[0] = (bytes[0] & 0xFE) | 0x02
      bytes.map { |b| format('%02X', b) }.join(':')
    end
  end
  
  def self.anonymize_batch(addresses)
    # Consistent anonymization using hash mapping
    mapping = {}
    
    addresses.map do |addr|
      normalized = MacAddress.new(addr).address
      mapping[normalized] ||= anonymize(normalized)
      mapping[normalized]
    end
  end
end

MacAddressAnonymizer.anonymize('00:1A:2B:3C:4D:5E', preserve_oui: true)
# => "00:1A:2B:A7:F3:91" (random device ID)

MacAddressAnonymizer.anonymize('00:1A:2B:3C:4D:5E', preserve_oui: false)
# => "02:8C:E4:1B:9A:5F" (fully random)

Error Handling & Edge Cases

Invalid format detection requires comprehensive validation beyond simple pattern matching:

class MacAddressValidator
  ERRORS = {
    invalid_format: 'MAC address format is invalid',
    invalid_length: 'MAC address must be 12 hexadecimal digits',
    invalid_characters: 'MAC address contains invalid characters',
    broadcast_address: 'Broadcast address not allowed',
    null_address: 'Null address not allowed',
    multicast_address: 'Multicast address not allowed in this context'
  }
  
  def self.validate(address, allow_multicast: false, allow_null: false)
    errors = []
    
    # Remove delimiters
    cleaned = address.to_s.gsub(/[\s:.\-]/, '')
    
    # Check length
    if cleaned.length != 12
      errors << ERRORS[:invalid_length]
      return errors
    end
    
    # Check characters
    unless cleaned.match?(/^[0-9A-Fa-f]{12}$/)
      errors << ERRORS[:invalid_characters]
      return errors
    end
    
    # Convert to normalized format
    normalized = cleaned.upcase.scan(/.{2}/).join(':')
    
    # Check for broadcast
    if normalized == 'FF:FF:FF:FF:FF:FF'
      errors << ERRORS[:broadcast_address]
    end
    
    # Check for null
    if normalized == '00:00:00:00:00:00' && !allow_null
      errors << ERRORS[:null_address]
    end
    
    # Check for multicast
    first_byte = normalized[0..1].to_i(16)
    if (first_byte & 1) == 1 && !allow_multicast
      errors << ERRORS[:multicast_address]
    end
    
    errors
  end
end

MacAddressValidator.validate('00:1A:2B:3C:4D:5E')
# => []

MacAddressValidator.validate('00:1A:2B:3C:4D')
# => ["MAC address must be 12 hexadecimal digits"]

MacAddressValidator.validate('FF:FF:FF:FF:FF:FF')
# => ["Broadcast address not allowed"]

MacAddressValidator.validate('01:00:5E:00:00:01')
# => ["Multicast address not allowed in this context"]

Delimiter ambiguity requires heuristic detection for mixed-format inputs:

class MacAddressParser
  def self.detect_format(address)
    cleaned = address.to_s.strip
    
    case cleaned
    when /^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/
      :colon
    when /^([0-9A-Fa-f]{2}-){5}[0-9A-Fa-f]{2}$/
      :hyphen
    when /^[0-9A-Fa-f]{4}\.[0-9A-Fa-f]{4}\.[0-9A-Fa-f]{4}$/
      :cisco
    when /^[0-9A-Fa-f]{12}$/
      :compact
    else
      :unknown
    end
  end
  
  def self.parse_flexible(address)
    format = detect_format(address)
    
    case format
    when :colon, :hyphen, :cisco
      address.gsub(/[:\-.]/, '').upcase.scan(/.{2}/).join(':')
    when :compact
      address.upcase.scan(/.{2}/).join(':')
    else
      raise ArgumentError, "Unable to parse MAC address: #{address}"
    end
  end
end

MacAddressParser.parse_flexible('00:1A:2B:3C:4D:5E')
# => "00:1A:2B:3C:4D:5E"

MacAddressParser.parse_flexible('001A.2B3C.4D5E')
# => "00:1A:2B:3C:4D:5E"

MacAddressParser.parse_flexible('001a2b3c4d5e')
# => "00:1A:2B:3C:4D:5E"

Database storage decisions impact query performance and indexing strategies:

# Store as normalized string for human readability
class Device < ActiveRecord::Base
  before_validation :normalize_mac_address
  
  validates :mac_address, presence: true, uniqueness: true
  validates :mac_address, format: {
    with: /\A([0-9A-F]{2}:){5}[0-9A-F]{2}\z/,
    message: 'must be in format XX:XX:XX:XX:XX:XX'
  }
  
  private
  
  def normalize_mac_address
    return if mac_address.nil?
    self.mac_address = MacAddress.new(mac_address).address
  rescue ArgumentError => e
    errors.add(:mac_address, e.message)
  end
end

# Store as 64-bit integer for efficient indexing and range queries
class DeviceOptimized < ActiveRecord::Base
  def mac_address=(value)
    mac_obj = MacAddress.new(value)
    self.mac_address_int = mac_obj.to_integer
    @mac_address_formatted = mac_obj.address
  end
  
  def mac_address
    @mac_address_formatted ||= MacAddress.from_integer(mac_address_int).address
  end
end

Collision detection in address pools prevents duplicate assignments:

class MacAddressPool
  def initialize(oui_prefix)
    @oui = oui_prefix
    @assigned = Set.new
    @max_attempts = 1000
  end
  
  def allocate
    attempts = 0
    
    loop do
      candidate = generate_address
      
      if @assigned.add?(candidate)
        return candidate
      end
      
      attempts += 1
      raise 'Address pool exhausted' if attempts >= @max_attempts
    end
  end
  
  def release(address)
    normalized = MacAddress.new(address).address
    @assigned.delete(normalized)
  end
  
  private
  
  def generate_address
    device_bytes = 3.times.map { rand(256) }
    device_part = device_bytes.map { |b| format('%02X', b) }.join(':')
    "#{@oui}:#{device_part}"
  end
end

pool = MacAddressPool.new('00:1A:2B')
addr1 = pool.allocate
addr2 = pool.allocate
# => "00:1A:2B:7F:3E:A1"

pool.release(addr1)

Tools & Ecosystem

The ipaddr gem from Ruby's standard library handles IP addresses but lacks MAC address support. The macaddr gem provides MAC address handling:

require 'macaddr'

# System MAC address retrieval
Mac.address
# => "00:1A:2B:3C:4D:5E"

# All network interface addresses
Mac.addr
# => ["00:1A:2B:3C:4D:5E", "AA:BB:CC:DD:EE:FF"]

The net-ping gem enables network discovery using MAC addresses:

require 'net/ping'

# ICMP ping with ARP table inspection
pinger = Net::Ping::External.new('192.168.1.1')
if pinger.ping?
  # Extract MAC from ARP cache after ping
  arp_output = `arp -a 192.168.1.1`
  mac = arp_output[/([0-9a-f]{2}[:\-]){5}[0-9a-f]{2}/i]
end

The packetfu gem provides raw packet manipulation including Ethernet frames:

require 'packetfu'

# Create Ethernet frame with specific MAC addresses
packet = PacketFu::EthPacket.new
packet.eth_saddr = '00:1A:2B:3C:4D:5E'
packet.eth_daddr = 'AA:BB:CC:DD:EE:FF'
packet.eth_proto = 0x0800 # IPv4

# Inspect frame
packet.peek
# => Ethernet header with source and destination MACs

System utilities provide MAC address information outside Ruby:

# Linux - interface MAC address
cat /sys/class/net/eth0/address

# macOS/BSD - interface configuration
ifconfig en0 | grep ether

# Windows - network adapter configuration
getmac /v /fo csv

# Cross-platform - ARP table
arp -a

Network monitoring tools like tcpdump and Wireshark capture and filter packets by MAC address:

# Capture packets from specific MAC
tcpdump -i eth0 ether src 00:1a:2b:3c:4d:5e

# Capture packets to specific MAC
tcpdump -i eth0 ether dst aa:bb:cc:dd:ee:ff

Reference

MAC Address Format Specifications

Format Pattern Example Common Usage
Colon-separated XX:XX:XX:XX:XX:XX 00:1A:2B:3C:4D:5E Linux, Unix, BSD
Hyphen-separated XX-XX-XX-XX-XX-XX 00-1A-2B-3C-4D-5E Windows, Microsoft
Cisco format XXXX.XXXX.XXXX 001A.2B3C.4D5E Cisco devices
Compact XXXXXXXXXXXX 001A2B3C4D5E Storage, databases
IEEE canonical XX-XX-XX-XX-XX-XX 00-1A-2B-3C-4D-5E IEEE documentation

Address Type Classification

Type Bit Pattern First Byte Examples Description
Unicast Bit 0 = 0 00, 02, 04, 06 Single destination device
Multicast Bit 0 = 1 01, 03, 05, 07 Group of devices
Broadcast All bits 1 FF All devices on segment
Universal Bit 1 = 0 00, 01, 04, 05 Manufacturer assigned
Local Bit 1 = 1 02, 03, 06, 07 Locally administered

Special MAC Addresses

Address Purpose Usage Context
FF:FF:FF:FF:FF:FF Broadcast ARP requests, DHCP discovery
00:00:00:00:00:00 Null address Uninitialized interfaces
01:00:5E:XX:XX:XX IPv4 multicast IP multicast over Ethernet
33:33:XX:XX:XX:XX IPv6 multicast IPv6 multicast over Ethernet
01:80:C2:00:00:00 STP BPDU Spanning Tree Protocol
FF:FF:FF:FF:FF:FE Reserved Invalid, commonly used in tests

Ruby Regular Expressions

Pattern Matches Use Case
/^([0-9A-Fa-f]{2}[:-.]?){5}[0-9A-Fa-f]{2}$/ Any delimiter format Flexible parsing
/^([0-9A-F]{2}:){5}[0-9A-F]{2}$/ Uppercase colon-separated Strict validation
/^[0-9A-Fa-f]{12}$/ Compact format After delimiter removal
/\b([0-9A-Fa-f]{2}[:-.]){5}[0-9A-Fa-f]{2}\b/ Extract from text Log file parsing

Validation Rules

Rule Check Implementation
Length Exactly 12 hex digits cleaned.length == 12
Characters Only 0-9, A-F match?(/^[0-9A-Fa-f]{12}$/)
Not broadcast Not FF:FF:FF:FF:FF:FF normalized != 'FF:FF:FF:FF:FF:FF'
Not null Not 00:00:00:00:00:00 normalized != '00:00:00:00:00:00'
Unicast only Bit 0 of byte 0 is 0 (first_byte & 1) == 0
Universal only Bit 1 of byte 0 is 0 (first_byte & 2) == 0

Bit Operations

Operation Ruby Code Result
Extract first byte address[0..1].to_i(16) Integer 0-255
Check multicast bit (first_byte & 1) == 1 Boolean
Check local bit (first_byte & 2) == 2 Boolean
Set local bit byte OR 0x02 Locally administered
Clear multicast bit byte AND 0xFE Unicast
Convert to integer address.gsub(':', '').to_i(16) 48-bit integer

Common OUI Prefixes

OUI Manufacturer Notes
00:1A:2B Example Corp Reserved for documentation
00:00:5E IANA Reserved for protocols
00:0C:29 VMware Virtual machine interfaces
08:00:27 Oracle VirtualBox Virtual machine interfaces
52:54:00 QEMU/KVM Virtual machine interfaces
AC:DE:48 Private ranges Reserved for local use