【T02】理解子网和CIDR的概念

本文详细解析IP地址分类,包括A、B、C、D、E类的特性与应用,探讨子网划分原理,以及CIDR技术如何优化IP地址分配,减少路由表项,实现更高效网络管理。
1、IP地址分为5类,A、B、C、D、E,它们的前缀分别是:
    A:0     网络个数2^7,主机个数2^24,大概1千6百万
    B:10        网络个数2^14,大概1万6千,主机个数2^16,大概6万5千
    C:110       网络个数2^21,大概2百万,主机个数2^8,254个
    D:1110      用于多播编址
    E:1111      留作未来使用
    注意:对于主机号,全0和全1特殊用处,因此可用的地址要减去2
2、子网划分,IP地址分为网络ID和主机ID,考虑B类的主机ID,可以容纳6万5千个主机,现实中根本用不了这么多,
    因此在内部(比如局域网)可以从主机ID中,划出一部分作为子网。如果子网掩码相同,可以认为主机在同一个网络中。
3、广播地址分为以下情况:
    有限广播为255.255.255.255,路由器从不转发这种数据报,局域网内的所有主机可以收到
    网络直接广播为指定网络ID,主机ID全部设为1,传送到目标网络的所有主机
    子网直接广播为指定网络ID和子网ID,子网内的所有主机收到数据报
4、对于C类地址,能够容纳主机个数太少,需要网络ID减少,这可以认为CIDR(Classless Inter Domain Routing 无类别域间路由)
    子网掩码是加长网络ID,而CIDR使其变短,同时指定网络掩码。
    虽然B类地址,加上子网掩码,也类似C类地址缩短网络号,但是B类地址从外部用来看,认为网络号还是不带子网的前缀。
    CIDR不按照传统的IP地址分类,而是指定网络掩码,使得IP地址的分配更加有效。
5、为什么CIDR使得IP地址的分配更加有效?
    举例来说,现在有3个1000G的硬盘,使用传统的方式,只能进行分区如下:
    10个100G的分区,100个10G的分区,1000个1G的分区,分别对应于A类,B类,C类地址。
    但是在实际使用中,可能根本不需要10个100G的分区,但是没有办法,只能进行这样进行分区来使用。
    而CIDR彻底废弃了这种方法,无分类就是不考虑IP地址所属的类别。
    根据实际的需求进行分区,比如第一个1000G的硬盘,可以分成25个40G的分区,或者40个25G的分区,或者200个5G的分区。
6、更重要的一点是,CIDR这种组网技术可以将一组较小的无类别网络汇聚为一个较大的单一路由表项,
    减少Internet路由域中路由表条目的数量。

转载于:https://www.cnblogs.com/nzbbody/p/6389587.html

#include "cidr_utils.h" // 判断 IPv4 是否在 CIDR 网段中 int is_in_cidr(const char *ip_str, const char *cidr_str) { struct in_addr ip_addr, network, mask; if (inet_pton(AF_INET, ip_str, &ip_addr) <= 0) { return 0; // 无效 IP } char cidr_copy[32]; strncpy(cidr_copy, cidr_str, sizeof(cidr_copy) - 1); cidr_copy[sizeof(cidr_copy) - 1] = '\0'; char *slash = strchr(cidr_copy, '/'); if (!slash) return 0; *slash = '\0'; int bits = atoi(slash + 1); if (inet_pton(AF_INET, cidr_copy, &network) <= 0) { return 0; // 无效网络 } // 计算子网掩码 mask.s_addr = (bits == 0) ? 0 : htonl((0xFFFFFFFF << (32 - bits)) & 0xFFFFFFFF); // 判断是否在子网中 return (ip_addr.s_addr & mask.s_addr) == (network.s_addr & mask.s_addr); } // 判断 IPv6 是否在 CIDR 网段中 int is_in_ipv6_cidr(const char *ip_str, const char *cidr_str) { struct in6_addr ip_addr, network_addr; unsigned int prefix_len; // 解析 CIDR char cidr_copy[128]; strncpy(cidr_copy, cidr_str, sizeof(cidr_copy) - 1); cidr_copy[sizeof(cidr_copy) - 1] = '\0'; char *slash = strchr(cidr_copy, '/'); if (!slash) return 0; *slash = '\0'; prefix_len = atoi(slash + 1); // 解析网络地址 if (inet_pton(AF_INET6, cidr_copy, &network_addr) <= 0) { return 0; } // 解析输入的 IP if (inet_pton(AF_INET6, ip_str, &ip_addr) <= 0) { return 0; } // 比较前缀 int full_bytes = prefix_len / 8; int partial_bits = prefix_len % 8; for (int i = 0; i < full_bytes; i++) { if (ip_addr.s6_addr[i] != network_addr.s6_addr[i]) { return 0; } } if (partial_bits > 0) { unsigned char mask = (0xFF << (8 - partial_bits)) & 0xFF; if ((ip_addr.s6_addr[full_bytes] & mask) != (network_addr.s6_addr[full_bytes] & mask)) { return 0; } } return 1; } /* ANSI-C code produced by gperf version 3.1 */ /* Command-line: gperf -t -N is_ip_denied -K ip -L ANSI-C denylist.gperf */ /* Computed positions: -k'7,9' */ #include "denylist_hash.h" #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) /* The character set is not based on ISO-646. */ #error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>." #endif #line 3 "denylist.gperf" struct denylist_entry { const char* ip; // 存储要匹配的 IPv4/IPv6 地址 }; #define TOTAL_KEYWORDS 12 #define MIN_WORD_LENGTH 14 #define MAX_WORD_LENGTH 18 #define MIN_HASH_VALUE 18 #define MAX_HASH_VALUE 43 /* maximum key range = 26, duplicates = 0 */ #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static unsigned int hash (register const char *str, register size_t len) { static unsigned char asso_values[] = { 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 15, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 9, 44, 15, 5, 0, 0, 44, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 10, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44 }; return len + asso_values[(unsigned char)str[8]] + asso_values[(unsigned char)str[6]]; } struct denylist_entry * is_ip_denied (register const char *str, register size_t len) { static struct denylist_entry wordlist[] = { {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, #line 8 "denylist.gperf" {"239.255.255.250 "}, #line 19 "denylist.gperf" {"ff05::1:5 "}, {""}, {""}, #line 18 "denylist.gperf" {"ff05::1:3 "}, #line 10 "denylist.gperf" {"239.255.12.42 "}, {""}, {""}, {""}, #line 11 "denylist.gperf" {"224.0.23.0 "}, #line 12 "denylist.gperf" {"224.0.1.178 "}, {""}, {""}, #line 16 "denylist.gperf" {"ff05::2 "}, {""}, #line 14 "denylist.gperf" {"ff01::2 "}, {""}, {""}, {""}, #line 13 "denylist.gperf" {"ff01::1 "}, #line 9 "denylist.gperf" {"232.0.0.100 "}, {""}, {""}, {""}, #line 17 "denylist.gperf" {"ff05::fb "}, #line 15 "denylist.gperf" {"ff01::fb "} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { register unsigned int key = hash (str, len); if (key <= MAX_HASH_VALUE) { register const char *s = wordlist[key].ip; if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') return &wordlist[key]; } } return 0; } #line 20 "denylist.gperf" #include <stdio.h> #include <string.h> #include "denylist_hash.h" #include "cidr_utils.h" int is_ip_denied_extended(const char* ip) { // 1. 固定 denylist 检查 if (is_ip_denied(ip, strlen(ip)) != NULL) { return 1; } // 2. IPv4 CIDR 匹配 if (is_in_cidr(ip, "224.0.0.0/24")) { return 1; } // 3. IPv6 CIDR 匹配 if (is_in_ipv6_cidr(ip, "ff02::/16")) { return 1; } return 0; } int main() { const char* test_ips[] = { "224.0.0.1", // 固定 denylist "224.0.0.123", // IPv4 CIDR "224.0.1.1", // 允许 "ff02::1", // 固定 denylist "ff02::a1", // IPv6 CIDR "ff03::1", // 允许 "8.8.8.8", // 允许 "::1", // 允许 "ff02::2", // 固定 denylist "ff02:0000:0000:0000::1" // IPv6 CIDR }; for (int i = 0; i < 10; ++i) { const char* ip = test_ips[i]; printf("IP: %s -> %s\n", ip, is_ip_denied_extended(ip) ? "DENIED" : "ALLOWED"); } return 0; } 这是我的程序完整.c文件内容,帮我生成一下文件结构图
最新发布
09-02
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值