ntopng源码编译也是可以自定义一下的。
但是因为是c++的,不太好看。
总览
大致流程是
make uninstall
- 修改源码
make
make install
分析源码,我觉得主要修改的函数是src/NetworkInterface.cpp
中的dissectPacket
函数,在注释那一段调用了processPacket
处理数据包,因此可以在这里添加对于数据包的处理。
bool NetworkInterface::dissectPacket(const struct pcap_pkthdr *h,
const u_char *packet, bool *shaped,
u_int16_t *ndpiProtocol) {
struct ndpi_ethhdr *ethernet, dummy_ethernet;
u_int64_t time;
static u_int64_t lasttime = 0;
u_int16_t eth_type, ip_offset, vlan_id = 0, eth_offset = 0;
u_int32_t null_type;
int pcap_datalink_type = get_datalink();
bool pass_verdict = true;
......
try {
pass_verdict = processPacket(&h->ts, time, ethernet, vlan_id, iph,
ip6, h->caplen - ip_offset, h->len,
h, packet, shaped, ndpiProtocol);
//*********************************** my code start ****************************************
ntop->getTrace()->traceEvent(TRACE_NORMAL, "-------------------- normal -----------------------");
//*********************************** my code end ****************************************
} catch(std::bad_alloc& ba) {
static bool oom_warning_sent = false;
if(!oom_warning_sent) {
ntop->getTrace()->traceEvent(TRACE_WARNING, "Not enough memory");
oom_warning_sent = true;
}
}
}
break;
......
purgeIdle(last_pkt_rcvd);
return(pass_verdict);
}
但是好像在processPacket
函数里处理会更方便一点
bool NetworkInterface::processPacket(const struct bpf_timeval *when,
const u_int64_t time,
struct ndpi_ethhdr *eth,
u_int16_t vlan_id,
struct ndpi_iphdr *iph,
struct ndpi_ipv6hdr *ip6,
u_int16_t ipsize,
u_int16_t rawsize,
const struct pcap_pkthdr *h,
const u_char *packet,
bool *shaped,
u_int16_t *ndpiProtocol) {
bool src2dst_direction;
u_int8_t l4_proto;
Flow *flow;
u_int8_t *eth_src = eth->h_source, *eth_dst = eth->h_dest;
IpAddress src_ip, dst_ip;
u_int16_t src_port = 0, dst_port = 0, payload_len = 0;
struct ndpi_tcphdr *tcph = NULL;
struct ndpi_udphdr *udph = NULL;
u_int16_t l4_packet_len;
u_int8_t *l4, tcp_flags = 0, *payload = NULL;
u_int8_t *ip;
bool is_fragment = false, new_flow;
bool pass_verdict = true;
int a_shaper_id = DEFAULT_SHAPER_ID, b_shaper_id = DEFAULT_SHAPER_ID; /* Default */
......
//*********************************** my code start ****************************************
ntop->getTrace()->traceEvent(TRACE_NORMAL, "");
//*********************************** my code end ****************************************
......
if(pass_verdict)
incStats(when->tv_sec, iph ? ETHERTYPE_IP : ETHERTYPE_IPV6,
flow->get_detected_protocol().protocol,
rawsize, 1, 24 /* 8 Preamble + 4 CRC + 12 IFG */);
bool dump_is_unknown = dump_unknown_traffic
&& (!flow->isDetectionCompleted() ||
flow->get_detected_protocol().protocol == NDPI_PROTOCOL_UNKNOWN);
if(dump_is_unknown
|| dump_all_traffic
|| dump_security_packets
|| flow->dumpFlowTraffic()) {
if(dump_to_disk) dumpPacketDisk(h, packet, dump_is_unknown ? UNKNOWN : GUI);
if(dump_to_tap) dumpPacketTap(h, packet, GUI);
}
} else
incStats(when->tv_sec, iph ? ETHERTYPE_IP : ETHERTYPE_IPV6,
flow->get_detected_protocol().protocol,
rawsize, 1, 24 /* 8 Preamble + 4 CRC + 12 IFG */);
return(pass_verdict);
}
细节
IpAddress Class
这里有结果结构体需要注意一下,比如现在的一个问题,是IpAddress
这个类,这么定义的
struct ipAddress {
u_int8_t ipVersion:3 /* Either 4 or 6 */,
localHost:1, privateIP:1, multicastIP:1, broadcastIP:1,
notUsed:1 /* Future use */;
union {
struct ndpi_in6_addr ipv6;
u_int32_t ipv4; /* Host byte code */
} ipType;
};
/* **************************************** */
class IpAddress {
private:
struct ipAddress addr;
u_int32_t ip_key;
char* intoa(char* buf, u_short bufLen, u_int8_t bitmask);
void checkIP();
void compute_key();
public:
IpAddress();
IpAddress(char *string);
IpAddress(IpAddress *ip);
IpAddress(u_int32_t _ipv4);
IpAddress(struct ndpi_in6_addr *_ipv6);
bool isEmpty();
inline void reset() { memset(&addr, 0, sizeof(addr)); }
inline bool isIPv4() { return((addr.ipVersion == 4) ? true : false); }
inline bool isIPv6() { return((addr.ipVersion == 6) ? true : false); }
inline void set_ipv4(u_int32_t _ipv4) { addr.ipVersion = 4, addr.ipType.ipv4 = _ipv4; compute_key(); }
inline void set_ipv6(struct ndpi_in6_addr *_ipv6) { addr.ipVersion = 6, memcpy(&addr.ipType.ipv6, _ipv6, sizeof(struct ndpi_in6_addr)); compute_key(); }
inline u_int32_t get_ipv4() { return((addr.ipVersion == 4) ? addr.ipType.ipv4 : 0); }
inline struct ndpi_in6_addr* get_ipv6() { return((addr.ipVersion == 6) ? &addr.ipType.ipv6 : NULL); }
inline struct ipAddress* getIP() { return(&addr); };
inline bool equal(u_int32_t ipv4_addr) { if((addr.ipVersion == 4) && (addr.ipType.ipv4 == ipv4_addr)) return(true); else return(false); };
inline bool equal(struct ndpi_in6_addr *ip6_addr) { if((addr.ipVersion == 6) && (memcmp(&addr.ipType.ipv6, ip6_addr, sizeof(struct ndpi_in6_addr)) == 0)) return(true); else return(false); };
inline bool equal(IpAddress *_ip) { return(this->compare(_ip) == 0); };
void set_from_string(char *string);
int compare(IpAddress *ip);
inline u_int32_t key() { return(ip_key); };
void set(IpAddress *ip);
inline bool isPrivateAddress() { return(addr.privateIP); };
inline bool isMulticastAddress() { return(addr.multicastIP); };
inline bool isBroadcastAddress() { return(addr.broadcastIP); };
char* print(char *str, u_int str_len, u_int8_t bitmask = 0);
bool isLocalHost(int16_t *network_id);
bool isLocalInterfaceAddress();
void deserialize(json_object *o);
char* serialize();
json_object* getJSONObject();
bool match(patricia_tree_t *ptree);
void* findAddress(patricia_tree_t *ptree);
};
这里主要看他的这个ipv4
,是私有变量,所以得通过公共函数get_ipv4()
调用。
然后可以看到这是一个u_int32_t
类型的,它的返回值就是一个整型,如果想输出的话得用%d
吧,我试了%d和%ld
,一个好一个不好。
看下面的输出示例,后面的整型是%d
前面的是%ld
,前面就明显感觉怪怪的。
01/Dec/2020 15:48:33 [NetworkInterface.cpp:871] get a udp packet from br-ex Network from 139639896830578(176):13568 to 1744939200(0):56034
01/Dec/2020 15:48:33 [NetworkInterface.cpp:871] get a udp packet from br-ex Network from 139639896830578(176):13568 to 1744939200(0):56034
01/Dec/2020 15:48:33 [NetworkInterface.cpp:871] get a udp packet from br-ex Network from 139639896830578(176):13568 to 1744939200(0):61578
01/Dec/2020 15:48:33 [NetworkInterface.cpp:871] get a udp packet from br-ex Network from 16885952(176):4 to -1(255):35091
01/Dec/2020 15:48:34 [NetworkInterface.cpp:871] get a udp packet from br-ex Network from 139639721666752(0):20699 to 1920103026(176):13568
01/Dec/2020 15:48:34 [NetworkInterface.cpp:871] get a udp packet from eno16777736 Network from 139639721666752(0):31193 to 1920103026(176):13568
然后针对这个输出1920103026
,试着把他转为IP地址。
先转为二进制1110010011100100111001001110010
,但是发现只有31位,试着在前面补一个0,然后分段,就是01110010 01110010 01110010 01110010
。
再转为十进制114.114.114.114
。
这就是这个整型对应的IP地址了。
倒序
再试一下,1744939200
,二进制为1101000000000011010100011000000
,只有31位,也得补0。然后分段一下01101000 00000001 10101000 11000000
,转为十进制是104.1.168.192
。
诶出现问题了,这个地址应该是192.168.1.104
吧,所以说明这个东西他是反的,应该倒序一下。