ICMP协议与TTL值:ping与Dos攻击的背后,便捷的探针与廉价的子弹
前言
输入 ping 命令,你便得到了你的设备到目标服务器的延迟。除此之外,它后面还紧跟着一个TTL值。 ping命令的背后是什么?这个TTL值又有什么意义?
ping 命令实际上发送了一段ICMP报文
ICMP全称控制报文协议(Internet Control Message Protocol)。它本质上只是TCP/IP协议簇的一个子协议。
一般只用来诊断网络问题、检测网络可达性还有报告错误条件,甚至Dos攻击背后也有它的身影。
ICMP 报文结构一段ICMP 消息,首先点明其类型,其后提供错误信息的代码,再计算用于验证消息完整性的校验和,最后是包含具体的控制信息或错误数据的消息体。
短、固定、开销极低。这是它后面所有故事的前提。
ICMP 类型类型上有 错误报告消息 和 查询消息 两大类,
错误报告消息:用来报告目标不可达或者超时等错误条件
查询消息:用于网络诊断,比如回显请求(Echo Request)和回显应答(Echo Reply)。
TTL:给转发次数设个上限在ping请求中,你的设备发出一个回显请求,目标设备收到后回一个回显应答,两个时间点一减,就得到 ...
TCP与UDP之分:可靠与轻便的抉择
前言想象一下,当你寄出一封信,如果不借助其他通信渠道,即使邮差弄丢了你的信,你也无从得知,这便是UDP的局限。为了确保消息的传达,如果一段时间后没有收到回信以确认,你就再次寄出,循环往复,直到对方给出答复,这便是tcp的哲学。
数据包在网络通信中,每份数据会被切成小块,每一块叫做一个数据包。
每个包都带着各自的发出方与接收方信息
包括
发送方的端口、接收方的端口、数据包总长、校验和、数据
负责搬运这些包的则是 IP 协议
但通信从来不保证顺利。包可能丢失、可能乱序、可能重复。
如果数据包在没能成功送达,发送方要如何知晓?
TCP 的选择:让接收方亲口确认每收到一份数据,接收方就回一句「收到了」。发送方等不到这句答复,就认定数据丢了,原样再发一次。
重发会不会导致重复?不会。每个包都带序号,接收方按序号把包重新拼起来:
丢的能发现,乱的能重排,重的能合并。
这就像两个人打电话,一句一句对账。你说收到,我再说下一句。
代价也很明显:每一次确认都要跑个来回,时间就耗在这上面。
TCP的三次握手正式对话开始前,双方要先对一次。客户端发起连接请求,服务端接住,客户端才开始发数据。这就是常说的 ...
中断回调用HAL_Delay延迟导致卡死
写按键驱动的时候封装了一层函数,接收按键枚举和监听事件函数指针,传递给外部中断回调统一处理,习惯性地在监听函数写了HAL_Delay(200),然后就坏菜了
编译下载,按下Confirm,程序卡死
重新回顾了一下NVIC与HAL_Delay的机制,才注意到
HAL_Delay依赖HAL_GetTick获取SysTick计数值来实现延时的时间判断,而HAL_GetTick的值又需要SysTick中断来更新。在优先级更高的中断的回调中调用HAL_Delay时,优先级相对较低的SysTick中断无法触发,uwTick的值得不到更新,HAL_Delay所比较的时间一直不动,便一直执行阻塞,造成cpu卡死。
删除中断中出现的HAL_Delay(),编译下载,正常运行。
C#初探:DI注入及其生命周期
在 C#.NET 中,依赖注入(Dependency Injection,简称 DI) 是一种设计模式,用于实现控制反转(Inversion of Control,IoC),以降低代码耦合、提高可测试性和可维护性。
简而言之,就是将对象实例的创建和依赖管理,托管给IoC容器,再通过注入将实例传递给需要的流程,实现代码的解耦Register 服务注册常用的四种注册方式
12345678// **1** 实现-接口 Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>()//**2** 实现 Add{LIFETIME}<{SERVICE},>()//**3** 对象 AddSingleton<{SERVICE}>(new {IMPLEMENTATION})//**4** 工厂模式 Add{LIFETIME}<{SERVICE} ...
STM32核心引脚与GPIO - STM32学习笔记
电源引脚VDDD=device,正电源电压
VSSS=series,公共接(数)地或负电源电压。
VDDA/VSSA相应,VDDA、VSSA则为模电中的方案,VSSA接入模拟地
VBAT在主电源断开时为 RTC(实时时钟)和备份寄存器供电。确保在主电源断开时,RTC 和备份寄存器的内容不会丢失。
没有外部电池:如果应用中没有使用外部电池,VBAT 必须连接到 VDD 引脚上。
没有外部电池且需要稳定供电:如果没有外部电池,VBAT 引脚必须和 100nF 的陶瓷电容一起连接到 VDD 电源上。
使用外部电池:当使用外部电池时,VBAT 引脚可以直接连接到电池上,以在主电源断开时为 RTC 和备份寄存器供电。
时针引脚OSC_IN/OSC_OUT (HSE:高速外部时钟,频率高)
OSC32_IN/OSC32_OUT (LSE:低速外部时钟,功耗低)
外部高速晶体振荡器(crystal oscillator)的输入和输出引脚。这些引脚用于连接外部晶体振荡器,以提供精确的时钟信号给单片机。
复位引脚NRST,在保存一定信息状态的情况下( ...
通过Air实现Go的热重载
花一周学了Go之后就上手写后端了,然而gin不带热重载,饱受ctrl+c ,go run 折磨,才发现了Air。
安装go install github.com/air-verse/air@latest
通过air -v获取版本成功,安装完成
生成配置文件air init
生成了.air.toml文件,可自己修改配置
启动执行air启动热重载
测试修改代码后立即自动build了一遍,即刻生效,不用一遍遍run了🙂
官方Github仓库
npm无法加载文件,在此系统上禁止运行脚本。
更新完node之后跑了下npm,发现整个npm命令都用不了了:
npm : 无法加载文件 D:\node\node_global\npm.ps1,因为在此系统上禁止运行脚本。
大概是系统策略限制?
运行:get-ExecutionPolicy
得到结果:*Restricted*,也就是当前策略禁止运行脚本。
改变策略:Set-ExecutionPolicy RemoteSigned
验证:Get-ExecutionPolicy
得到结果:RemoteSigned,更改生效
再次运行npm -v,正常返回版本号,问题解决
ES6异步编程笔记
计时器123setTimeout(()=>{ 代码块},等待时间)
无论等待时间多短,异步任务都不会阻塞接下来的代码执行,即使是0也会在同步任务执行完后再执行(宏任务,执行顺序在同步代码、微任务之后)
Promise本身是个类,实例化传入函数执行异步任务,成功执行调用resolve(),失败调用reject(),两个方法都可以接受传入各种参数来传递成功/失败信息
成功(即resolve()被执行)后会自动执行该Promise对象的then()回调,then()方法本身返回一个新Promise对象,可以接着往下then,失败则调用catch()回调。
除了resolve()和reject()外还有个finally(),无论成败都会在结束之后执行
Async
先声明要异步的函数,把传入耗时任务的Promise对象作为返回值(如果任务本身是异步任务(fetch、io等)就直接传入,否则要手动用setTimeout等调整队列)
用async修饰的函数简化后续操作,在async修饰的函数内使用await Promise对象来时async函数内余下任务等 ...
ES6核心特性速通笔记
碎碎念
高考完决定改学后端,经过一番纠结后最终选择了nodejs,凭借java基础和一点点js基础,过了几天文档和一些速通教程,通关ES6,以此笔记作结
模版字符串"a,"+var1 ⇔ `a,${var1}`
解构赋值1.数组中const [a,b,c]=[1,2,3]
等同于
1234const arr=[1,2,3]const a=arr[0]const b=arr[1]const c=arr[2]
便于操作组内某一元素
(补充:可以跳过不要的元素,变量名留空即可。如:*const [a, ,c]=[1,2,3]中a、c赋值了1、3而留空保留括号的的2没有被赋值到新的变量)
2.类中按顺序将内部属性赋值给左侧变量名,也可以用原属性名称:新名称的形式自定义名称或顺序
123456const {username,url:link} = { username: "Binarydev", url: "https://binarydev.top"}con ...
绕过前端登录修复qexo的cdn失效
想写文章的时候打开hexo的后台,发现样式炸了,登录也没反应,f12之后发现js在cdn上的资源无了😨
后台可以更换为其它cdn,但还是得先登录,绕进死胡同了
于是决定用post请求直接登录绕过前端,再去后台改
在html源码中找到登录按钮对应的事件
定位到submit方法
记下请求内容与url
控制台直接post之后被csrf拦下😓需要加在请求头上
最终js代码:
123456789101112131415const USERNAME = "用户名";const PASSWORD = "密码";// 获取CSRF tokenconst csrfToken = document.querySelector('input[name="csrfmiddlewaretoken"]').value;// 手动发起登录请求fetch("/api/auth/", { method: "POST", headers: { "C ...