软路由更新日志

最近发现clash(mihomo)核心的内存使用率有明显问题,用几天这玩意就能吃200M以上的内存了,再后面就不得不重启。 并且这个核心的DNS性能也存在部分问题,我不得不使用chinadns-ng来代替clash内部的dns. ...

2025年06月21日 · 4 分钟 · 1798 字 · sdttttt

又双叒叕来改造软路由

警告:这次纯粹是闲得慌🤣 这次改造的目标是原Openwrt更改为(伪)旁路由,主路由这次使用RouterOS系统。 国内国外分流会在RouterOS上执行一次,然后国内流量直接由RouterOS处理和发送,国外流量以及DNS请求会被标记网关会被重定向到Openwrt上. ...

2025年06月14日 · 4 分钟 · 1533 字 · sdttttt

第一个裸机程序

今天尝试写我的第一个裸机程序,虚拟机使用bochs,这个虚拟机配置很容易,也比较简单,非常新手。 1# bochs 配置文件 2 3# 设置Bochs 在运行过程中能够使用的内存,32MB 4megs: 32 5 6# BIOS和显示BIOS 7romimage: file=/home/admin123/Desktop/bochs/share/bochs/BIOS-bochs-latest 8vgaromimage: file=/home/admin123/Desktop/bochs/share/bochs/VGABIOS-lgpl-latest 9 10# 软盘,不用 11# floppya: 1_44=a.img, status=inserted 12 13# 使用硬盘 14# boot: floppy 15boot: disk 16 17# 日志文件的输出。 18log: bochs.out 19 20# 关闭鼠标 21mouse: enabled=0 22keyboard_mapping: enabled=1,map=/home/admin123/Desktop/bochs/share/bochs/keymaps/x11-pc-us.map 23 24# 硬盘设置 25ata0-master: type=disk, path="hd60M.img", mode=flat, cylinders=121, heads=16, spt=63 26ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 27 28# gdb的支持,1234 端口调试 29gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0 1[org 0x7c00] 2[bits 16] 3BOOT_MAIN_ADDR equ 0x500 4readdiskmsg db "ReadDisk...", 0 5 6global _start 7 8_start: 9 xor ax, ax 10 mov ds, ax 11 mov es, ax 12 mov ss, ax 13 mov fs, ax 14 mov sp, 0x7c00 15 16 mov ax, 3 17 int 0x10 18 19 mov ecx, 2 20 mov bl, 2 21 22 mov dx, 0x1f2 23 mov al, bl 24 out dx, al 25 26 inc dx 27 mov al, cl 28 out dx, al 29 30 inc dx 31 mov al, ch 32 out dx, al 33 34 inc dx 35 shr ecx, 16 36 mov al, cl 37 out dx, al 38 39 inc dx 40 mov al, ch 41 and al, 0b1110_1111 42 out dx, al 43 44 inc dx 45 mov al, 0x20 46 out dx, al 47 48 mov si, readdiskmsg 49 call print 50 51.hd_ready_check: 52 mov dx, 0x1f7 53 in al, dx 54 and al, 0b0000_1000 55 cmp al, 0b0000_1000 56 jnz .hd_ready_check 57 58 mov dx, 0x1f0 59 mov cx, 256 60 mov edi, BOOT_MAIN_ADDR 61 62.read_boot: 63 in ax, dx 64 mov [edi], ax 65 add edi, 2 66 loop .read_boot 67 68 jmp BOOT_MAIN_ADDR 69 70;; mov si, string 71;; call print 72print: 73 mov ah, 0x0e 74 mov bh, 0 75 mov bl, 0x01 76.print_loop: 77 mov al, [si] 78 cmp al, 0 79 jz .print_done 80 int 0x10 81 82 inc si 83 jmp .print_loop 84 85.print_done: 86 ret 87 88times 510 - ($ - $$) db 0 89db 0x55, 0xaa 汇编具体就不解释了,太累了。 ...

2025年05月20日 · 2 分钟 · 511 字 · sdttttt

硬盘LBA28读取以及BootLoader加载

⚠这篇文章比较无聊,因为涉及到一些硬件相关的东西,所以大部分的知识内容都很刻板,基本只能当作字典用。 之前讲了关于主引导扇区上的内容,这次就来讲讲BootLoader具体是怎么编写和加载系统的. 首先我们需要知道硬盘是如何工作的,以及它的结构。 ...

2025年05月16日 · 3 分钟 · 1332 字 · sdttttt

RSSHub的反代配置

为了方便做日志和限流,给RSSHub配个和好伙伴openresty(NGINX的一个支持lua的分支)写了一下反代的配置,只说一下自己写的功能吧: 请求头会说自己是SpringBoot应用,因为我最恶心的就是spring全家桶了。 请求会记录在rsshub代理等待了多久。 rsshub查询错误的话直接返回状态码,响应体直接放空,省点流量。 stat 给出一些简单的性能数据和热点IP 1http { 2 3 ## 4 # Basic Settings 5 ## 6 7 sendfile on; 8 tcp_nopush on; 9 tcp_nodelay on; 10 keepalive_timeout 65; 11 types_hash_max_size 2048; 12 server_tokens off; 13 14 # server_names_hash_bucket_size 64; 15 # server_name_in_redirect off; 16 17 include /etc/nginx/mime.types; 18 default_type application/octet-stream; 19 20 ## 21 # SSL Settings 22 ## 23 24 ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE 25 ssl_prefer_server_ciphers on; 26 27 ## 28 # Logging Settings 29 ## 30 31 access_log off; 32 error_log /var/log/nginx/error.log; 33 34 ## 35 # Gzip Settings 36 ## 37 38 gzip on; 39 40 gzip_vary on; 41 # gzip_proxied any; 42 gzip_comp_level 6; 43 # gzip_buffers 16 8k; 44 gzip_http_version 1.1; 45 gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; 46 gzip_min_length 1024; 47 48 ## 49 # Virtual Host Configs 50 ## 51 52 # include /etc/nginx/conf.d/*.conf; 53 # include /etc/nginx/sites-enabled/*; 54 55 lua_shared_dict rss_limit_req_store 10m; 56 57 init_by_lua_block { 58 package.path = "/etc/openresty/lua/?.lua;" .. package.path 59 } 60 61 upstream rsshub { 62 server 127.0.0.1:1222 max_fails=3 fail_timeout=30s; 63 keepalive 8; 64 } 65 66 server { 67 listen 1200; 68 listen [::]:1200; 69 server_name ""; 70 71 access_by_lua_block { 72 local rtime = require "rtime" 73 rtime.start() 74 } 75 76 header_filter_by_lua_block { 77 ngx.header["Server"] = "spring-boot" 78 79 local rtime = require "rtime" 80 local process_time = rtime.get_duration_ms() 81 ngx.header["x-wait-for"] = process_time 82 } 83 84 log_by_lua_block { 85 local log_path = "/var/log/nginx/access.log" 86 87 local now = os.date("%Y-%m-%d %H:%M:%S") 88 local method = ngx.var.request_method or "-" 89 local uri = ngx.var.request_uri or "-" 90 local rt_ms = tonumber(ngx.var.request_time) * 1000 91 if not rt_ms then rt_ms = 0 end 92 93 local srcip = ngx.var.remote_addr or "-" 94 local dstip = ngx.var.server_addr or "-" 95 local bytes = tonumber(ngx.var.body_bytes_sent) or 0 96 97 -- 获取 User-Agent 98 local ua = ngx.var.http_user_agent or "-" 99 100 -- 构造日志 101 local log_lines = { 102 string.format("%s [%s] %s %.1fms", now, method, uri, rt_ms), 103 string.format("[%s] <=> [%s] Byte: %d", srcip, dstip, bytes), 104 ua, 105 "" -- 空行分隔 106 } 107 108 -- 安全写入 109 local fp, err = io.open(log_path, "a") 110 if not fp then 111 ngx.log(ngx.ERR, "Failed to open log file: ", err) 112 return 113 end 114 115 for _, line in ipairs(log_lines) do 116 local ok, err = fp:write(line, "\n") 117 if not ok then 118 ngx.log(ngx.ERR, "Failed to write log line: ", err) 119 break 120 end 121 end 122 fp:close() 123 } 124 125 location = /stat { 126 stub_status; 127 access_log off; 128 129 access_by_lua_block { 130 local addr = ngx.var.remote_addr 131 132 if not addr:match("^10%.126%.126%.%d+$") then 133 ngx.log(ngx.ERR, "IP not allowed: ", addr, " for /stat, redirect to @fallback") 134 ngx.exit(503) 135 end 136 } 137 138 error_page 503 = @fallback; 139 } 140 141 location ~ /(telegram|twitter)/ { 142 access_by_lua_block { 143 ngx.exit(503) 144 } 145 146 error_page 503 = @fallback_gfw; 147 } 148 149 location / { 150 151 access_by_lua_block { 152 local rtime = require "rtime" 153 rtime.start() 154 155 local limit_req = require "resty.limit.req" 156 local lim, err = limit_req.new("rss_limit_req_store", 10, 20) 157 if not lim then 158 ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err) 159 ngx.exit(500) 160 end 161 162 local key = ngx.var.binary_remote_addr 163 local delay, err = lim:incoming(key, true) 164 165 if not delay then 166 if err == "rejected" then 167 ngx.log(ngx.WARN, "rate limited, key: ", key) 168 ngx.exit(429) 169 end 170 ngx.log(ngx.ERR, "failed to limit req: ", err) 171 ngx.exit(500) 172 end 173 174 if delay > 0 then 175 ngx.sleep(delay) 176 end 177 } 178 179 proxy_pass http://rsshub; 180 # 代理统一用HTTP1.1 181 proxy_http_version 1.1; 182 183 # 传递真实客户端信息 184 proxy_set_header Host $host; 185 proxy_set_header X-Real-IP $remote_addr; 186 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 187 proxy_set_header X-Forwarded-Proto $scheme; 188 # proxy_set_header X-Forwarded-Host $host; 189 proxy_set_header X-Forwarded-Port $server_port; 190 191 # 支持 WebSocket 192 proxy_set_header Upgrade $http_upgrade; 193 proxy_set_header Connection "upgrade"; 194 195 # 超时设置 196 proxy_connect_timeout 60s; 197 proxy_send_timeout 60s; 198 proxy_read_timeout 60s; 199 200 # 错误处理 201 proxy_next_upstream error timeout; 202 proxy_intercept_errors on; 203 error_page 503 = @fallback; 204 } 205 206 location ~* \.(jpg|jpeg|gif|ico|css|js|woff|woff2|ttf|svg|eot)$ { 207 expires 1d; 208 add_header Cache-Control "public, immutable"; 209 210 # 仍代理到后端(如果你的服务自己处理静态资源) 211 proxy_pass http://rsshub; 212 proxy_set_header Host $host; 213 proxy_set_header X-Real-IP $remote_addr; 214 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 215 proxy_set_header X-Forwarded-Proto $scheme; 216 217 proxy_http_version 1.1; 218 proxy_pass_request_headers on; 219 } 220 221 location ~* \.(png)$ { 222 empty_gif; 223 } 224 225 location @fallback { 226 internal; 227 content_by_lua_block { 228 ngx.status = 503 229 ngx.print() 230 ngx.exit(ngx.status) 231 } 232 } 233 234 location @fallback_gfw { 235 internal; 236 content_by_lua_block { 237 ngx.status = 503 238 ngx.header["Content-Type"] = "text/plain" 239 ngx.print("we cannot access GFW site.") 240 ngx.exit(ngx.status) 241 } 242 } 243 } 244 245} 1-- ip_cidr.lua 2 3local _M = {} 4 5local bit = require "bit" 6 7local internal_ipset = { 8 "10.0.0.0/8", 9 "172.16.0.0/12", 10 "192.168.0.0/16" 11} 12 13local function ip_to_num(ip) 14 -- 将 IPv4 字符串(如 "192.168.1.1")转换为 32 位整数 15 local parts = {} 16 for part in ip:gmatch("%d+") do -- 提取所有数字部分(如 "192", "168") 17 table.insert(parts, tonumber(part)) 18 end 19 20 if #parts ~= 4 then 21 return nil, "invalid IPv4 address: 不是有效的 IPv4 格式" 22 end 23 24 for _, p in ipairs(parts) do 25 if p < 0 or p > 255 then 26 return nil, "invalid IPv4 address: 八位组超出 0-255 范围" 27 end 28 end 29 30 -- 计算 32 位整数(大端序) 31 -- 傻瓜也能听懂的讲解:也算是帮我复习了 32 -- IP地址每个位最大255 也就是 FF = 1111 1111 33 -- 192.168.1.1 经过上面转成parts就是 [192, 168, 1 ,1] 34 -- 现在你要把这些数字转成一个整数,当然你可以直接乘10的倍数变成19216811 35 -- 但是这样子网掩码计算就比较复杂,并且乘法在计算机底层上算不上很高效率的指令 36 -- 所以这里用左移,上面说了每个位最大255也就是8个1 37 -- 那么最前面的192是从右数第4位那就移动 8 * 4 = 24 38 -- 以此类推,最后这个32位二进制数,8位的16进制数就是ip地址 39 local part1 = bit.lshift(parts[1], 24) -- 左移 24 位 40 local part2 = bit.lshift(parts[2], 16) -- 左移 16 位 41 local part3 = bit.lshift(parts[3], 8) -- 左移 8 位 42 local part4 = parts[4] -- 无需移位 43 return bit.bor(part1, part2, part3, part4), nil -- 按位或合并 44end 45 46function _M.match(target_ip, cidr) 47 48 if target_ip == nil or type(target_ip) ~= "string" or target_ip == "" then 49 return false, nil 50 end 51 52 local cidr_ip_str, prefix_str = cidr:match("^([^/]+)/(%d+)$") 53 if not cidr_ip_str or not prefix_str then 54 return false, "invalid CIDR format: 错误 = " .. cidr 55 end 56 57 local prefix = tonumber(prefix_str) 58 if prefix < 0 or prefix > 32 then 59 return false, "invalid prefix: 前缀长度需为 0-32 的整数" 60 end 61 62 -- 步骤 2:将 CIDR 中的 IP 转换为整数 63 local cidr_ip_num, err = ip_to_num(cidr_ip_str) 64 if not cidr_ip_num then 65 return false, "CIDR IP error: " .. err 66 end 67 68 -- 生成掩码位 69 -- 傻瓜也能听懂的讲解: 70 -- 打个比方,最常用的24,32 - 24 = 8 71 -- 0xFFFFFFFF << 8 = 0xFFFFFFF00 72 -- 然后去掉高位,转回32位(这个是16进制,1位当4位算) 73 -- 0xFFFFFF00 按照子网掩码转成可读的方式 74 -- FF FF FF 00 = 255 255 255 0 75 -- 如果这还听不懂,那只能是根本不知道进制之间的转换是怎么算的 76 77 local mask = 0 78 79 if prefix ~= 0 then 80 mask = bit.lshift(0xFFFFFFFF, 32 - prefix) 81 mask = bit.band(mask, 0xFFFFFFFF) 82 end 83 84 -- 网段 85 local cidr_network = bit.band(cidr_ip_num, mask) 86 87 local target_ip_num, err = ip_to_num(target_ip) 88 89 if not target_ip_num then 90 return false, "Target IP error: " .. err 91 end 92 93 local target_ip_cidr = bit.band(target_ip_num, mask) 94 95 print(target_ip_cidr) 96 print(cidr_network) 97 print(mask) 98 99 return target_ip_cidr == cidr_network, nil 100end 101 102function _M.is_internal(target_ip) 103 104 for _, t in ipairs(internal_ipset) do 105 local ok, err = _M.match(target_ip, t) 106 if ok and err == nil then return ok, err end 107 end 108 109 return false, nil 110end 111 112return _M 1-- ngx_log.lua 2local _M = {} 3 4local cjson = require "cjson" 5 6function _M.req_info() 7 local log_path = "/var/log/nginx/access.log" 8 9 local now = os.date("%Y-%m-%d %H:%M:%S") 10 local method = ngx.var.request_method or "-" 11 local uri = ngx.var.request_uri or "-" 12 local rt_ms = tonumber(ngx.var.request_time) * 1000 13 if not rt_ms then rt_ms = 0 end 14 15 local srcip = ngx.var.remote_addr or "-" 16 local dstip = ngx.var.server_addr or "-" 17 local bytes = tonumber(ngx.var.body_bytes_sent) or 0 18 19 -- 获取 User-Agent 20 local ua = ngx.var.http_user_agent or "-" 21 22 -- 构造日志 23 local log_lines = { 24 string.format("%s [%s] %s %.1fms", now, method, uri, rt_ms), 25 string.format("[%s] <=> [%s] Byte: %d", srcip, dstip, bytes), 26 ua, 27 "" -- 空行分隔 28 } 29 30 -- 安全写入 31 local fp, err = io.open(log_path, "a") 32 if not fp then 33 ngx.log(ngx.ERR, "Failed to open log file: ", err) 34 return 35 end 36 37 local ok, err = pcall(function() 38 for _, line in ipairs(log_lines) do 39 local ok, err = fp:write(line, "\n") 40 if not ok then 41 ngx.log(ngx.ERR, "Failed to write log line: ", err) 42 break 43 end 44 end 45 end) 46 47 fp:close() 48 if not ok then ngx.log(ngx.ERR, "Logging error: ", err) end 49end 50 51return _M 1-- ngx_log.lua 2 3local _M = {} 4 5function _M.start() 6 ngx.ctx.start_time = ngx.now() 7end 8 9function _M.get_duration_ms() 10 local start = ngx.ctx.start_time 11 if not start then return 0 end 12 return string.format("%.1fms", (ngx.now() - start) * 1000) 13end 14 15return _M

2025年05月15日 · 5 分钟 · 2178 字 · sdttttt

BIOS最初的引导

由于操作系统本身时存放在硬盘中,并非能在bios引导后直接在内存中运行,所以才有了BIOS引导操作系统的这个步骤。 在主板上电之后,BIOS需要去找到引导程序的位置,这个位置固定在(0磁头0柱面1扇区)的位置,这个扇区也被称为主引导扇区(MBR)。一个扇区大小固定为512字节。也就是boot_loader的大小也必须在512字节以内。 ...

2025年05月14日 · 2 分钟 · 519 字 · sdttttt

通过函数指针来运行汇编(机器码)

之前已经知道了函数这个玩意在计算机中的本质,本身在栈中存放其实就是一个指针的方式,而指针指向的内容就是在内存中存放的机器码。 解释到这里就已经很明显了,函数其实并不是一定要在编译期载入内存后静态,也就是固定的方式运行的。 ...

2025年05月07日 · 1 分钟 · 410 字 · sdttttt

尝试写一个字符串拷贝

1#include <stdio.h> 2#include <stdlib.h> 3 4extern int strlen2(char* str); 5extern void memscp2(char* dest, char* src,unsigned int size); 6extern void memscp3(char* dest, char* src,unsigned int size); 7 8int main() 9{ 10 int a = add(1, 2); 11 printf("%d\n", a); 12 printf("%d\n", strlen2("awd434")); 13 14 char* s = calloc(sizeof(char), 10); 15 memscp2(s, "awdawdawdfawffawf", strlen2("awdawdawdfawffawf")); 16 printf("%s\n", s); 17 18 char* ss = calloc(sizeof(char), 10); 19 memscp3(ss, "awdawdawdfawffawf", strlen2("awdawdawdfawffawf")); 20 printf("%s\n", s); 21 22 return 0; 23} 1SECTION .data 2 3SECTION .text 4 global memscp2 5 global memscp3 6 7; void memscp2(char* dest /* rdi */ , char* src /* rsi */,unsigned int size /* rdx */) 8memscp2: 9 mov rcx, rdx 10 cld 11 rep movsb 12 ret 13 14; void memscp3(char* dest /* rdi */ , char* src /* rsi */,unsigned int size /* rdx */) 15memscp3: 16 mov rcx, rdx 17nextbyte: 18 mov rax, [rsi] 19 mov [rdi], rax 20 add rsi, 8 21 add rdi, 8 22 loop nextbyte 23 xor rax, rax 24 ret 写了两个版本,上面的是movsb,一个专门用来拷贝字符的指令,估计是有特殊优化。 ...

2025年05月06日 · 1 分钟 · 225 字 · sdttttt

C中的指针运算,类型转换以及函数指针

这次依然是从汇编开始分析C语言里的一些语法实现,这次还是Windows平台上为主~ 直接上最简单的: 1int z = 0; 2char s1 = (char)z; 3 4// ASM 5int* z = 0; 6// 这次就直接显示符号名吧,不看内存地址了 7// dword ptr就是数据类型声明 8mov dword ptr [z],0 9char* s1 = (char*)z; 10// movzx这个指令,下面讲解,总之就是把z移动到eax寄存器. 11movzx eax,byte ptr [z] 12// 直接粗暴的进行一个强转,al是AX的第八位,AX是EAX的低16位 13// mov指令要求操作数大小相等,byte ptr只占8个字节,所以这里用AL寄存器 14mov byte ptr [s1],al movzx这个指令简单来说就是把小字节操作数移动到大字节寄存器,同时让大字节的高位补零。 ...

2025年05月04日 · 2 分钟 · 995 字 · sdttttt

尝试写一个strlen

1#include <stdio.h> 2 3extern int strlen2(char *str); 4 5int main() { 6 char a[] = "hello,world"; 7 int len = strlen2(a); 8 9 printf("%s len:%d \n", a, len); 10 11 return 0; 12} 1SECTION .data 2 3SECTION .text 4 global strlen2 5 6strlen2: 7 mov rax, rdi 8next: 9 cmp byte [rax], 0 10 je down 11 inc rax 12 jmp next 13down: 14 sub rax, rdi 15 ret

2025年04月25日 · 1 分钟 · 69 字 · sdttttt