joy涉及的源代码
p2f.c
config.c
osdetect.c
anon.c
pkt_proc.c
nfv9.c
classify.c
radix_trie.c
hdr_dsc.c
procwatch.c
addr_attr.c
addr.c
wht.c
str_match.c
acsm.c
example.c
updater.c
ipfix.c
salt.c
parson.c
fingerprint.c
ppi.c
utils.c
payload.c
proto_identify.c
fp_tls.c
extractor.c
dhcp.c
dns.c
http.c
tls.c
ssh.c
ike.c
joy.c
主流程
main
finish_initial_setup
proto_identify_init // proto_identify.c
// mode = offline
process_single_input_file
process_pcap_file
joy_libpcap_process_packet // joy_api.c
process_packet // pkt_proc.c
process_tcp
process_udp
process_icmp
process_ip
proto_identify_init 会创建 tcp/udp 关键字字典树, 后缀用于检测上层协议.
process_packet 是报文处理的核心函数, 其中会对报文进行处理, 主要是解析协议层, 并调用上层协议的处理函数.
process_tcp
flow_key_get_record // p2f.c, 查表获取流记录
retrans_detected
flow_record_process_packet_length_and_time_ack
proto_identify_tcp // proto_identify.c, 识别tcp上层协议, 只检测前两个payload>0的包
search_keyword_dict
update_all_features // update header description
proto_identy_tcp 使用关键字识别来确定(某些)上层协议, 如果命中, 则返回对应的协议号和 client/server 方向.
/*
* Estimate the TCP application protocol
* Optimization: stop after first 2 packets that have non-zero payload
*/
if ((!record->app) && record->op <= 2) {
const struct pi_container *pi = proto_identify_tcp(payload, size_payload);
if (pi != NULL) {
record->app = pi->app;
record->dir = pi->dir;
}
}
update_all_features 这里用了一个宏定义技巧, 就是在多个 feature 上都调用 update_feature, 这里的 feature 就是协议插件, 比如 http, dns 等.
#define tcp_feature_list salt, ppi, fpx
#define payload_feature_list wht, example, dns, ssh, tls, dhcp, dhcpv6, http, ike, payload
#define feature_list payload_feature_list, tcp_feature_list
/** The macro update_feature(f) processes a single packet and updates
* the feature context
*/
#define update_feature(f) \
if (f##_filter(record) && (glb_config->report_##f)) { \
if (record->f == NULL) f##_init(&record->f); \
f##_update(record->f, header, payload, size_payload, glb_config->report_##f); \
}
/** The macro update_all_features(list) invokes update_feature() for each
* feature in list
*/
#define update_all_features(feature_list) MAP(update_feature, feature_list)
updaet_feature 也是个宏, 展开后, 先判断是否是当前协议/有没有开启协议插件, 如果是的话再调用相应协议的 update 函数, 比如 http 展开后:
if (http_filter(record) && (glb_config->report_http)) {
if (record->http == NULL)
http_init(&record->http);
http_update(record->http, header, payload, size_payload, glb_config->report_http);
}
其中 http 过滤条件 (http_filter) 是:
#define http_filter(record) \
((record->key.prot == 6) && \
(record->app == 80 || (record->key.sp == 80 || record->key.dp == 80)) \
)
而 http_update 会解析/处理 HTTP 报文.
协议处理
TCP
DNS
识别规则:
udp, server->client, {WILDCARD, WILDCARD, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00}
HTTP
识别规则:
- GET
tcp, client->server,{0x47, 0x45, 0x54, 0x20}
- POST
tcp, client->server,{0x50, 0x4f, 0x53, 0x54, 0x20}
- OPTIONS
tcp, client->server,{0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x20}
- HEAD
tcp, client->server,{0x48, 0x45, 0x41, 0x44, 0x20}
- PUT
tcp, client->server,{0x50, 0x55, 0x54, 0x20}
- DELETE
tcp, client->server,{0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x20}
- TRACE
tcp, client->server,{0x54, 0x52, 0x41, 0x43, 0x45, 0x20}
- CONNECT
tcp, client->server,{0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x20}
- HTTP 1.1
tcp, server->client,{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20}
TLS
识别规则:
- Client Hello 1.0
tcp, client->server,{0x16, 0x03, 0x01, WILDCARD, WILDCARD, 0x01}
- Server hello 1.0
tcp, server->client,{0x16, 0x03, 0x01, WILDCARD, WILDCARD, 0x02}
- Client Hello 1.1
tcp, client->server,{0x16, 0x03, 0x02, WILDCARD, WILDCARD, 0x01}
- Server hello 1.1
tcp, server->client,{0x16, 0x03, 0x02, WILDCARD, WILDCARD, 0x02}
- Client Hello 1.2
tcp, client->server,{0x16, 0x03, 0x03, WILDCARD, WILDCARD, 0x01}
- Server Hello 1.2
tcp, server->client,{0x16, 0x03, 0x03, WILDCARD, WILDCARD, 0x02}