kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

邮件SPF防伪

SPF 记录是存在 DNS 里的 TXT 记录,用来声明哪些服务器能代表你的域名发邮件,防止被伪造发信。

作用:收件方会查你的 SPF 记录,核对发信 IP 是否在授权列表内,不在就可能判为垃圾邮件或直接拒收。 常见格式:以v=spf1开头,例如v=spf1 include:spf.protection.outlook.com -all,表示只允许该服务发信。

spf 禁止所有

SPF“禁止所有”的核心实现是通过记录末尾的-all(硬失败)机制,明确拒绝所有未被前置规则授权的IP发送邮件,是邮件域名最高级别的发件权限管控策略。

SPF记录中的all机制是兜底规则,必须放在整条记录的最后位置,不同前缀对应不同的“禁止”强度:

-all(硬失败):完全禁止所有未授权IP,接收服务器会直接拒绝这类邮件,是真正意义上的“禁止所有”。

~all(软失败):标记未授权邮件为可疑但不直接拒绝,适合配合DMARC使用,避免误拦合法邮件。

绝对禁止使用+all,它会允许全球所有服务器代发邮件,完全失去SPF防护意义。

典型配置场景

完全禁发邮件的域名:配置记录为v=spf1 -all,表示该域名不允许任何服务器发送邮件,彻底阻断伪造该域名的发件行为。

仅授权指定发件源:比如仅允许企业自有邮件服务器发信,其余全部禁止,记录示例:v=spf1 ip4:114.xxx.xxx.xxx -all。

第三方邮件服务商场景:先引用服务商的SPF规则,再兜底禁止所有其他来源,例如谷歌邮箱场景:v=spf1 include:_spf.google.com -all。

TCP_NEW_SYN_RECV fix bug

https://github.com/torvalds/linux/commit/5e0724d027f0548511a2165a209572d48fe7a4c8

TCP_NEW_SYN_RECV 漏了上面patch

把 syn_recv 状态的req也放进 sk 队列.

在收到第三个ack 的时候执行:

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
tcp_check_req() {
	...
	child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, req, &own_req, 0);

	return inet_csk_complete_hashdance(sk, child, req, own_req);
}


tcp_v4_syn_recv_sock() {
	...
	// __inet_hash_nolisten(newsk, NULL); // 3.10.0
	__inet_hash_nolisten(newsk, NULL, req_to_sk(req_unhash), own_req); // fix
}

__inet_hash_nolisten() {
	...
	spin_lock(lock);
	if (osk) {
		*own_req = sk_nulls_del_node_init_rcu(osk);
	}
	spin_unlock(lock);
	...
}

inet_csk_complete_hashdance() {
	if (own_req) {
		inet_csk_reqsk_queue_drop(sk, req);
		reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req);
		if (inet_csk_reqsk_queue_add(sk, req, child))
			return child;
	}

	/* Too bad, another child took ownership of the request, undo. */
	bh_unlock_sock(child);
	sock_put(child);
	return NULL;
}

3.10.0 的代码 syn_recv_sock() -> __inet_hash_nolisten(newsk, NULL); 直接把newsk加到队列, 不考虑req。

就有可能出现BUG: 一个req创建了2个newsk, 在inet_csk_complete_hashdance的时候, 2个newsk都执行了inet_csk_reqsk_queue_drop. 导致req被多次释放

所以在splock内只让一个线程创建成功newsk, 用own_req标记

PerformanceObserver监测网页性能

https://segmentfault.com/a/1190000012833867?utm_source=sf-related

https://www.5axxw.com/questions/content/e8hdl8

https://www.cnblogs.com/momo798/p/17292621.html

处理模型

参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
navigationStart 加载起始时间
redirectStart 重定向开始时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回开始重定向的fetchStart的值。其他情况,则返回0)
redirectEnd 重定向结束时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回最后一次重定向接受完数据的时间。其他情况则返回0)
fetchStart 浏览器发起资源请求时,如果有缓存,则返回读取缓存的开始时间
domainLookupStart 查询DNS的开始时间。如果请求没有发起DNS请求,如keep-alive,缓存等,则返回fetchStart
domainLookupEnd 查询DNS的结束时间。如果没有发起DNS请求,同上
connectStart 开始建立TCP请求的时间。如果请求是keep-alive,缓存等,则返回domainLookupEnd
(secureConnectionStart) 如果在进行TLS或SSL,则返回握手时间
connectEnd 完成TCP链接的时间。如果是keep-alive,缓存等,同connectStart
requestStart 发起请求的时间
responseStart 服务器开始响应的时间
domLoading 从图中看是开始渲染dom的时间,具体未知
domInteractive 未知
domContentLoadedEventStart 开始触发DomContentLoadedEvent事件的时间
domContentLoadedEventEnd DomContentLoadedEvent事件结束的时间
domComplete 从图中看是dom渲染完成时间,具体未知
loadEventStart 触发load的时间,如没有则返回0
loadEventEnd load事件执行完的时间,如没有则返回0
unloadEventStart unload事件触发的时间
unloadEventEnd unload事件执行完的时间

兼容性:

案例

DNS解析时间: domainLookupEnd - domainLookupStart

TCP建立连接时间: connectEnd - connectStart

白屏时间: responseStart - navigationStart

dom渲染完成时间: domContentLoadedEventEnd - navigationStart

页面onload时间: loadEventEnd - navigationStart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script type="text/javascript">
	const perfObserver = new PerformanceObserver((observedEntries) => {
		const entry = observedEntries.getEntriesByType('navigation')[0];
		tim = entry.loadEventEnd - entry.domainLookupStart;
		//console.log('pageload time: ', tim);
		if (tim < 1000)
				document.getElementById('pageTimeShow').innerHTML = '耗时: ' + Math.round(tim) + '毫秒';
		else
				document.getElementById('pageTimeShow').innerHTML = '耗时: ' + (Math.round(tim/10) / 100) + '秒';
	})
	perfObserver.observe({ entryTypes: ['navigation'] });
	//console.log(performance.getEntriesByType("navigation")[0]);
	//console.log(performance.timing);
</script>

字段说明

key 说明
connectEnd HTTP(TCP) 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间
connectStart HTTP(TCP) 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间
decodedBodySize 从HTTP或缓存中获取的消息体积大小
domainLookupEnd DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
domainLookupStart DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
duration 加载时间
encodedBodySize 从HTTP或缓存中获取的body体积大小
entryType 资源类型,entryType类型不同数组中的对象结构也不同
fetchStart 浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前
initiatorType 谁发起的请求
name 资源名称,是资源的绝对路径或调用mark方法自定义的名称
nextHopProtocol 获取资源使用的网络协议
redirectEnd 最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内的重定向才算,否则值为 0
redirectStart 第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0
requestStart HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存,连接错误重连时,这里显示的也是新建立连接的时间
responseEnd HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存
responseStart HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存
secureConnectionStart HTTPS 连接开始的时间,如果不是安全连接,则值为 0
serverTiming 包含服务时间元数据的数组
startTime 开始时间
transferSize 加载资源的体积大小,包含请求头及请求体
workerStart DOMHighResTimeStamp