joy涉及的源代码
p2f.cconfig.cosdetect.canon.cpkt_proc.cnfv9.cclassify.cradix_trie.chdr_dsc.cprocwatch.caddr_attr.caddr.cwht.cstr_match.cacsm.cexample.cupdater.cipfix.csalt.cparson.cfingerprint.cppi.cutils.cpayload.cproto_identify.cfp_tls.cextractor.cdhcp.cdns.chttp.ctls.cssh.cike.cjoy.c
主流程
mainfinish_initial_setupproto_identify_init // proto_identify.c// mode = offlineprocess_single_input_fileprocess_pcap_filejoy_libpcap_process_packet // joy_api.cprocess_packet // pkt_proc.cprocess_tcpprocess_udpprocess_icmpprocess_ip
proto_identify_init 会创建 tcp/udp 关键字字典树, 后缀用于检测上层协议.
process_packet 是报文处理的核心函数, 其中会对报文进行处理, 主要是解析协议层, 并调用上层协议的处理函数.
process_tcpflow_key_get_record // p2f.c, 查表获取流记录retrans_detectedflow_record_process_packet_length_and_time_ackproto_identify_tcp // proto_identify.c, 识别tcp上层协议, 只检测前两个payload>0的包search_keyword_dictupdate_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}
