不可靠(unreliable)的意思是它不能保证IP数据报能成功地到达目的地。IP仅提供最好的传输服务。如果发生某种错误时,如某个路由器暂时用完了缓冲区,IP有一个简单的错误处理算法:丢弃该数据报,然后发送 ICMP消息报给信源端。任何要求的可靠性必须由上层来提供(如TCP)。

TCP的状态变迁图

摘自《TCP-IP详解》

摘自《Unix网络编程》 2.5节 The Transport Layer: TCP, UDP, and SCTP

ss

TCP在不可靠的IP层上提供了一个可靠的运输层。为了提供这种可靠的服务,TCP采用了超时重传、发送和接收端到端的确认分组等机制。

ARP属于链路层还是网络层,https://www.zhihu.com/question/27668104

连MAC都不知道的算第1层,例如已经死绝了的hub只知道MAC不知道IP的算第2层,例如普通交换机只知道IP不知道port(也就不管TCP还是UDP)的算第3层,例如普通路由器知道IP还知道port的算第4层,例如 NAT关心payload的算第7层,例如 http proxy

作者:陈硕

如果要在TCP/IP协议栈中选择一个”最不安全的协议”,那么我会毫不犹豫把票投给ARP协议。我们经常听到的这些术语,包括”网络扫描”、”内网渗透”、”中间人拦截”、”局域网流控”、”流量欺骗”,基本都跟ARP脱不了干系。大量的安全工具,例如大名鼎鼎的Cain、功能完备的Ettercap、操作傻瓜式的P2P终结者,底层都要基于ARP实现。

当一台主机把以太网数据帧发送到位于同一局域网上的另一台主机时,是根据 48 bit的以
太网地址来确定目的接口的。设备驱动程序从不检查IP数据报中的目的IP地址。
地址解析为这两种不同的地址形式提供映射: 32 bit的IP

ARP是解决统一局域网上的主机路由器的IP地址和硬件地址的映射问题。
每一个主机都设有一个ARP高速缓存,里面有本局网上的各主机和路由器的IP地址到硬件地址的映射表
当主机A要向本局域网上的某个主机B的IP地址发送IP数据报时,就先在其ARP高速缓存中查看有无主机B的IP地址,如果有,就在ARP高速缓存器中查找出其对应的硬件地址,再把这个硬件地址写入mac帧中,然后通过局域网把mac帧发往此硬件地址,否则主机A就自动运行ARP,然后按以下步骤找出主机B的硬件地址:
(1)ARP进程在本局网上广播发送一个ARP请求分组。
(2)在本局域网上的所有主机上运行的ARP进程都收到此ARP请求分组。
(3)主机B的IP地址与ARP请求分组中要查询的IP地址一致就收下这个ARP请求分组,并向主机A发送ARP响应分组,并在这个ARP响应分组中写如自己的硬件地址。
(4)主机A收到主机B的ARP响应分组后,就在其ARP高速缓存中写入主机B的IP地址到硬件地址的映射。

1
2
3
4
5
6
# 我的GPU虚机,为什么只缓存了两条记录?
$ arp -v
Address HWtype HWaddress Flags Mask Iface
192.168.4.2 ether fa:16:3e:45:99:f4 C eth0
192.168.4.1 ether fa:16:3e:e1:79:74 C eth0
Entries: 2 Skipped: 0 Found: 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# -v参数显示环回接口
C:\Users\ADMIN>arp -a -v

接口: 127.0.0.1 --- 0x1 # 环回接口,虚拟网卡。并不表示“本机”
Internet 地址 物理地址 类型
224.0.0.22 静态 #
224.0.0.251 静态
239.255.255.250 静态

接口: 9.186.102.45 --- 0xc # 以太网适配器。连接特定的DNS后缀: crl.ibm.com
Internet 地址 物理地址 类型
9.186.102.1 00-00-0c-07-ac-52 动态 # 网关。动态说明可以改变。手工绑定之后,就不会受ARP攻击的影响了
9.186.102.3 e8-ba-70-42-96-c0 动态 # 后面这些是干嘛的,
9.186.102.4 e8-ba-70-42-89-c0 动态
9.186.102.100 d4-81-d7-8b-4d-31 动态
9.186.102.108 44-37-e6-c3-a4-b9 动态 # 我曾经远程桌面连接过的服务器
9.186.102.154 00-21-86-f1-47-ae 动态
9.186.102.176 3c-97-0e-b6-5c-56 动态
9.186.102.255 ff-ff-ff-ff-ff-ff 静态 # ff:ff:ff:ff:ff:ff是广播地址。
224.0.0.22 01-00-5e-00-00-16 静态 # 01:00:5e:xx:xx:xx是IPv4多播地址
224.0.0.251 01-00-5e-00-00-fb 静态 # 不同多播地址,什么含义?是代表我的主机曾经连接过这些主机,是吧
224.0.0.252 01-00-5e-00-00-fc 静态
239.255.255.250 01-00-5e-7f-ff-fa 静态
255.255.255.255 ff-ff-ff-ff-ff-ff 静态 # 为什么两个广播地址。

接口: 9.186.59.118 --- 0xd
Internet 地址 物理地址 类型
9.186.58.1 00-00-00-00-00-00 无效 # 网关
9.186.59.255 ff-ff-ff-ff-ff-ff 静态
224.0.0.22 01-00-5e-00-00-16 静态
224.0.0.251 01-00-5e-00-00-fb 静态
224.0.0.252 01-00-5e-00-00-fc 静态
239.255.255.250 01-00-5e-7f-ff-fa 静态
255.255.255.255 ff-ff-ff-ff-ff-ff 静态

接口: 0.0.0.0 --- 0xffffffff # 表示“本网络中的本机”
Internet 地址 物理地址 类型
224.0.0.22 01-00-5e-00-00-16 静态
224.0.0.251 01-00-5e-00-00-fb 静态
255.255.255.255 ff-ff-ff-ff-ff-ff 静态

接口: 192.168.191.1 --- 0x31
Internet 地址 物理地址 类型
192.168.191.2 d4-90-9c-57-ad-75 静态
192.168.191.255 ff-ff-ff-ff-ff-ff 静态
224.0.0.22 01-00-5e-00-00-16 静态
224.0.0.251 01-00-5e-00-00-fb 静态
224.0.0.252 01-00-5e-00-00-fc 静态
239.255.255.250 01-00-5e-7f-ff-fa 静态
255.255.255.255 ff-ff-ff-ff-ff-ff 静态

采用双向绑定的方法解决并且防止ARP欺骗

疑问

ARP协议:不知道局域网有多少IP,首先广播。在局域网里每个机子收到广播后,回复mac。拿到信息会有一个ARP表。

  • ARP表存在哪?
    每台设备都会维护一份ARP表。
  • 每台机器会维护全部表吗?会维护全表。

有了 IP 地址,为什么还要用 MAC 地址?

一. 整体与局部信息传递时候,需要知道的其实是两个地址:

  • 终点地址(Final destination address)
  • 下一跳的地址(Next hop address)

IP地址本质上是终点地址,它在跳过路由器(hop)的时候不会改变,而MAC地址则是下一跳的地址,每跳过一次路由器都会改变。

这就是为什么还要用MAC地址的原因之一,它起到了记录下一跳的信息的作用。

注:一般来说IP地址经过路由器是不变的,不过NAT(Network address translation)例外,这也是有些人反对NAT而支持IPV6的原因之一。

introduction

三种实现:

  • python的smtplib
  • javamail.lib
  • 自己写简易socket实现
  • telnet实现

smtplib实现发送email

  1. 利用smtplib发送email,源代码。

见song.common.autoalert.email.send.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 以python源代码为基准
import smtplib
from email.mime.text import MIMEText
from config import *
import socket

def send_mail(to_list,subject,content):
me="hello"+"<"+mail_user+"@"+mail_postfix+">"
msg = MIMEText(content,_subtype='plain',_charset='gb2312')
msg['Subject'] = subject
msg['From'] = me
msg['To'] = ";".join(to_list)
try:
server = smtplib.SMTP()

server.connect(smtp_host, smtp_port) # 这里有response吗?加ssl连接吗?
server.ehlo() # 与服务器打招呼,并告知客户端使用的机器名字,可以随便填写
server.starttls() # 登录时需要启动TLS加密 (smtp服务器规定的)
server.login(mail_user,mail_pass) # 这里做了什么?建立了tls加密的socket连接,然后发送加密后的数据获取认证吗?
server.sendmail(me, to_list, msg.as_string()) # 这里有response吗,没有response应该就是UDP连接吧
server.close()
return True
except Exception, e:
print str(e)
return False

if __name__ == '__main__':
if send_mail(mailto_list,"hello","send from python smtplib"):
print "发送成功"
else:
print "发送失败"
  1. 修改源代码 smtpliba.py
1
2
3
4
5
6
7
8
def putcmd(self, cmd, args=""):
"""Send a command to the server."""
if args == "":
str = '%s%s' % (cmd, CRLF)
else:
str = '%s %s%s' % (cmd, args, CRLF)
print 'sending:' + str # 在smtpliba.py中添加这一行代码
self.send(str)
  1. 运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Authentication methods
Authentication methods the server supports:
authlist: ['LOGIN', 'PLAIN', 'XOAUTH2'] # outlook竟然还支持plain的登录方式?

# authmethod = AUTH_PLAIN
sending: ehlo [192.168.253.1]
sending: STARTTLS
sending: ehlo [192.168.253.1]
sending: AUTH PLAIN AHMyamFja3NvbkBob3RtYWlsLmNvbQBrZGY4KmRmNSFzNF9q
sending: mail FROM:<s2jackson@hotmail.com> size=215
sending: rcpt TO:<13521649928@139.com>
sending: data
# 发送成功

# authmethod = AUTH_LOGIN
sending: ehlo [192.168.253.1]
sending: STARTTLS
sending: ehlo [192.168.253.1]
sending: AUTH LOGIN czJqYWNrc29uQGhvdG1haWwuY29t
sending: a2RmOCpkZjUhczRfag==
sending: mail FROM:<s2jackson@hotmail.com> size=215
sending: rcpt TO:<13521649928@139.com>
sending: data
# 发送成功

javamail实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 以java源代码为基准
package song.net.mail.demo;

import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import java.util.Properties;
import song.config.Info;

public class SendWithAuth {
private static final String SMTP_HOST_NAME = Info.SMTP_HOST;
private static final Integer SMTP_PORT = Info.SMTP_PORT;
private static final String SMTP_AUTH_USER = Info.SMTP_AUTH_USER;
private static final String SMTP_AUTH_PWD = Info.SMTP_AUTH_PWD;
private static final String MAIL_TO = Info.MAIL_TO;

public static void main(String[] args) throws Exception{
new SendWithAuth().test();
}

public void test() throws Exception{
Properties props = new Properties();
// property列表,见 https://javamail.java.net/nonav/docs/api/com/sun/mail/smtp/package-summary.html
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.host", SMTP_HOST_NAME);
props.put("mail.smtp.port", SMTP_PORT); // 默认是25端口,但是这个smtp服务器要求是587端口
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", true); // 登录时需要启动TLS加密 (smtp服务器规定的)

Authenticator auth = new SMTPAuthenticator();
Session mailSession = Session.getDefaultInstance(props, auth);
Transport transport = mailSession.getTransport();

// header是在什么时候加的?比如Subject,from,to, cc等
MimeMessage message = new MimeMessage(mailSession);
message.setContent("send from java mail", "text/plain"); // 等价于message.setText
message.setFrom(new InternetAddress(SMTP_AUTH_USER)); // Set From: header field of the header.
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(MAIL_TO)); // Set To: header field of the header.
message.setSubject("hi"); // Set Subject: header field, 可省略


transport.connect();
transport.sendMessage(message,
message.getRecipients(Message.RecipientType.TO));
transport.close();
}

private class SMTPAuthenticator extends javax.mail.Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
String username = SMTP_AUTH_USER;
String password = SMTP_AUTH_PWD;
return new PasswordAuthentication(username, password);
}
}

}

自己写简易socket实现smtp邮件发送

telnet实现smtp邮件发送

##

nameserver root zone

How Domain Name Servers Work
How the Domain Name System (DNS) Works

区域文件

要理解不同的 DNS 记录,首先必须了解区域文件是什么?

区域文件
区域文件是名称服务器存储其所知道的域名的信息的方式。名称服务器知道的每个域名都存储在区域文件中。对于名称服务器来说,大多数请求都不能在它自己服务器中找到区域文件。

如果它被配置成可以递归查询,如解析名称服务器,那它会递归找到结果并返回。否则,它会告诉请求者方下一步到哪里查询。

名称服务器具有的区域文件越多,它能够权威回答的请求越多。

解析过程

DNS地址解析器的核心功能能

  • gethostbyname 主机名->ip
  • gethostbyaddr ip-主机名

gethostbyname 主机名–>ip

DNS服务器在名称解析过程中正确的查询顺序为:

本地缓存记录→区域记录→根域名服务器→转发域名服务器

具体步骤如下:

  1. 客户机提交域名解析请求,并将该请求发送给本地域名服务器
  2. 当本地的域名服务器收到请求后,就先查询本地缓存。如果有查询的DNS信息记录,则直接返回查询的结果。如果没有该记录,本地域名服务器就把请求发给根域名服务器
  3. 根域名服务器再返回给本地域名服务器一个所查询域的顶级域名服务器的地址。
  4. 本地服务器再向返回的域名服务器发送请求。
  5. 接收到该查询请求的域名服务器查询其缓存和记录,如果有相关信息则返回本地域名服务器查询结果,否则通知本地域名服务器下级的域名服务器的地址。
  6. 本地域名服务器将查询请求发送给下级的域名服务器的地址,直到获取查询结果。
  7. 本地域名服务器将返回的结果保存到缓存,并且将结果返回给客户机,完成解析过程。

通常情况下,我们是先设定DNS解析规则,然后ISP(供应商)依据指定的解析规则进行DNS解析。同样,我们通过测试解析结果,也可以反推DNS解析规则。本文以百度首页为例,分析其DNS解析规则。

域名的层级

本机只向自己的DNS服务器查询,dig命令有一个@参数,显示向其他DNS服务器查询的结果。

DNS服务器怎么会知道每个域名的IP地址呢?答案是分级查询。

举例来说,www.example.com真正的域名是www.example.com.root,简写为www.example.com.。因为,根域名.root对于所有域名都是一样的,所以平时是省略的。

根域名的下一级,叫做”顶级域名”(top-level domain,缩写为TLD),比如.com、.net;再下一级叫做”次级域名”(second-level domain,缩写为SLD),比如www.example.com里面的.example,这一级域名是用户可以注册的;再下一级是主机名(host),比如www.example.com里面的www,又称为"三级域名",这是用户在自己的域里面为服务器分配的名称,是用户可以任意分配的。

流程

因为DNS系统是分层的,每个DNS只知道自己所管理的域,并不知道其他域。我的电脑DNS服务器设置为8.8.8.8,当我要解析www.zhihu.com的时候,假如8.8.8.8这台DNS服务器并没有缓存关于www.zhihu.com的信息,那么8.8.8.8就要向13台根服务器查询,这13台服务器也不知道www.zhihu.com的IP,但是它知道.com,.net等这些顶级域的DNS的IP地址,于是告诉8.8.8.8向这些顶级域的服务器去查询www.zhihu.com的信息,.com再告诉8.8.8.8要向zhihu.com的DNS服务器查询www这台主机的IP地址,最终才能解析www.zhihu.com。所以在目前来说(.)是整个DNS系统的核心,在DNS系统里面是必须存在的,如果没有(.),DNS的层级结构就被破坏的。

https://www.zhihu.com/question/21499001/answer/18432636

其他

ICANN拒绝谷歌将.search变成无点顶级域名

非常好的文章–http://colobu.com/2016/09/29/more-about-dns/

权威DNS

权威DNS是经过上一级授权对域名进行解析的服务器,同时它可以把解析授权转授给其他人,如COM顶级服务器可以授权xxorg.com这个域名的的权威服务器为NS.ABC.COM,同时NS.ABC.COM还可以把授权转授给NS.DDD.COM,这样NS.DDD.COM就成了ABC.COM实际上的权威服务器了。平时我们解析域名的结果都源自权威DNS。比如xxorg.com的权威DNS服务器就是dnspod的F1G1NS1.DNSPOD.NET和F1G1NS2.DNSPOD.NET。

从字面意思也可以看出,权威就是该域名及下级域名的“说了算”的服务器;在权威上可以设置,修改,删除该区域内的解析记录, 而非权威DNS只能是查询。

Local DNS

Local DNS 也是和我们日常上网接触最多的DNS包括你的服务提供商(ISP)分配给你的DNS(一般为两个),或者接下来讲到的公共DNS。又因为填写在你的本地电脑上,所以也称为Local DNS。

公共DNS

公共DNS不是:

  • 不是根服务器
  • 不是权威dns托管商,不提供域名注册等服务,比如万网和DNSpod
  • 不是权威dns,不针对个别域名进行解析
  • 公共DNS服务的特点就是服务的域名数量巨大,用户数多,同时要求具有安全性和抗攻击性,低延迟(响应快),无拦截(无广告)以及对解析成功率要求非常的高。
1
2
3
4
5
6
7
8
9
10
Google DNS:	8.8.8.8	8.8.4.4
OpenDNS: 208.67.222.222 208.67.220.220
V2EX DNS: 199.91.73.222 178.79.131.110
OpenerDNS: 42.120.21.30 (无添加剂)
香港: 205.252.144.228 202.181.224.2
澳门:202.175.3.8 202.175.3.3
台湾: 168.95.192.1 168.95.1.1
114DNS: 114.114.114.114,114.114.115.115
阿里DNS: 223.5.5.5,223.6.6.6
百度DNS: 180.76.76.76

用114DNS真的会被嵌广告

递归DNS

就是local dns。递归DNS可以理解为是一种功能复杂些的resolver,其核心功能一个是缓存、一个是递归查询。收到域名查询请求后其首先看本地缓存是否有记录,如果没有则一级一级的查询根、顶级域、二级域……直到获取到结果然后返回给用户。日常上网中运营商分配的DNSNS如8.8.8.8即这里所说的递归DNS。

递归服务器怎么知道根权威服务器的地址?很简单,在递归服务器上都保存有一份根服务器的地址列表,如上面表格列出的根服务器的地址。

递归服务器每次查询域名都要向根那里找权威服务器吗?不是的,一旦成功一次,递归服务器就会把权威服务器列表缓存下来(如COM顶级服务器列表可以缓存48小时)。

根域名服务器

一般说的13个根DNS服务器,指的是逻辑上有13个,而不是物理上13个服务器。

所有 root DNS的坐标:http://root-servers.org/ 。截至2014年10月,全球有504台根服务器,被编号为A到M共13个标号。

中国大陆在北京有三台编号为L的镜像,编号为F、I、J的镜像各一台,共6台;香港有编号为D、J的镜像各2台,编号为A、F、I、L的镜像各一台,共8台;台湾则有编号为F、I、J各一台,共3台。(镜像技术)

值的注意的是,在中国的只是根服务器的镜像,而不是根服务器的管理者,没有控制权。而且一经发现镜像服务器频繁出错,管理者有权将这个镜像踢出路由表。2010年就发生过此事。

为什么不能在中国设立第十四个根域名服务器

https://commondatastorage.googleapis.com/letscorp_archive/archives/73147

美国放松根域名服务器管控:不会彻底放手,但中国应抓住契机

为什么 DNS 根服务器只有 13 个 IP

为什么中国不建立根服务器?

一个IP如何实现全球部署? 任播(Anycast)技术

这是网络层的技术,详见网络层

通常一个IP都是对应一台通讯主机。
谷歌DNS服务8.8.8.8也是一台主机吗?根域名服务器只有13台吗?如何实现一个IP却全球部署?

虽然IP地址相同,但是服务器确可能有多台。

。大部分借由任播(Anycast)技术,编号相同的根服务器使用同一个IP,504台根服务器总共只使用13个IP,因此可以抵抗针对其所进行的分布式拒绝服务攻击(DDoS)。
在IP网络上通过一个Anycast地址标识一组DNS服务群,访问该地址的报文可以被IP网络路由到这一组DNS群的任何一台主机上,因此不同区域的用户会被路由到最近的服务器。

任播Anycasting最初是在RFC1546中提出并定义的,它的最初语义是,在IP网络上通过一个Anycast地址标识一组提供特定服务的主机,同时服务访问方并不关心提供服务的具体是哪一台主机(比如DNS或者镜像服务),访问该地址的报文可以被IP网络路由到这一组目标中的任何一台主机上,它提供的是一种无状态的、尽力而为的服务。

DNS劫持也是类似的原理吗?假装IP是8.8.8.8

如何查询8.8.8.8背后有哪些ip提供服务?

https://www.v2ex.com/t/259939

原理

DNS劫持 DNS污染

指的是用户访问一个地址,国内的服务器(非DNS)监控到用户访问的已经被标记地址时,服务器伪装成DNS服务器向用户发回错误的地址的行为。 为了减免网络上的交通,一般的域名都会把外间的域名服务器数据暂存起来,待下次有其他机器要求解析域名时,可以立即提供服务。一旦有关网域的局域域名服务器的缓存受到污染,就会把网域内的电脑导引往错误的服务器或服务器的网址。

某个国家出现过多次的DNS污染, 参看知乎。

8.8.8.8告诉我youtube网站的IP是1.2.3.4。我是该怀疑谁?

说明你被劫持了

如果traceroute 8.8.8.8时,从国内ip直接跳到8.8.8.8,那极可能是运营商自己搞的假服务器,中国移动的宽带,基本上将网上公开的公众dns都搞了个假的,目的就是完全劫持网内的dns查询。

我假装我是8.8.8.8不行吗?
你假装真不行,运营商假装才行。有的地区的运营商是会劫持8.8.8.8到它的服务器的

如何检查DNS是否被劫持

DNS劫持是什么原理

DNS缓存

查询DNS的时候可能会有多个地方存在缓存:

浏览器 DNS缓存
Java DNS缓存
OS DNS缓存
Local DNS缓存