靖安科技 (一面)
面试
用户鉴权 用的什么进行鉴权?鉴权方式是什么?证书鉴权的方式是什么?
- 两段式鉴权
业务登录鉴权:发生于
SDK与 管理平台 之间SDK用 用户名/密码 +optional TOTP调SDKAuth,用于确认 “这个人是不是合法用户”。SDK登录成功后,平台会下发ca/cert/key/server[],客户端再用这些材料去建立OpenVPN实例去建立连接。
VPN接入鉴权:发生于OpenVPN插件与 管理平台 之间- 到了服务端,插件在
TLS_VERIFY阶段取客户端证书的 **序列号SN和CN**,再调用同步RPC方法CertStatus查询这个证书当前是不是有效、属于哪个实体、对应哪个用户。
- 到了服务端,插件在
- 所以插件做的主鉴权不是用户名/密码,而是:
mTLS握手- 远端证书状态校验。
- 两段式鉴权
证书里面的内容是什么?基于什么的呢?
- 这套系统底层是基于
X.509证书 +PKI/CA体系 的OpenVPN双向TLS。 - 插件实际会读取证书里的
CN和SN X.509证书主要包含:Subject(主体)Issuer(签发者)Serial Number(序列号)Validity(有效期)Public Key(公钥)
- 这套系统底层是基于
你讲一下 策略拉取 具体由那些策略?
- 本质上是用户访问控制策略,主要包括:
- 拒绝策略
refusePolicy - 路由规则
routeRule - 限制速率
rateLimit - 时间窗
hourFrom/hourTo
- 拒绝策略
- 本质上是用户访问控制策略,主要包括:
网络访问策略还是路由策略?
- 插件拉取的是 网络访问策略,插件拿到策略后,是用
nftables做:- 允许哪些目的网段;
- 允许哪些
TCP/UDP端口; - 允许哪些
ICMP类型; - 超过速率怎么处理;
- 到期后怎么拒绝;
- 插件拉取的是 网络访问策略,插件拿到策略后,是用
路由策略没有进行管理嘛?
- 有路由管理,但不在插件这一层。
- 路由配置 是在托管节点生成
OpenVPN服务端通过配置进行管理的。- 插件负责用户访问控制;
OpenVPN服务配置负责路由下发;
实现方式是什么?
- 插件先拉用户策略,再把策略编译成
nftables规则下发到Linux内核。 - 大致流程:
- 客户端证书校验通过后,插件识别出
userId; - 异步调用
UserAccessRules(userId); - 等
OpenVPN在LEARN_ADDRESS事件拿到这个用户的虚拟IP; - 把
UserAccessRules转成vpn_access_rules; - 调
nft_adaptor.add_vpn_user_filter; - 为这个用户建立独立规则链;
- 客户端证书校验通过后,插件识别出
- 插件先拉用户策略,再把策略编译成
libnft的实现原理知道吗?- 用户态先构造规则;
libnftables解析/编译规则;- 通过
netlink把规则发给内核里的nf_tables; - 内核在
Netfilterhook点上执行这些规则;
现在我搭建了一个
openvpn服务器,它是在互联网上的,现在用户A和用户B,他们如何通过openvpn将他们组建成一个虚拟局域网里呢?让A和B之间可以进行点对点通信?- 官方手册明确说,
client-to-client会让openVPN服务端可以在内部路由客户端之间的流量; - 否则客户端通常只能“看见服务器”;
- 官方手册明确说,
流量解析 是如何做的呢?
OpenVPN启动完成后,插件在OPENVPN_PLUGIN_ROUTE_UP事件里取到设备名dev;tcap用PcapPlusPlus在这个网卡上做live capture;- 把原始包解析成 多层协议对象;
- 解析到哪一层由配置
parseUntil决定; - 当前支持解析的内容包括:
Ethernet、IPv4/IPv6、TCP/UDP、ICMP等等; - 插件再根据
src/dst VIP去本地在线用户表里补齐vpn_user字段; - 最后把整条记录序列化成
JSON发到Kafka;
日志投递 具体指的是什么?
- 服务日志:
OpenVPN服务端本身的运行日志、错误日志; - 流量审计日志: 插件抓包解析后生成的
JSON事件;
- 服务日志:
为什么选择
kafka做日志投递?- 解耦: 避免插件直接依赖某个日志平台的写入接口;
- 削峰缓冲:
VPN流量是突发的,Kafka更适合扛 burst,避免反压直接打到接入链路。 - 多消费者复用: 安全、审计、运维、风控都可以各自消费同一份数据。
- 可回放: 出现安全事件时可以重放历史流量事件做追查。
kafka顺序写入以及多Broker的情况,kafka会进行多分批发送,kafka怎么保证顺序呢?Kafka只保证 “单个partition内” 的顺序,不保证跨partition的全局顺序。- 同一个
topic下的partition,事件会按写入顺序追加,消费者也按这个顺序读取。
kafka分区你通常设置成多少个呢?- 不太了解,通常托管节点下发给插件的配置
介绍一下基于
N:M线程模型的高性能服务器框架?讲解一下线程池如何调度协程任务的嘛?
线程和协程的区别是什么?优劣是什么?
如果只用多线程做协程调度器,它为什么就没有因为上下文造成的影响呢?
你没有解释如何抵消线程进行切换造成的影响?
- 控制住线程数: 线程数不要跟连接数走;
8核机器开8~16个线程通常就够了,不是1000个连接就开1000个线程,线程一少,线程切换总量自然就下来了。 - 切换尽量发生在线程内部: 线程切换很贵,协程切换便宜。
- 少做线程切换
- 多做协程切换
- 减少线程阻塞和唤醒: 线程最怕因为阻塞频繁的被唤醒,这个过程会不断触发内核调度
- 线程没事就睡在
epoll_wait; - 真有
IO事件来了再醒; - 一个线程醒来后能连续处理多个
ready协程;
- 线程没事就睡在
- 减少跨线程迁移:
- 控制住线程数: 线程数不要跟连接数走;
现在有 1000 个连接需要你去处理,你现在用线程调度器去都调度你的协程,平均你每个线程需要你去调度多少个协程呢?要启动多少个线程呢?
现在我再具体一点,现在我有 1000 个协程任务,你现在要协调都多少个线程来协调多少个协程来达到最高的效率呢?
你怎么知道调度那些协程到那些线程呢?
多线程/多协程的场景下,如果你的程序异常崩溃了,你去怎么排查?
- 通过线程
id/协程id,找到崩溃的线程; - 通过
gdb调试崩溃程序; - 查看所有线程的调用栈;
- 查看当前线程在跑哪个协程;
- 通过线程
gdb怎么找到死锁的原因?- 通过
p mutex查看哪个线程拥有这把锁;
- 通过
怎么看出来 内存泄漏?
Valgrind:valgrind --leak-check=full ./server
内存非法访问怎么查看的?
- 类型
- 野指针;
- 空指针;
- 选空指针;
- 越界读写;
- 通过
gdb进行调试;+
- 类型
死在代码行上但是你看不出来?
有什么情况,调用成员函数会直接使得程序崩溃?
可插拔中间件机制是什么?
反问:没能很好的表达你在项目中的细节,你在这个项目能做到多深?
