0%
حساب نطاق عناوين شبكة CIDR باستخدام Python

حساب نطاق عناوين شبكة CIDR باستخدام Python

تعلّم كيفية تحديد عدد عناوين IP والنطاق الكامل لشبكة CIDR باستخدام Python. شرح تفصيلي يعتمد على الوحدة ipaddress مع أمثلة عملية.

I

InSkillCoach

· دقيقة

حساب نطاق عناوين شبكة CIDR باستخدام Python

CIDR (Classless Inter-Domain Routing) هو أسلوب لتخصيص عناوين IP وتوجيه حزم IP، وقد حلّ محل النظام السابق القائم على فئات عناوين الشبكة. ويُعدّ فهم كيفية حساب نطاق عناوين IP لشبكة CIDR أمرًا أساسيًا في إدارة الشبكات وأمن المعلومات وإدارة الأنظمة.

في هذا الدليل، سنستكشف كيفية استخدام Python لتحديد نطاق عناوين IP لشبكة CIDR بسرعة وكفاءة.

ما هو ترميز CIDR؟

يتكوّن ترميز CIDR من جزأين:

  • عنوان IP (من النوع IPv4 أو IPv6)
  • لاحقة تحدّد حجم بادئة الشبكة (قناع الشبكة الفرعية)

على سبيل المثال، يشير 192.168.1.0/24 إلى ما يلي:

  • 192.168.1.0 هو عنوان الشبكة
  • /24 تعني أن أول 24 بتًا ثابتة (وهو ما يقابل قناع الشبكة الفرعية 255.255.255.0)
  • تضم هذه الشبكة جميع العناوين من 192.168.1.0 إلى 192.168.1.255

استخدام الوحدة ipaddress

تتضمن Python وحدة قوية تُسمى ipaddress ضمن مكتبتها القياسية (منذ Python 3.3)، تُسهّل كثيرًا العمليات الحسابية المتعلقة بعناوين IP والشبكات.

التثبيت

لا حاجة إلى أي تثبيت لأن الوحدة ipaddress جزء من المكتبة القياسية في Python:

import ipaddress

تحديد نطاق عناوين شبكة CIDR

إليك طريقة حساب نطاق عناوين شبكة CIDR:

import ipaddress

def get_cidr_range(cidr_notation):
    """
    حساب نطاق عناوين IP لشبكة CIDR.
    
    Args:
        cidr_notation (str): ترميز CIDR (مثال: '192.168.1.0/24')
        
    Returns:
        dict: قاموس يحتوي على معلومات الشبكة
    """
    try:
        network = ipaddress.ip_network(cidr_notation, strict=False)
        
        # جمع معلومات الشبكة
        network_info = {
            'network_address': str(network.network_address),
            'broadcast_address': str(network.broadcast_address) if hasattr(network, 'broadcast_address') else None,
            'netmask': str(network.netmask),
            'prefix_length': network.prefixlen,
            'num_addresses': network.num_addresses,
            'first_usable_address': str(next(network.hosts())) if network.num_addresses > 1 else None,
            'last_usable_address': str(list(network.hosts())[-1]) if network.num_addresses > 1 else None,
            'address_range': f"{next(network.hosts())} - {list(network.hosts())[-1]}" if network.num_addresses > 1 else None,
            'is_private': network.is_private,
            'version': 'IPv4' if network.version == 4 else 'IPv6'
        }
        
        return network_info
        
    except ValueError as e:
        return {'error': str(e)}

# أمثلة على الاستخدام
cidr_examples = [
    '192.168.1.0/24',  # شبكة محلية تقليدية (/24)
    '10.0.0.0/8',      # شبكة خاصة من الفئة A
    '172.16.0.0/12',   # شبكة خاصة من الفئة B
    '8.8.8.0/24',      # شبكة عامة (تحتوي على Google DNS)
    '192.168.0.1/32',  # عنوان IP واحد فقط
    '2001:db8::/32',   # شبكة IPv6
]

for cidr in cidr_examples:
    print(f"\nInformations pour le réseau {cidr}:")
    network_info = get_cidr_range(cidr)
    
    if 'error' in network_info:
        print(f"Erreur: {network_info['error']}")
        continue
    
    # عرض معلومات الشبكة
    for key, value in network_info.items():
        print(f"- {key}: {value}")

النتيجة لشبكة IPv4 (/24)

Informations pour le réseau 192.168.1.0/24:
- network_address: 192.168.1.0
- broadcast_address: 192.168.1.255
- netmask: 255.255.255.0
- prefix_length: 24
- num_addresses: 256
- first_usable_address: 192.168.1.1
- last_usable_address: 192.168.1.254
- address_range: 192.168.1.1 - 192.168.1.254
- is_private: True
- version: IPv4

فهم عدد عناوين IP في شبكة CIDR

يمكن حساب عدد عناوين IP في شبكة CIDR باستخدام الصيغة: 2^(32-البادئة) لشبكات IPv4 و2^(128-البادئة) لشبكات IPv6.

إليك دالة توضّح هذه العلاقة:

def explain_cidr_size(prefix_length, ip_version=4):
    """
    شرح حجم شبكة CIDR وحساب عدد عناوين IP.
    
    Args:
        prefix_length (int): طول بادئة CIDR (مثال: 24 في /24)
        ip_version (int): إصدار IP (4 أو 6)
        
    Returns:
        dict: الشرح والحسابات
    """
    if ip_version == 4:
        total_bits = 32
        max_prefix = 32
    else:  # IPv6
        total_bits = 128
        max_prefix = 128
    
    if prefix_length < 0 or prefix_length > max_prefix:
        return {'error': f'Préfixe invalide pour IPv{ip_version}'}
    
    host_bits = total_bits - prefix_length
    num_addresses = 2 ** host_bits
    
    if ip_version == 4:
        # في IPv4، تُحتسب عادةً العناوين القابلة للاستخدام
        # (باستثناء عنوان الشبكة وعنوان البث broadcast)
        usable_addresses = max(0, num_addresses - 2) if prefix_length < 31 else num_addresses
    else:
        # في IPv6، لا يُطرح عادةً أي عنوان
        usable_addresses = num_addresses
    
    explanation = {
        'prefix_length': prefix_length,
        'ip_version': f'IPv{ip_version}',
        'total_bits': total_bits,
        'network_bits': prefix_length,
        'host_bits': host_bits,
        'formula': f'2^{host_bits}',
        'total_addresses': num_addresses,
        'usable_addresses': usable_addresses
    }
    
    return explanation

# جدول مقارنة لبادئات CIDR المختلفة
print("Tableau comparatif des tailles de réseaux CIDR pour IPv4:")
print("-" * 80)
print(f"{'Préfixe':<10}{'Masque':<15}{'Bits hôte':<15}{'Nombre d\'adresses':<20}{'Adresses utilisables':<20}")
print("-" * 80)

for prefix in [8, 16, 20, 24, 27, 28, 29, 30, 31, 32]:
    info = explain_cidr_size(prefix)
    
    # حساب قناع الشبكة الفرعية
    if prefix == 32:
        mask = "255.255.255.255"
    else:
        mask_int = (0xffffffff >> (32 - prefix)) << (32 - prefix)
        mask = '.'.join([str((mask_int >> i) & 0xff) for i in [24, 16, 8, 0]])
    
    print(f"/{prefix:<9}{mask:<15}{info['host_bits']:<15}{info['total_addresses']:<20}{info['usable_addresses']:<20}")

نتيجة جدول المقارنة

Tableau comparatif des tailles de réseaux CIDR pour IPv4:
--------------------------------------------------------------------------------
Préfixe   Masque          Bits hôte       Nombre d'adresses  Adresses utilisables
--------------------------------------------------------------------------------
/8        255.0.0.0       24              16777216           16777214          
/16       255.255.0.0     16              65536              65534             
/20       255.255.240.0   12              4096               4094              
/24       255.255.255.0   8               256                254               
/27       255.255.255.224 5               32                 30                
/28       255.255.255.240 4               16                 14                
/29       255.255.255.248 3               8                  6                 
/30       255.255.255.252 2               4                  2                 
/31       255.255.255.254 1               2                  2                 
/32       255.255.255.255 0               1                  1

حالات خاصة في CIDR

شبكات /31 - الاتصال من نقطة إلى نقطة (RFC 3021)

أدخل المعيار RFC 3021 استخدام البادئة /31 لوصلات الاتصال من نقطة إلى نقطة، مما يتيح توفير عناوين IP:

def analyze_point_to_point_network(cidr_notation):
    """
    تحليل شبكة من نقطة إلى نقطة بالبادئة /31.
    
    Args:
        cidr_notation (str): ترميز CIDR (يجب أن يكون /31)
        
    Returns:
        dict: معلومات حول وصلة نقطة إلى نقطة
    """
    try:
        network = ipaddress.ip_network(cidr_notation, strict=False)
        
        if network.prefixlen != 31:
            return {'error': 'Cette fonction est conçue pour les réseaux /31 uniquement'}
        
        # في شبكة /31، يمكن استخدام العنوانين كليهما (RFC 3021)
        addresses = list(network.hosts())
        
        if len(addresses) != 2:
            return {'error': 'Nombre d\'adresses incorrect pour un réseau /31'}
        
        return {
            'network': str(network),
            'device_a': str(addresses[0]),
            'device_b': str(addresses[1]),
            'note': 'Configuration point à point (RFC 3021)'
        }
        
    except ValueError as e:
        return {'error': str(e)}

# مثال على وصلة من نقطة إلى نقطة
p2p_example = '192.168.1.0/31'
p2p_info = analyze_point_to_point_network(p2p_example)

print(f"\nLiaison point à point {p2p_example}:")
for key, value in p2p_info.items():
    print(f"- {key}: {value}")

شبكات /32 - عنوان واحد

للعناوين الفردية (مثل واجهات loopback):

def analyze_host_address(ip_address):
    """
    تحليل عنوان IP فردي (البادئة /32).
    
    Args:
        ip_address (str): عنوان IP (مع /32 أو بدونها)
        
    Returns:
        dict: معلومات حول العنوان
    """
    try:
        # التأكد من أن العنوان يحمل البادئة /32
        if '/' not in ip_address:
            ip_address = f"{ip_address}/32"
        
        host = ipaddress.ip_interface(ip_address)
        
        if host.network.prefixlen != 32:
            return {'error': 'Cette fonction est conçue pour les adresses /32 uniquement'}
        
        return {
            'address': str(host.ip),
            'prefix': host.network.prefixlen,
            'network': str(host.network),
            'is_private': host.ip.is_private,
            'note': 'Adresse unique (souvent utilisée pour les interfaces loopback)'
        }
        
    except ValueError as e:
        return {'error': str(e)}

# مثال على عنوان واحد
host_example = '10.0.0.1/32'
host_info = analyze_host_address(host_example)

print(f"\nAdresse unique {host_example}:")
for key, value in host_info.items():
    print(f"- {key}: {value}")

إدارة الشبكات الفرعية (Subnetting)

يُعدّ تقسيم الشبكة إلى شبكات فرعية مهمة شائعة لدى مسؤولي الشبكات. وتُسهّل Python هذه العملية:

def create_subnets(cidr_notation, new_prefix_length):
    """
    تقسيم شبكة CIDR إلى شبكات فرعية.
    
    Args:
        cidr_notation (str): ترميز CIDR للشبكة الأم
        new_prefix_length (int): طول البادئة للشبكات الفرعية
        
    Returns:
        list: قائمة الشبكات الفرعية
    """
    try:
        network = ipaddress.ip_network(cidr_notation, strict=False)
        
        if new_prefix_length <= network.prefixlen:
            return {'error': 'Le nouveau préfixe doit être plus grand que le préfixe du réseau parent'}
        
        subnets = list(network.subnets(new_prefix=new_prefix_length))
        
        # تحديد عدد الشبكات الفرعية المعروضة لتفادي مخرجات ضخمة
        display_limit = 10
        total_subnets = len(subnets)
        
        result = {
            'parent_network': str(network),
            'parent_prefix': network.prefixlen,
            'new_prefix': new_prefix_length,
            'total_subnets': total_subnets,
            'subnets_sample': [str(subnet) for subnet in subnets[:display_limit]]
        }
        
        if total_subnets > display_limit:
            result['note'] = f"Affichage limité aux {display_limit} premiers sous-réseaux sur un total de {total_subnets}"
        
        return result
        
    except ValueError as e:
        return {'error': str(e)}

# مثال على التقسيم إلى شبكات فرعية
subnet_example = '192.168.0.0/24'
new_prefix = 26

subnet_info = create_subnets(subnet_example, new_prefix)

print(f"\nDivision de {subnet_example} en sous-réseaux /{new_prefix}:")
for key, value in subnet_info.items():
    if key == 'subnets_sample':
        print(f"- Exemples de sous-réseaux:")
        for i, subnet in enumerate(value, 1):
            print(f"  {i}. {subnet}")
    else:
        print(f"- {key}: {value}")

تطبيق عملي: تخطيط الشبكة

إليك مثالًا على تطبيق عملي لتخطيط شبكة تضم عدة شبكات فرعية ذات احتياجات محددة من حيث عدد المضيفين:

def plan_network(base_network, requirements):
    """
    تخطط شبكة عن طريق تخصيص شبكات فرعية وفق متطلبات محددة.
    
    Args:
        base_network (str): الشبكة الأساسية بصيغة CIDR
        requirements (dict): قاموس يضم اسم الشبكة الفرعية وعدد المضيفين المطلوب
        
    Returns:
        dict: خطة الشبكات الفرعية المخصصة
    """
    try:
        network = ipaddress.ip_network(base_network, strict=False)
        sorted_requirements = sorted(requirements.items(), key=lambda x: x[1], reverse=True)
        
        allocated_subnets = {}
        next_network = network
        
        for name, hosts_needed in sorted_requirements:
            # حساب البادئة المطلوبة لعدد المضيفين
            # الصيغة: 2^(32-prefix) - 2 ≥ hosts_needed (لـ IPv4)
            prefix = 32
            while prefix > 0 and (2 ** (32 - prefix) - 2 < hosts_needed):
                prefix -= 1
            
            if prefix <= network.prefixlen:
                return {'error': f"Impossible d'allouer suffisamment d'adresses pour {name}"}
            
            # الحصول على الشبكة الفرعية المتاحة التالية
            try:
                subnet = next(next_network.subnets(new_prefix=prefix))
                allocated_subnets[name] = {
                    'subnet': str(subnet),
                    'prefix': prefix,
                    'addresses_total': subnet.num_addresses,
                    'addresses_usable': subnet.num_addresses - 2,
                    'network_address': str(subnet.network_address),
                    'broadcast_address': str(subnet.broadcast_address),
                    'first_usable': str(next(subnet.hosts())),
                    'last_usable': str(list(subnet.hosts())[-1])
                }
                
                # تحديث الشبكة المتبقية
                remaining_networks = list(next_network.address_exclude(subnet))
                if remaining_networks:
                    next_network = remaining_networks[0]
                else:
                    break
                    
            except StopIteration:
                return {'error': f"Espace d'adressage épuisé, impossible d'allouer pour {name}"}
        
        return {
            'base_network': str(network),
            'allocated_subnets': allocated_subnets
        }
        
    except ValueError as e:
        return {'error': str(e)}

# مثال على تخطيط شبكة مؤسسة
base_network = '10.0.0.0/22'  # كتلة /22 (1022 عنوانًا قابلًا للاستخدام)

# متطلبات الأقسام المختلفة
department_requirements = {
    'Bureau': 500,         # المكتب يحتاج إلى 500 مضيف
    'Serveurs': 100,       # الخوادم تحتاج إلى 100 مضيف
    'Invités': 200,        # شبكة الضيوف تحتاج إلى 200 مضيف
    'IoT': 50,             # أجهزة IoT تحتاج إلى 50 عنوانًا
    'Management': 30       # شبكة الإدارة تحتاج إلى 30 عنوانًا
}

network_plan = plan_network(base_network, department_requirements)

print(f"\nPlan de réseau pour {base_network}:")
if 'error' in network_plan:
    print(f"Erreur: {network_plan['error']}")
else:
    print(f"Réseau de base: {network_plan['base_network']}")
    print("\nAllocation des sous-réseaux:")
    for dept, subnet_info in network_plan['allocated_subnets'].items():
        print(f"\n{dept}:")
        for key, value in subnet_info.items():
            print(f"- {key}: {value}")

التوافق مع IPv6

تعمل جميع الدوال المذكورة أعلاه مع IPv6 أيضًا، رغم أن بعض المفاهيم، مثل عنوان البث (broadcast)، غير موجودة في IPv6:

def get_ipv6_cidr_range(cidr_notation):
    """
    تحسب نطاق العناوين لشبكة IPv6 بصيغة CIDR.
    
    Args:
        cidr_notation (str): صيغة CIDR لشبكة IPv6 (مثال: '2001:db8::/64')
        
    Returns:
        dict: معلومات عن شبكة IPv6
    """
    try:
        network = ipaddress.ip_network(cidr_notation, strict=False)
        
        if network.version != 6:
            return {'error': 'Cette fonction est conçue pour les réseaux IPv6 uniquement'}
        
        # الاقتصار في العرض على بضعة عناوين في IPv6
        # (وإلا فسنحصل على ملايين أو مليارات المدخلات)
        hosts_iter = network.hosts()
        first_host = next(hosts_iter)
        
        # في IPv6 نعرض أول العناوين وآخرها فقط
        # لأن عددها كبير جدًا عادةً
        sample_hosts = [str(first_host)]
        
        # بالنسبة للشبكات من نوع /64 والأكبر، يكون حساب العنوان الأخير مكلفًا جدًا
        # لذلك نبنيه يدويًا
        if network.prefixlen <= 64:
            # لبادئة ≤ 64، نحسب العنوان الأخير صراحةً
            last_host_str = str(network.network_address + (1 << (128 - network.prefixlen)) - 1)
            sample_note = "Trop d'adresses pour énumérer"
        else:
            # لبادئة > 64، يمكننا تعداد المضيفين
            # التقدم في المكرِّر للعثور على العنوان الأخير
            last_host = None
            count = 0
            limit = 1000  # تحديد عدد التكرارات للبادئات الأكبر
            
            for host in hosts_iter:
                last_host = host
                count += 1
                if count >= limit:
                    break
            
            last_host_str = str(last_host) if last_host else "..."
            sample_note = f"Échantillon limité à {count+1} adresses" if count < limit else f"Échantillon limité aux premières et dernières adresses"
        
        sample_hosts.append(last_host_str)
        
        return {
            'network_address': str(network.network_address),
            'prefix_length': network.prefixlen,
            'num_addresses': network.num_addresses,
            'address_sample': sample_hosts,
            'sample_note': sample_note,
            'is_private': network.is_private,
            'is_global': network.is_global,
            'version': 'IPv6'
        }
        
    except ValueError as e:
        return {'error': str(e)}

# أمثلة على شبكات IPv6
ipv6_examples = [
    '2001:db8::/32',   # كتلة التوثيق
    '2001:db8::/48',   # تخصيص نموذجي لموقع
    '2001:db8::/64',   # شبكة نموذجية لقطاع شبكي
    'fe80::/64',       # Link-local
    'fd00::/8'         # Unique Local Address (ULA)
]

for cidr in ipv6_examples:
    print(f"\nInformations pour le réseau IPv6 {cidr}:")
    network_info = get_ipv6_cidr_range(cidr)
    
    if 'error' in network_info:
        print(f"Erreur: {network_info['error']}")
        continue
    
    for key, value in network_info.items():
        print(f"- {key}: {value}")

الخلاصة

تُعدّ إدارة شبكات CIDR مهارة أساسية للمتخصصين في مجال تقنية المعلومات. وتوفّر الوحدة ipaddress في Python طريقة أنيقة وقوية للتعامل مع عناوين IP والشبكات.

إليك النقاط الرئيسية التي ينبغي تذكرها:

  1. تجمع صيغة CIDR بين عنوان IP وبادئة لتحديد شبكة
  2. تحدد البادئة عدد عناوين IP المتاحة في الشبكة
  3. تسهّل Python الحسابات الشبكية بفضل وحدة ipaddress
  4. تنطبق هذه المفاهيم على IPv4 وIPv6 معًا، مع بعض الاختلافات

هذه المعارف ضرورية من أجل:

  • تخطيط شبكات المؤسسات وتصميمها
  • فهم تجزئة الشبكات
  • ضبط أجهزة الشبكة
  • تطوير تطبيقات مراقبة الشبكات أو أتمتتها
  • تحسين أمان الشبكة عبر تجزئة مناسبة

لتعميق معارفك، راجع التوثيق الرسمي لوحدة ipaddress ووثائق RFC المرتبطة بمعايير الإنترنت.

InSkillCoach

نبذة عن InSkillCoach

خبير في التدريب والتقنيات

مدرّب متخصص في التقنيات المتقدمة والذكاء الاصطناعي، تدعمه شركة GNeurone Inc.

الشهادات:

  • AWS Certified Solutions Architect – Professional
  • شهادات Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
602
51

التعليقات

التعليقات مدعومة عبر GitHub Discussions

سجّل الدخول باستخدام GitHub للمشاركة في النقاش

تم نسخ الرابط!