ip addr 的一些说明(转整)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ip addr 的一些说明(转整)相关的知识,希望对你有一定的参考价值。

参考技术A ip addr是linux下除ifconfig外,另一个查看ip的命令,可以先看看这个命令的输出:

通常这个命令我们最关心的是ip地址,也即192.168.3.9,那么我们就先来讲述一下ip。首先这是一个IPv4地址,这样的ip被分为四个部分,每部分一个字节(8bit),所以ip是32位的,但是这样产生的地址数量马上就不够用了,当初设计的时候并没有想到如今会有这么多的计算机,于是后来又诞生了IPv6,也就是上面输出中的fe80::20c:29ff:fee7:d708,这个有 128 位,目前看来是足够了。

对于前三类,每种又分为网络号和主机号两部分,为什么要区分这两个?就好比大家都住在六单元 1001 号,我是小区 A 的六单元 1001,而你是小区 B 的六单元 1001 号。网络号就相当于小区,主机号相当于具体门牌号。

下面这个表格,详细地展示了 A、B、C 三类地址所能包含的主机的数量。

这里面有个尴尬的事情,就是 C 类地址能包含的最大主机数量实在太少了,只有 254 个。当时设计的时候恐怕没想到,现在估计一个网吧都不够用吧。而 B 类地址能包含的最大主机数量又太多了。6 万多台机器放在一个网络下面,一般的企业基本达不到这个规模,闲着的地址就是浪费。

于是又产生了一种折中的方式无类型域间选路,简称CIDR,这种方案打破了原先将ip分为五类的做法,直接将32位的地址划分为两块,前面是网络号,后面是主机号,从哪里开始划分呢?注意上面输出的inet 192.168.3.9/24,ip后面多了个/24,这就表示,前24位是网络号,后8位是主机号。

伴随着CIDR存在的是一个广播地址192.168.3.255,如果发送这个地址,则192.168.3网络里的所有机器都能收到,另一个是子网掩码255.255.255.0,将子网掩码和ip地址进行AND运算,由于前三段都是255,转换成二进制都是1,1与任何数AND运算都是原来的值,故前三个数不变还是192.168.3,最后一段是0,0与任何数and都是0,所以最后是0,最终计算结果是192.168.3.0,这就是网络号,所以子网掩码和ip的and运算结果就是网络号。
在日常的工作中,几乎不用划分 A 类、B 类或者 C 类,所以时间长了,很多人就忘记了这个分类,而只记得 CIDR。但是有一点还是要注意的,就是公有 IP 地址和私有 IP 地址。

表格最右列是私有 IP 地址段。平时我们看到的数据中心里,办公室、家里或学校的 IP 地址,一般都是私有 IP 地址段。因为这些地址允许组织内部的 IT 人员自己管理、自己分配,而且可以重复。因此,你学校的某个私有 IP 地址段和我学校的可以是一样的。

表格中的 192.168.0.x 是最常用的私有 IP 地址。你家里有 Wi-Fi,对应就会有一个 IP 地址。一般你家里地上网设备不会超过 256 个,所以 /24 基本就够了。有时候我们也能见到 /16 的 CIDR,这两种是最常见的,也是最容易理解的。不需要将十进制转换为二进制 32 位,就能明显看出 192.168.0 是网络号,后面是主机号。而整个网络里面的第一个地址 192.168.0.1,往往就是你这个私有网络的出口地址。例如,你家里的电脑连接 Wi-Fi,Wi-Fi 路由器的地址就是 192.168.0.1,而 192.168.0.255 就是广播地址。一旦发送这个地址,整个 192.168.0 网络里面的所有机器都能收到。但是也不总都是这样的情况。因此,其他情况往往就会很难理解,还容易出错。比如:192.168.3.9/22,要是求一下这个网络的第一个地址、广播地址和子网掩码,要是你一上来就答192.168.3.1那就大错特错了,22不是8的整数倍就不好办了,前面的192.168所占的16位不变,只是3这段(0000 0011),只能化为6bit+2bit两部分,所以现在的情况就变成:前16位+6位是网络号,剩下的2位+8位是主机号,故第一个地址是192.168.<000000><00>.1即192.168.0.1,子网掩码是255.255.<111111><00>.0即255.255.252.0,广播地址是192.168.<000000><11>.255即192.168.3.255。是不是挺绕的?

在 IP 地址的后面有个 scope,对于eno16777736这张网卡来讲,是 global,说明这张网卡是可以对外的,可以接收来自各个地方的包。对于 lo 来讲,是 host,说明这张网卡仅仅可以供本机相互通信。lo全称是loopback,也就是回环网卡,,往往会被分配到 127.0.0.1 这个地址。这个地址用于本机通信,经过内核处理后直接返回,不会在任何网络中出现。

在ip地址的上一行是link/ether 00:0c:29:e7:d7:08,这个称为MAC地址,是网卡的物理地址,用16进制,6个字节表示。

因为 MAC 地址号称全局唯一,不会有两个网卡有相同的 MAC 地址,而且网卡自生产出来,就带着这个地址。很多人看到这里就会想,既然这样,整个互联网的通信,全部用 MAC 地址好了,只要知道了对方的 MAC 地址,就可以把信息传过去。这样当然是不行的,一个网络包要从一个地方发送到另一个地方,除了要知道对方的具体位置,还要有定位功能,ip就相当于是提供定位功能的,而MAC地址则类似于身份证号。诚然,身份证号是全局唯一的,但问题是我在北京,你在上海,就算我知道你身份证号能找到你吗?

所以,MAC 地址的通信范围比较小,局限在一个子网里面。例如,从 192.168.0.2/24 访问 192.168.0.3/24 是可以用 MAC 地址的。一旦跨子网,即从 192.168.0.2/24 到 192.168.1.2/24,MAC 地址就不行了,需要 IP 地址起作用了。

解析完了 MAC 地址,我们再来看 <BROADCAST,MULTICAST,UP,LOWER_UP> 是干什么的?这个叫作net_device flags,网络设备的状态标识。UP 表示网卡处于启动的状态;BROADCAST 表示这个网卡有广播地址,可以发送广播包;MULTICAST 表示网卡可以发送多播包;LOWER_UP 表示 L1 是启动的,也即网线插着呢。MTU1500 是指最大传输单元 MTU 为 1500,这是以太网的默认值。

qdisc pfifo_fast 是什么意思呢?qdisc 全称是queueing discipline,中文名叫排队规则。内核如果需要通过某个网络接口发送数据包,它都需要按照为这个接口配置的 qdisc(排队规则)把数据包加入队列。最简单的 qdisc 是 pfifo,它不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。pfifo_fast 稍微复杂一些,它的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。

=====================================================

X-Forwarded-For的一些理解

X-Forwarded-For 是一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址(其实这个真实未必是真实的,后面会说到)。

那为什么 Web 服务器只有通过 X-Forwarded-For 头才能获取真实的 IP?
这里用 PHP 语言来说明,不明白原理的开发者为了获取客户 IP,会使用 $_SERVER[‘REMOTE_ADDR‘] 变量,这个服务器变量表示和 Web 服务器握手的 IP 是什么(这个不能伪造)。
但是很多用户都通过代理来访问服务器的,那么假如使用该全局变量,PHP获取到的 IP 就是代理服务器的 IP(不是用户的)。

可能很多人看的晕乎乎的,那么看看一个请求可能经过的路径:

客户端=>(正向代理=>透明代理=>服务器反向代理=>)Web服务器

其中正向代理、透明代理、服务器反向代理这三个环节并不一定存在。

  • 什么是正向代理呢,很多企业会在自己的出口网关上设置代理(主要是为了加速和节省流量)。
  • 透明代理可能是用户自己设置的代理(比如为了FQ,这样也绕开了公司的正向代理)。
  • 服务器反向代理是部署在 Web 服务器前面的,主要原因是为了负载均衡和安全考虑。

现在假设几种情况:

  • 假如客户端直接连接 Web 服务器(假设 Web 服务器有公网地址),则 $_SERVER[‘REMOTE_ADDR‘] 获取到的是客户端的真实 IP 。
  • 假设 Web 服务器前部署了反向代理(比如 Nginx),则 $_SERVER[‘REMOTE_ADDR‘] 获取到的是反向代理设备的 IP(Nginx)。
  • 假设客户端通过正向代理直接连接 Web 服务器(假设 Web 服务器有公网地址),则 $_SERVER[‘REMOTE_ADDR‘] 获取到的正向代理设备的 IP 。

其实这里的知识点很多,记住一点就行了,$_SERVER[‘REMOTE_ADDR‘] 获取到的 IP 是 Web 服务器 TCP 连接的 IP(这个不能伪造,一般 Web 服务器也不会修改这个头)。

X-Forwarded-For

从上面大家也看出来了,因为有了各种代理,才会导致 REMOTE_ADDR 这个全局变量产生了一定的歧义,为了让 Web 服务器获取到真实的客户端 IP,X-Forwarded-For 出现了,这个协议头也是由 Squid 起草的(Squid 应该是最早的代理软件之一)。

这个协议头的格式:

X-Forwarded-For: client, proxy1, proxy2

client 表示用户的真实 IP,每经过一次代理服务器,代理服务器会在这个头增加用户的 IP(有点拗口)。
注意最后一个代理服务器请求 Web 服务器的时候是不会将自己的 IP 附加到 X-Forwarded-For 头上的,最后一个代理服务器的 IP 地址应该通过$_SERVER[‘REMOTE_ADDR‘]获取。

举个例子:
用户的 IP 为(A),分别经过两个代理服务器(B,C),最后到达 Web 服务器,那么Web 服务器接收到的 X-Forwarded-For 就是 A,B。

那么 PHP 如何获取真实客户端 IP 呢?

$ip = isset($_SERVER[‘HTTP_X_FORWARDED_FOR‘]) ? trim($_SERVER[‘HTTP_X_FORWARDED_FOR‘]) : ‘‘;
if (!$ip) {
    $ip = isset($_SERVER[‘REMOTE_ADDR‘]) ? trim($_SERVER[‘REMOTE_ADDR‘]) : ‘‘;
}
$a = explode(‘|‘, str_replace(‘,‘, ‘|‘, $ip));
$ip = trim($a[0]);

这里预先说明下,假设这两个代理服务器都是好的代理服务器,没有伪造 HTTP_X_FORWARDED_FOR。

配置反向代理

上面一直在说代理,大家可能觉得这到底有啥用?不同类型的代理有不同的目的,对于正向代理来说主要是为了加速并且让局域网的用户有一个真实的 IP 地址,而透明代理则主要是为了一些其他的目的(比如就是不想让别人知道我的 IP),而反向代理主要是企业内部安全和负载均衡考虑,这里主要说下如何配置反向代理。

现在只要是具备一定规模的网站(Web 服务器大于 1 台),为了安全和负载均衡考虑都会在 Web 服务器前面部署反向代理,反向代理有 HAproxy,Nginx,Apache 等等。

这里通过 Nginx 来部署反向代理:

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

简单的解释下:

  • X-Forwarded-For 表示 Nginx 接收到的头,原样的转发过来(假如不转发,Web 服务器就不能获取这个头)。
  • X-Real-IP,这是一个内部协议头(就是反向代理服务器和 Web 服务器约定的),这个头表示连接反向代理服务器的 IP 地址(这个地址不能伪造),其实个人觉得为了让 PHP 代码保持无二义性,不应该这样设置,可以修改为 proxy_set_header REMOTE_ADDR $remote_addr;

Apache WEB 服务器的 Access 日志如何获取 X-Forwarded-For 头

其实写这篇文章主要是因为自己在 Apache Web 服务器上获取不到 X-Forwarded-For(上层的负载均衡设备确定传递了),搜索了下(在 Apache 官方文档并没有找到解决方案),解决如下:

LogFormat "%{X-Forwarded-For}i %a %h %A %l %u %t "%r" %>s %b "%{Referer}i"
 "%{User-Agent}i"" combined

X-Forwarded-For 安全性

那么很多同学会说,通过 X-Forwarded-For 就能获取到用户的真实 IP,是不是万事大吉了,对于 Web 服务器来说,安全有两个纬度,第一个纬度是 REMOTE_ADDR 这个头,这个头不能伪造。第二个纬度就是 X-Forwarded-For,但是这个头是可以伪造的。

那么谁在伪造呢?,我们分别看下:

正向代理一般是公司加速使用的,假如没有特殊的目的,不应该传递 X-Forwarded-For 头,因为它的上层连接是内部 IP,不应该暴露出去,当然它也可以透明的传递这个头的值(而这个值用户可以伪造)。

透明代理,这个可能是用户自己搭建的(比如FQ),而且在一个用户的请求中,可能有多个透明代理,这时候透明代理就抓瞎了,为了让自己尽量的正确,也会透明的传递这个头的值(而这个值用户可以伪造),当然一些不法企业或者人员,为了一些目的,会改下这个头的值(比如来自世界各地的 IP 地址)。

反向代理,Web 服务器前的反向代理服务器是不会伪造的(同一个公司的),一般会原样传递这个头的值。

那么对应用程序来说,既然这个值不能完全相信,该怎么办呢?这取决于应用的性质:

假如提供的服务可能就是一些非机密服务,也不需要知道用户的真实 IP,那么建议应用程序或者 Web 服务器对 REMOTE_ADDR 做一些限制,比如进行限速等等,也可以放行一些白名单的代理 IP,但是这些白名单 IP 就太难衡量了。

假设你的服务很重要,比如抽奖(一个 IP 只能一次抽奖),这时候你可能想通过 X-Forwarded-For 来获取用户的真实 IP(假如使用 REMOTE_ADDR 则会误杀一片),但是由于 X-Forwarded-For 可能会伪造,所以其实并没有什么好的办法,只能在应用层进行处理了。





以上是关于ip addr 的一些说明(转整)的主要内容,如果未能解决你的问题,请参考以下文章

CentOS7修改网卡名称为eth0及一些基本设置

C#中获取服务器IP,客户端IP以及Request.ServerVariables详细说明

Nginx日志变量说明

memcached 常用命令及使用说明

从ip addr add和ifconfig的区别看linux网卡ip地址的结构

从ip addr add和ifconfig的区别看linux网卡ip地址的结构