--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stc-plugin-pcap.h"
+
+//LCOV_EXCL_START
+static GHashTable *g_pcap_tables = NULL;
+static bool g_pcap_start_fm = false;
+static struct timeval g_pcap_tv = { 0, };
+
+static void __pcap_data_free(gpointer value)
+{
+ stc_pcap_data_s *data = (stc_pcap_data_s *)value;
+
+ g_thread_unref(data->thread);
+
+ FREE(data->name);
+ FREE(data);
+}
+
+/*
+static void __pcap_data_info(const u_char *packet, int len)
+{
+ GString *data;
+
+ data = g_string_sized_new(len);
+ if (data == NULL)
+ return;
+
+ while(len--)
+ g_string_append_printf(data, "%02x", *(packet++));
+
+ STC_LOGD("[%s]", g_string_free(data, FALSE));
+}
+*/
+
+static void __pcap_ntp_time_info(uint32_t s, char *time)
+{
+ time_t seconds;
+ char *curr = NULL;
+ int len = 0;
+ uint32_t sec = ntohl(s);
+
+ if (sec) {
+ seconds = sec - NTP_JAN_1970;
+ curr = ctime(&seconds);
+ len = strlen(curr);
+ curr[len - 1] = '\0';
+
+ snprintf(time, len, "%s", curr);
+ } else {
+ snprintf(time, 10, "00:00:00");
+ }
+}
+
+static void __pcap_ntp_refid_info(ntp_t *ntp_h, char *refid)
+{
+ switch (ntp_h->stratum) {
+ case NTP_STRATUM_UNSPECIFIED:
+ snprintf(refid, BUFF_SIZE_ID, "%s", "(unspec)");
+ break;
+ case NTP_STRATUM_PRIM_REF:
+ snprintf(refid, BUFF_SIZE_ID, "%s", "(prim_ref)");
+ break;
+ case NTP_STRATUM_INFO_QUERY:
+ snprintf(refid, BUFF_SIZE_ID, "%s INFO_QEURY",
+ inet_ntoa(*((struct in_addr *)&ntp_h->refid)));
+ break;
+ case NTP_STRATUM_INFO_REPLY:
+ snprintf(refid, BUFF_SIZE_ID, "%s INFO_REPLY",
+ inet_ntoa(*((struct in_addr *)&ntp_h->refid)));
+ break;
+ default:
+ snprintf(refid, BUFF_SIZE_ID, "%s",
+ inet_ntoa(*((struct in_addr *)&ntp_h->refid)));
+ break;
+ }
+}
+
+static uint16_t __pcap_ntp_fraction_info(uint16_t f)
+{
+ uint16_t fraction;
+ double ff;
+
+ ff = ntohs(f) / 65536.0;
+ fraction = (uint16_t)(ff * 1000000.0);
+
+ return fraction;
+}
+
+static void __pcap_ntp_info(const u_char *packet)
+{
+ ntp_t *ntp_h = (ntp_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_IP_HEADER + SIZE_UDP_HEADER);
+ char refid[BUFF_SIZE_ID];
+ char reftime[BUFF_SIZE_TIME];
+ char orgtime[BUFF_SIZE_TIME];
+ char rectime[BUFF_SIZE_TIME];
+ char xmttime[BUFF_SIZE_TIME];
+
+ __pcap_ntp_refid_info(ntp_h, refid);
+ __pcap_ntp_time_info(ntp_h->reftime.second, reftime);
+ __pcap_ntp_time_info(ntp_h->orgtime.second, orgtime);
+ __pcap_ntp_time_info(ntp_h->rectime.second, rectime);
+ __pcap_ntp_time_info(ntp_h->xmttime.second, xmttime);
+
+ STC_LOGD("Flags[0x%02x] Stratum[%u] Poll[%u:%us] Precision[%u] "
+ "Root delay[%u.%06us] Root dispersion[%u.%06us] Ref ID[%s]",
+ ntp_h->flags, ntp_h->stratum, ntp_h->poll,
+ ntp_h->precision, 1 << ntp_h->precision,
+ ntohs(ntp_h->rootdelay.second),
+ __pcap_ntp_fraction_info(ntp_h->rootdelay.fraction),
+ ntohs(ntp_h->rootdisp.second),
+ __pcap_ntp_fraction_info(ntp_h->rootdisp.fraction),
+ refid);
+
+ STC_LOGD("Reference[%s] Origin[%s] Receive[%s] Transmit[%s]",
+ reftime, orgtime, rectime, xmttime);
+}
+
+static const char *__pcap_dhcp_client_id_info(uint8_t data)
+{
+ char *info = NULL;
+
+ switch (data) {
+ case DHCP_CLIENT_ID_ETHERNET:
+ info = "Ethernet";
+ break;
+ case DHCP_CLIENT_ID_IEEE802:
+ info = "IEEE 802 Networks";
+ break;
+ case DHCP_CLIENT_ID_ARCNET:
+ info = "ARCNET";
+ break;
+ case DHCP_CLIENT_ID_LOCALTALK:
+ info = "LocalTalk";
+ break;
+ case DHCP_CLIENT_ID_LOCALNET:
+ info = "LocalNet";
+ break;
+ case DHCP_CLIENT_ID_SMDS:
+ info = "SMDS";
+ break;
+ case DHCP_CLIENT_ID_FRAMERELAY:
+ info = "Frame Relay";
+ break;
+ case DHCP_CLIENT_ID_ATM1:
+ info = "ATM(Async Transfer Mode)";
+ break;
+ case DHCP_CLIENT_ID_HDLC:
+ info = "HDLC";
+ break;
+ case DHCP_CLIENT_ID_FIBRECHANNEL:
+ info = "Fibre Channel";
+ break;
+ case DHCP_CLIENT_ID_ATM2:
+ info = "ATM(Async Transfer Mode)";
+ break;
+ case DHCP_CLIENT_ID_SERIALLINE:
+ info = "Serial Line";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static const char *__pcap_dhcp_msg_type_info(uint8_t type)
+{
+ char *info = NULL;
+
+ switch (type) {
+ case DHCP_MSG_TYPE_DISCOVER:
+ info = "Discover";
+ break;
+ case DHCP_MSG_TYPE_OFFER:
+ info = "Offer";
+ break;
+ case DHCP_MSG_TYPE_REQUEST:
+ info = "Request";
+ break;
+ case DHCP_MSG_TYPE_DECLINE:
+ info = "Decline";
+ break;
+ case DHCP_MSG_TYPE_ACK:
+ info = "ACK";
+ break;
+ case DHCP_MSG_TYPE_NAK:
+ info = "NAK";
+ break;
+ case DHCP_MSG_TYPE_RELEASE:
+ info = "Release";
+ break;
+ case DHCP_MSG_TYPE_INFORM:
+ info = "Inform";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static void __pcap_bootp_magic_info(uint32_t magic,
+ uint8_t *moption, u_int16_t len)
+{
+ if (ntohl(magic) == BOOTP_MAGIC_DHCP) {
+ char buf[BOOTP_MOPTION_LEN];
+ uint8_t *opt = moption;
+
+ STC_LOGD("Magic cookie[DHCP]");
+
+ while(len > 0) {
+ uint8_t tag = opt[0];
+ uint8_t length = opt[1];
+ uint8_t *data = &opt[2];
+ char addr[BUFF_SIZE_IP];
+ char host[BUFF_SIZE_HOST];
+
+ switch (tag) {
+ case DHCP_TAG_SUBNET_MASK:
+ inet_ntop(AF_INET, (struct in_addr *)data,
+ addr, BUFF_SIZE_IP);
+ STC_LOGD("Subnet mask[%s]", addr);
+ break;
+ case DHCP_TAG_ROUTER:
+ inet_ntop(AF_INET, (struct in_addr *)data,
+ addr, BUFF_SIZE_IP);
+ STC_LOGD("Router[%s]", addr);
+ break;
+ case DHCP_TAG_DNS:
+ inet_ntop(AF_INET, (struct in_addr *)data,
+ addr, BUFF_SIZE_IP);
+ STC_LOGD("Domain name server[%s]", addr);
+ break;
+ case DHCP_TAG_HOST_NAME:
+ snprintf(buf, ((length < BOOTP_MOPTION_LEN) ?
+ (length + 1) : BOOTP_MOPTION_LEN), "%s", (char *)data);
+ STC_LOGD("Host name[%s]", buf);
+ break;
+ case DHCP_TAG_REQUESTED_IP:
+ inet_ntop(AF_INET, (struct in_addr *)data,
+ addr, BUFF_SIZE_IP);
+ STC_LOGD("Requested IP[%s]", addr);
+ break;
+ case DHCP_TAG_IP_LEASE_TIME:
+ STC_LOGD("IP address lease time[%us]",
+ ntohl(*(uint32_t *)data));
+ break;
+ case DHCP_TAG_MSG_TYPE:
+ STC_LOGD("DHCP message type[%u:%s]", *data,
+ __pcap_dhcp_msg_type_info(*data));
+ break;
+ case DHCP_TAG_SERVER_ID:
+ inet_ntop(AF_INET, (struct in_addr *)data,
+ addr, BUFF_SIZE_IP);
+ STC_LOGD("DHCP server identifier[%s]", addr);
+ break;
+ case DHCP_TAG_MSG_SIZE:
+ STC_LOGD("Maximum DHCP message size[%u]",
+ ntohs(*(uint16_t *)data));
+ break;
+ case DHCP_TAG_CLIENT_ID:
+ STC_LOGD("Client identifier HW type[0x%02x:%s]", *data,
+ __pcap_dhcp_client_id_info(*data));
+ if (*data == DHCP_CLIENT_ID_ETHERNET) {
+ g_strlcpy(host,
+ ether_ntoa((const struct ether_addr *)&data[1]),
+ sizeof(host));
+ STC_LOGD("Client identifier MAC[%s]", host);
+ }
+ break;
+ case DHCP_TAG_END:
+ STC_LOGD("End");
+ return;
+ default:
+ STC_LOGD("Unknown[%u]", tag);
+ break;
+ }
+
+ opt += (2 + length);
+ len -= (2 + length);
+ }
+ }
+}
+
+static const char *__pcap_bootp_op_info(uint8_t op)
+{
+ char *info = NULL;
+
+ switch (op) {
+ case BOOTP_REQUEST:
+ info = "Request";
+ break;
+ case BOOTP_REPLY:
+ info = "Reply";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static void __pcap_bootp_info(const u_char *packet)
+{
+ udp_t *udp_h = (udp_t *)(packet
+ + SIZE_ETHER_HEADER + SIZE_IP_HEADER);
+ bootp_t *bootp_h = (bootp_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_IP_HEADER + SIZE_UDP_HEADER);
+ char ciaddr[BUFF_SIZE_IP];
+ char yiaddr[BUFF_SIZE_IP];
+ char siaddr[BUFF_SIZE_IP];
+ char giaddr[BUFF_SIZE_IP];
+ char chaddr[BUFF_SIZE_HOST];
+ u_int16_t len;
+
+ inet_ntop(AF_INET, &bootp_h->ciaddr, ciaddr, BUFF_SIZE_IP);
+ inet_ntop(AF_INET, &bootp_h->yiaddr, yiaddr, BUFF_SIZE_IP);
+ inet_ntop(AF_INET, &bootp_h->siaddr, siaddr, BUFF_SIZE_IP);
+ inet_ntop(AF_INET, &bootp_h->giaddr, giaddr, BUFF_SIZE_IP);
+
+ g_strlcpy(chaddr,
+ ether_ntoa((const struct ether_addr *)bootp_h->chaddr),
+ sizeof(chaddr));
+
+ STC_LOGD("Message type[%u:%s] HW type[0x%02x] HW len[%u] Hops[%u] "
+ "Transaction ID[0x%08x] Seconds elapsed[%u] Flags[0x%04x]",
+ bootp_h->op, __pcap_bootp_op_info(bootp_h->op),
+ bootp_h->htype, bootp_h->hlen, bootp_h->hops,
+ ntohl(bootp_h->xid), ntohs(bootp_h->secs), ntohs(bootp_h->flags));
+
+ STC_LOGD("Client[%s] Your(client)[%s] Next server[%s] "
+ "Relay agent[%s] Client MAC[%s]",
+ ciaddr, yiaddr, siaddr, giaddr, chaddr);
+
+ len = ntohs(udp_h->len);
+ __pcap_bootp_magic_info(bootp_h->magic, bootp_h->moption, len);
+}
+
+static char *__pcap_dns_type_info(uint16_t type)
+{
+ char *info = NULL;
+
+ switch (type) {
+ case DNS_QTYPE_A:
+ info = "A";
+ break;
+ case DNS_QTYPE_CNAME:
+ info = "CNAME";
+ break;
+ case DNS_QTYPE_AAAA:
+ info = "AAAA";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static char *__pcap_dns_class_info(uint16_t class)
+{
+ char *info = NULL;
+
+ switch (class) {
+ case DNS_QCLASS_IN:
+ info = "IN";
+ break;
+ case DNS_QCLASS_CHAOS:
+ info = "CHAOS";
+ break;
+ case DNS_QCLASS_HS:
+ info = "HS";
+ break;
+ case DNS_QCLASS_ANY:
+ info = "ANY";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static uint8_t * __pcap_dns_name_info(uint8_t *dns_h,
+ uint8_t *data, u_char *name)
+{
+ uint8_t *sec = data;
+ u_char *dname = name;
+ uint8_t *nxt = NULL;
+
+ *name = '\0';
+ while (1) {
+ if ((*sec & 0xC0)) {
+ nxt = sec + 2;
+ sec = (uint8_t *)dns_h +
+ (htons(*(uint16_t *)sec) & 0x3FFF);
+ } else {
+ if (*sec == 0) {
+ *dname = '\0';
+ sec += 1;
+ break;
+ }
+
+ if (dname - name + *sec + 1 > BUFF_SIZE_NAME - 1) {
+ *name = '\0';
+ return NULL;
+ }
+
+ memcpy(dname, sec + 1, *sec);
+ dname += *sec;
+ sec += *sec + 1;
+ *dname = '.';
+ dname++;
+ }
+ }
+
+ *(--dname) = '\0';
+
+ if (nxt == NULL)
+ nxt = sec;
+
+ return (uint8_t *)nxt;
+}
+
+static void __pcap_dns_data_info(const u_char *packet)
+{
+ dns_t *dns_h = (dns_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_IP_HEADER +
+ SIZE_UDP_HEADER);
+ uint8_t *data = (uint8_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_IP_HEADER +
+ SIZE_UDP_HEADER + SIZE_DNS_HEADER);
+ uint16_t qdcount = ntohs(dns_h->questions);
+ uint16_t ancount = ntohs(dns_h->answerRR);
+ int i = 0;
+
+ for (i = 0; i < qdcount; ++i) {
+ u_char name[BUFF_SIZE_NAME];
+ uint16_t type;
+ uint16_t class;
+
+ if (i == 0)
+ STC_LOGD("[Queries]");
+
+ data = __pcap_dns_name_info((uint8_t *)dns_h, data, name);
+ if (data == NULL)
+ return;
+
+ type = ntohs(*(uint16_t *)&data[0]);
+ class = ntohs(*(uint16_t *)&data[2]);
+
+ STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s]",
+ name, type, __pcap_dns_type_info(type),
+ class, __pcap_dns_class_info(class));
+
+ data += 4;
+ }
+
+ for (i = 0; i < ancount; ++i) {
+ u_char name[BUFF_SIZE_NAME];
+ u_char cname[BUFF_SIZE_NAME];
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t length;
+ char ip[BUFF_SIZE_IP];
+
+ if (i == 0)
+ STC_LOGD("[Answers]");
+
+ data = __pcap_dns_name_info((uint8_t *)dns_h, data, name);
+ if (data == NULL)
+ return;
+
+ type = ntohs(*(uint16_t *)&data[0]);
+ class = ntohs(*(uint16_t *)&data[2]);
+ ttl = ntohl(*(uint32_t *)&data[4]);
+ length = ntohs(*(uint16_t *)&data[8]);
+
+ if (class == DNS_QCLASS_IN) {
+ switch (type) {
+ case DNS_QTYPE_A:
+ inet_ntop(AF_INET, (struct in_addr *)&data[10],
+ ip, BUFF_SIZE_IP);
+ STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s] "
+ "TTL[%u] Data length[%u] Address[%s]",
+ name, type, __pcap_dns_type_info(type),
+ class, __pcap_dns_class_info(class),
+ ttl, length, ip);
+ break;
+ case DNS_QTYPE_CNAME:
+ __pcap_dns_name_info((uint8_t *)dns_h, &data[10], cname);
+ if (data == NULL)
+ return;
+ STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s] "
+ "TTL[%u] Data length[%u] CName[%s]",
+ name, type, __pcap_dns_type_info(type),
+ class, __pcap_dns_class_info(class),
+ ttl, length, cname);
+ break;
+ case DNS_QTYPE_AAAA:
+ break;
+ default:
+ STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s] "
+ "TTL[%u] Data length[%u]",
+ name, type, __pcap_dns_type_info(type),
+ class, __pcap_dns_class_info(class),
+ ttl, length);
+ break;
+ }
+ }
+
+ data += (length + 10);
+ }
+}
+
+static void __pcap_dns_info(const u_char *packet)
+{
+ dns_t *dns_h = (dns_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_IP_HEADER + SIZE_UDP_HEADER);
+
+ STC_LOGD("Transaction ID[0x%x] Flags[0x%x] Questions[%u] "
+ "Answer RRs[%u] Authority RRs[%u] Additional RRs[%u]",
+ ntohs(dns_h->id), ntohs(dns_h->flags),
+ ntohs(dns_h->questions), ntohs(dns_h->answerRR),
+ ntohs(dns_h->authorityRR), ntohs(dns_h->additionalRR));
+
+ __pcap_dns_data_info(packet);
+}
+
+static const char *__pcap_icmp_code_info(u_int8_t type, u_int8_t code)
+{
+ char *info = NULL;
+
+ switch (type) {
+ case ICMP_DEST_UNREACH:
+ switch (code) {
+ case ICMP_NET_UNREACH:
+ info = "Network Unreachable";
+ break;
+ case ICMP_HOST_UNREACH:
+ info = "Host Unreachable";
+ break;
+ case ICMP_PROT_UNREACH:
+ info = "Protocol Unreachable";
+ break;
+ case ICMP_PORT_UNREACH:
+ info = "Port Unreachable";
+ break;
+ case ICMP_FRAG_NEEDED:
+ info = "Fragmentation Needed/DF set";
+ break;
+ case ICMP_SR_FAILED:
+ info = "Source Route failed";
+ break;
+ case ICMP_NET_UNKNOWN:
+ break;
+ case ICMP_HOST_UNKNOWN:
+ break;
+ case ICMP_HOST_ISOLATED:
+ break;
+ case ICMP_NET_ANO:
+ break;
+ case ICMP_HOST_ANO:
+ break;
+ case ICMP_NET_UNR_TOS:
+ break;
+ case ICMP_HOST_UNR_TOS:
+ break;
+ case ICMP_PKT_FILTERED:
+ info = "Packet filtered";
+ break;
+ case ICMP_PREC_VIOLATION:
+ info = "Precedence violation";
+ break;
+ case ICMP_PREC_CUTOFF:
+ info = "Precedence cut off";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+ break;
+ case ICMP_REDIRECT:
+ switch (code) {
+ case ICMP_REDIR_NET:
+ info = "Redirect Net";
+ break;
+ case ICMP_REDIR_HOST:
+ info = "Redirect Host";
+ break;
+ case ICMP_REDIR_NETTOS:
+ info = "Redirect Net for TOS";
+ break;
+ case ICMP_REDIR_HOSTTOS:
+ info = "Redirect Host for TOS";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+ break;
+ case ICMP_TIME_EXCEEDED:
+ switch (code) {
+ case ICMP_EXC_TTL:
+ info = "TTL count exceeded";
+ break;
+ case ICMP_EXC_FRAGTIME:
+ info = "Fragment Reass time exceeded";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static const char *__pcap_icmp_type_info(u_int8_t type)
+{
+ char *info = NULL;
+
+ switch (type) {
+ case ICMP_ECHOREPLY:
+ info = "Echo Reply";
+ break;
+ case ICMP_DEST_UNREACH:
+ info = "Destination Unreachable";
+ break;
+ case ICMP_SOURCE_QUENCH:
+ info = "Source Quench";
+ break;
+ case ICMP_REDIRECT:
+ info = "Redirect";
+ break;
+ case ICMP_ECHO:
+ info = "Echo Request";
+ break;
+ case ICMP_TIME_EXCEEDED:
+ info = "Time Exceeded";
+ break;
+ case ICMP_PARAMETERPROB:
+ info = "Parameter Problem";
+ break;
+ case ICMP_TIMESTAMP:
+ info = "Timestamp Request";
+ break;
+ case ICMP_TIMESTAMPREPLY:
+ info = "Timestamp Reply";
+ break;
+ case ICMP_INFO_REQUEST:
+ info = "Information Request";
+ break;
+ case ICMP_INFO_REPLY:
+ info = "Information Reply";
+ break;
+ case ICMP_ADDRESS:
+ info = "Address Mask Request";
+ break;
+ case ICMP_ADDRESSREPLY:
+ info = "Address Mask Reply";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static void __pcap_icmp_info(const u_char *packet)
+{
+ icmp_t *icmp_h = (icmp_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_IP_HEADER);
+
+ STC_LOGD("Type[%u:%s] Code[%u:%s] Checksum[0x%x]",
+ icmp_h->type, __pcap_icmp_type_info(icmp_h->type),
+ icmp_h->code, __pcap_icmp_code_info(icmp_h->type, icmp_h->code),
+ ntohs(icmp_h->checksum));
+}
+
+static void __pcap_tcp_info(const u_char *packet)
+{
+ tcp_t *tcp_h = (tcp_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_IP_HEADER);
+ u_int16_t source = ntohs(tcp_h->source);
+ u_int16_t dest = ntohs(tcp_h->dest);
+
+ STC_LOGD("Source[%u] Destination[%u] Sequence[%u] "
+ "Acknowledgment seq[%u] Window size[%u] ",
+ ntohs(tcp_h->source), ntohs(tcp_h->dest),
+ ntohl(tcp_h->seq), ntohl(tcp_h->ack_seq),
+ ntohs(tcp_h->window));
+
+ STC_LOGD("Checksum[0x%x] URG[%u] ACK[%u] PUSH[%u] "
+ "RST[%u] SYN[%u] FIN[%u]",
+ ntohs(tcp_h->check),
+ tcp_h->urg, tcp_h->ack, tcp_h->psh,
+ tcp_h->rst, tcp_h->syn, tcp_h->fin);
+
+ if (IS_SRC_OR_DST_PORT(PORT_DNS))
+ __pcap_dns_info(packet);
+}
+
+static void __pcap_udp_info(const u_char *packet)
+{
+ udp_t *udp_h = (udp_t *)(packet
+ + SIZE_ETHER_HEADER + SIZE_IP_HEADER);
+ u_int16_t source = ntohs(udp_h->source);
+ u_int16_t dest = ntohs(udp_h->dest);
+
+ STC_LOGD("Source[%u] Destination[%u] Len[%u] Checksum[0x%x]",
+ source, dest, ntohs(udp_h->len), ntohs(udp_h->check));
+
+ if (IS_SRC_OR_DST_PORT(PORT_DNS))
+ __pcap_dns_info(packet);
+ else if (IS_SRC_OR_DST_PORT(PORT_BOOTP_C) ||
+ IS_SRC_OR_DST_PORT(PORT_BOOTP_S))
+ __pcap_bootp_info(packet);
+ else if (IS_SRC_OR_DST_PORT(PORT_NTP))
+ __pcap_ntp_info(packet);
+}
+
+static const char *__pcap_eth_type_info(u_int16_t type)
+{
+ char *info = NULL;
+
+ switch (type) {
+ case ETHERTYPE_IP:
+ info = "IP";
+ break;
+ case ETHERTYPE_IPV6:
+ info = "IPv6";
+ break;
+ case ETHERTYPE_ARP:
+ info = "ARP";
+ break;
+ case ETHERTYPE_REVARP:
+ info = "REVARP";
+ break;
+ case ETHERTYPE_LOOPBACK:
+ info = "LOOPBACK";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static const char *__pcap_arp_opcode_info(u_int16_t opcode)
+{
+ char *info = NULL;
+
+ switch (opcode) {
+ case ARP_REQUEST:
+ info = "Request";
+ break;
+ case ARP_REPLY:
+ info = "Reply";
+ break;
+ case ARP_RREQUEST:
+ info = "RRequest";
+ break;
+ case ARP_RREPLY:
+ info = "RReply";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static void __pcap_arp_info(const u_char *packet)
+{
+ arp_t *arp_h = (arp_t *)(packet + SIZE_ETHER_HEADER);
+ u_int8_t *sha = (u_int8_t *)(packet +
+ SIZE_ETHER_HEADER + SIZE_ARP_HEADER);
+ u_int8_t *spa = (u_int8_t *)(sha + arp_h->ar_hln);
+ u_int8_t *tha = (u_int8_t *)(spa + arp_h->ar_pln);
+ u_int8_t *tpa = (u_int8_t *)(tha + arp_h->ar_hln);
+ u_int16_t ar_op = ntohs(arp_h->ar_op);
+ char sma[BUFF_SIZE_HOST];
+ char sia[BUFF_SIZE_IP];
+ char tma[BUFF_SIZE_HOST];
+ char tia[BUFF_SIZE_IP];
+ u_int16_t ar_pro;
+
+ g_strlcpy(sma,
+ ether_ntoa((const struct ether_addr *)sha),
+ sizeof(sma));
+ g_strlcpy(tma,
+ ether_ntoa((const struct ether_addr *)tha),
+ sizeof(tma));
+
+ inet_ntop(AF_INET, (struct in_addr *)spa, sia, BUFF_SIZE_IP);
+ inet_ntop(AF_INET, (struct in_addr *)tpa, tia, BUFF_SIZE_IP);
+
+ ar_pro = ntohs(arp_h->ar_pro);
+
+ STC_LOGD("HW type[%u] Protocol type[0x%04x:%s] "
+ "HW size[%u] Protocol size[%u] Opcode[%u:%s] ",
+ ntohs(arp_h->ar_hrd), ar_pro,
+ __pcap_eth_type_info(ar_pro),
+ arp_h->ar_hln, arp_h->ar_pln,
+ ar_op, __pcap_arp_opcode_info(ar_op));
+
+ STC_LOGD("Sender MAC[%s] Sender IP[%s] "
+ "Target MAC[%s] Target IP[%s]",
+ sma, sia, tma, tia);
+}
+
+static const char *__pcap_ip_protocol_info(u_int8_t p)
+{
+ char *info = NULL;
+
+ switch (p) {
+ case IPPROTO_IP:
+ info = "IP";
+ break;
+ case IPPROTO_ICMP:
+ info = "ICMP";
+ break;
+ case IPPROTO_IPIP:
+ info = "IPIP";
+ break;
+ case IPPROTO_TCP:
+ info = "TCP";
+ break;
+ case IPPROTO_UDP:
+ info = "UDP";
+ break;
+ case IPPROTO_IPV6:
+ info = "IPv6";
+ break;
+ case IPPROTO_ICMPV6:
+ info = "ICMPv6";
+ break;
+ default:
+ info = "Unknown";
+ break;
+ }
+
+ return info;
+}
+
+static void __pcap_ipv6_info(const u_char *packet)
+{
+ ip6_t *ip6_h = (ip6_t *)(packet + SIZE_ETHER_HEADER);
+ char ip6_src[BUFF_SIZE_IP6];
+ char ip6_dst[BUFF_SIZE_IP6];
+
+ inet_ntop(AF_INET6, &ip6_h->ip6_src, ip6_src, BUFF_SIZE_IP6);
+ inet_ntop(AF_INET6, &ip6_h->ip6_dst, ip6_dst, BUFF_SIZE_IP6);
+
+ STC_LOGD("Flow[0x%08x] Payload len[%u] Next hdr[%u:%s] "
+ "Hop limit[%u] Source[%s] Destination[%s]",
+ ntohl(ip6_h->ip6_flow), ntohs(ip6_h->ip6_plen),
+ ip6_h->ip6_nxt, __pcap_ip_protocol_info(ip6_h->ip6_nxt),
+ ip6_h->ip6_hlim, ip6_src, ip6_dst);
+
+ switch (ip6_h->ip6_nxt) {
+ case IPPROTO_IP:
+ break;
+ case IPPROTO_ICMP:
+ break;
+ case IPPROTO_IPIP:
+ break;
+ case IPPROTO_TCP:
+ break;
+ case IPPROTO_UDP:
+ break;
+ case IPPROTO_IPV6:
+ break;
+ case IPPROTO_ICMPV6:
+ break;
+ default:
+ break;
+ }
+}
+
+static void __pcap_ip_info(const u_char *packet)
+{
+ ip_t *ip_h = (ip_t *)(packet + SIZE_ETHER_HEADER);
+ char ip_src[BUFF_SIZE_IP];
+ char ip_dst[BUFF_SIZE_IP];
+
+ inet_ntop(AF_INET, &ip_h->ip_src, ip_src, BUFF_SIZE_IP);
+ inet_ntop(AF_INET, &ip_h->ip_dst, ip_dst, BUFF_SIZE_IP);
+
+ STC_LOGD("Header len[%u] TOS[0x%02x] Total len[%u] "
+ "ID[0x%04x] Flags[0x%02x] TTL[%u] Protocol[%u:%s] "
+ "Checksum[0x%04x] Source[%s] Destination[%s]",
+ ip_h->ip_hl << 2, ip_h->ip_tos,
+ ntohs(ip_h->ip_len), ntohs(ip_h->ip_id),
+ (ntohs(ip_h->ip_off) & 0xe000) >> 13,
+ ip_h->ip_ttl, ip_h->ip_p,
+ __pcap_ip_protocol_info(ip_h->ip_p),
+ ntohs(ip_h->ip_sum), ip_src, ip_dst);
+
+ switch (ip_h->ip_p) {
+ case IPPROTO_ICMP:
+ __pcap_icmp_info(packet);
+ break;
+ case IPPROTO_TCP:
+ __pcap_tcp_info(packet);
+ break;
+ case IPPROTO_UDP:
+ __pcap_udp_info(packet);
+ break;
+ default:
+ break;
+ }
+}
+
+static void __pcap_eth_info(const u_char *packet)
+{
+ eth_t *eth_h = (eth_t *)packet;
+ u_int8_t *eth_shost = eth_h->ether_shost;
+ u_int8_t *eth_dhost = eth_h->ether_dhost;
+ char shost[BUFF_SIZE_HOST];
+ char dhost[BUFF_SIZE_HOST];
+ u_int16_t ether_type;
+
+ g_strlcpy(shost,
+ ether_ntoa((const struct ether_addr *)eth_shost),
+ sizeof(shost));
+
+ g_strlcpy(dhost,
+ ether_ntoa((const struct ether_addr *)eth_dhost),
+ sizeof(dhost));
+
+ ether_type = ntohs(eth_h->ether_type);
+
+ STC_LOGD("Source[%s] Destination[%s] Type[0x%04x:%s]",
+ shost, dhost, ether_type, __pcap_eth_type_info(ether_type));
+}
+
+static void __pcap_fm_info(const struct pcap_pkthdr *pkthdr)
+{
+ char *curr = NULL;
+ int len = 0;
+ struct timeval ts = pkthdr->ts;
+ __time_t tv_sec = ts.tv_sec;
+ __suseconds_t tv_usec = tv_usec;
+
+ if (g_pcap_start_fm == false) {
+ g_pcap_tv = ts;
+ g_pcap_start_fm = true;
+ }
+
+ curr = ctime((const time_t *)&tv_sec);
+ len = strlen(curr);
+ curr[len - 1] = '\0';
+
+ STC_LOGD("Arrival time[%s] Timeval[%.06f] "
+ "Frame len[%u] Capture len[%u]", curr,
+ (float)((tv_sec - g_pcap_tv.tv_sec) * 1000000 +
+ (tv_usec - g_pcap_tv.tv_usec)) / 1000000,
+ pkthdr->len, pkthdr->caplen);
+}
+
+static void __pcap_handler(u_char *param,
+ const struct pcap_pkthdr *pkthdr,
+ const u_char *packet) {
+ eth_t *eth_h;
+ unsigned short eth_type;
+ /* int len = pkthdr->len; */
+
+ __pcap_fm_info(pkthdr);
+
+ eth_h = (eth_t *)packet;
+ __pcap_eth_info(packet);
+
+ eth_type = ntohs(eth_h->ether_type);
+ switch (eth_type) {
+ case ETHERTYPE_IP:
+ __pcap_ip_info(packet);
+ /* __pcap_data_info(pcaket, len); */
+ break;
+ case ETHERTYPE_IPV6:
+ __pcap_ipv6_info(packet);
+ break;
+ case ETHERTYPE_ARP:
+ case ETHERTYPE_REVARP:
+ __pcap_arp_info(packet);
+ break;
+ case ETHERTYPE_LOOPBACK:
+ break;
+ default:
+ break;
+ }
+}
+
+static gboolean __pcap_thread_source_func(gpointer data)
+{
+ char buf[MAX_IFACE_LENGTH];
+ stc_pcap_data_s *lookup;
+ stc_pcap_data_s *pcap_data = (stc_pcap_data_s *)data;
+
+ g_pcap_tv.tv_sec = 0;
+ g_pcap_tv.tv_usec = 0;
+ g_pcap_start_fm = false;
+
+ if (g_pcap_tables == NULL)
+ return false;
+
+ snprintf(buf, sizeof(buf), "%s_%d",
+ pcap_data->name, pcap_data->group);
+
+ lookup = g_hash_table_lookup(g_pcap_tables, buf);
+ if (!lookup) {
+ STC_LOGE("pcap loop not found");
+ return false;
+ }
+
+ g_hash_table_remove(g_pcap_tables, buf);
+ STC_LOGD("Successfully removed pcap loop [%s]", buf);
+
+ return false;
+}
+
+static gpointer __pcap_thread_func(gpointer data)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_if_t *alldevs = NULL;
+ pcap_if_t *dev = NULL;
+ char *name = NULL;
+ GSource *source = NULL;
+ GMainContext *context = NULL;
+ stc_pcap_data_s *pcap_data = (stc_pcap_data_s *)data;
+
+ if (pcap_findalldevs(&alldevs, errbuf) < 0 ||
+ alldevs == NULL) {
+ STC_LOGE("Failed to find all devs [%s]", errbuf);
+ goto thread_exit;
+ }
+
+ for (dev = alldevs; dev; dev = dev->next) {
+ if (g_strcmp0(dev->name, pcap_data->name) == 0) {
+ name = g_strdup(dev->name);
+ break;
+ }
+ }
+
+ pcap_freealldevs(alldevs);
+
+ if (name == NULL) {
+ STC_LOGE("Failed to find dev [%s]", pcap_data->name);
+ goto thread_exit;
+ }
+
+ STC_LOGD("Pcap source dev [%s]", name);
+
+ pcap_data->handle = pcap_open_live(name, 65535, 1, 1000, errbuf);
+ if (pcap_data->handle == NULL) {
+ STC_LOGE("Failed to open live [%s]", errbuf);
+ goto thread_exit;
+ }
+
+ pcap_loop(pcap_data->handle, 0, __pcap_handler, NULL);
+
+ pcap_close(pcap_data->handle);
+
+thread_exit:
+ FREE(name);
+
+ context = g_main_context_default();
+
+ source = g_idle_source_new();
+
+ g_source_set_callback(source,
+ __pcap_thread_source_func, pcap_data, NULL);
+ g_source_attach(source, context);
+
+ g_source_unref(source);
+
+ __STC_LOG_FUNC_EXIT__;
+ return NULL;
+}
+
+int stc_plugin_pcap_initialize(void)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ g_pcap_tables = g_hash_table_new_full(g_str_hash,
+ g_str_equal, g_free, __pcap_data_free);
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_pcap_deinitialize(void)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ if (g_pcap_tables) {
+ g_hash_table_destroy(g_pcap_tables);
+ g_pcap_tables = NULL;
+ }
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_pcap_lookup_dev(void)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ char *dev = NULL;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ dev = pcap_lookupdev(errbuf);
+ if (dev == NULL) {
+ STC_LOGE("Failed to look up dev [%s]", errbuf);
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_FAIL;
+ }
+
+ STC_LOGD("Dev [%s]", dev);
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_pcap_lookup_net(void)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ char *dev = NULL;
+ char net[BUFF_SIZE_IP];
+ char mask[BUFF_SIZE_IP];
+ char errbuf[PCAP_ERRBUF_SIZE];
+ int ret;
+ bpf_u_int32 netp;
+ bpf_u_int32 maskp;
+
+ dev = pcap_lookupdev(errbuf);
+ if (dev == NULL) {
+ STC_LOGE("Failed to look up dev [%s]", errbuf);
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_FAIL;
+ }
+
+ STC_LOGD("Dev [%s]", dev);
+
+ ret = pcap_lookupnet(dev, &netp, &maskp, errbuf);
+ if (ret == -1) {
+ STC_LOGE("Failed to look up net [%s]", errbuf);
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_FAIL;
+ }
+
+ inet_ntop(AF_INET, &netp, net, BUFF_SIZE_IP);
+ STC_LOGD("Net [%s]", net);
+
+ inet_ntop(AF_INET, &maskp, mask, BUFF_SIZE_IP);
+ STC_LOGD("Mask [%s]", mask);
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_pcap_find_alldevs(void)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ char net[BUFF_SIZE_IP];
+ char mask[BUFF_SIZE_IP];
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_if_t *alldevs = NULL;
+ pcap_if_t *dev = NULL;
+ bpf_u_int32 netp;
+ bpf_u_int32 maskp;
+
+ if (pcap_findalldevs(&alldevs, errbuf) < 0 ||
+ alldevs == NULL) {
+ STC_LOGE("Failed to find all devs [%s]", errbuf);
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_FAIL;
+ }
+
+ for (dev = alldevs; dev; dev = dev->next) {
+ STC_LOGD("Dev [%s]", dev->name);
+
+ if (dev->description)
+ STC_LOGD("Decs [%s]", dev->description);
+
+ if (pcap_lookupnet(dev->name, &netp, &maskp, errbuf) == -1) {
+ STC_LOGE("Failed to look up net [%s]", errbuf);
+ continue;
+ }
+
+ inet_ntop(AF_INET, &netp, net, BUFF_SIZE_IP);
+ STC_LOGD("Net [%s]", net);
+
+ inet_ntop(AF_INET, &maskp, mask, BUFF_SIZE_IP);
+ STC_LOGD("Mask [%s]", mask);
+ }
+
+ pcap_freealldevs(alldevs);
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_pcap_register_loop_pcap(const char *ifname,
+ int group)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ stc_pcap_data_s *data;
+ stc_pcap_data_s *lookup;
+ char buf[MAX_IFACE_LENGTH];
+
+ ret_value_msg_if(g_pcap_tables == NULL,
+ STC_ERROR_FAIL,
+ "pcap tables is not initialized!");
+
+ ret_value_msg_if(ifname == NULL,
+ STC_ERROR_FAIL,
+ "Invalid parameter [ifname]");
+
+ snprintf(buf, sizeof(buf), "%s_%d", ifname, group);
+
+ lookup = g_hash_table_lookup(g_pcap_tables, buf);
+ if (lookup) {
+ STC_LOGD("pcap loop already present");
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_ALREADY_DATA;
+ }
+
+ data = MALLOC0(stc_pcap_data_s, 1);
+ if (!data) {
+ STC_LOGE("data allocation failed");
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_OUT_OF_MEMORY;
+ }
+
+ data->name = g_strdup(ifname);
+ data->group = group;
+ data->thread = g_thread_new(buf, __pcap_thread_func, data);
+
+ g_hash_table_insert(g_pcap_tables, g_strdup(buf), data);
+ STC_LOGD("Successfully added pcap loop [%s]", buf);
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_pcap_unregister_loop_pcap(const char *ifname,
+ int group)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ stc_pcap_data_s *lookup;
+ char buf[MAX_IFACE_LENGTH];
+
+ ret_value_msg_if(g_pcap_tables == NULL,
+ STC_ERROR_FAIL,
+ "pcap tables is not initialized!");
+
+ ret_value_msg_if(ifname == NULL,
+ STC_ERROR_FAIL,
+ "Invalid parameter [ifname]");
+
+ snprintf(buf, sizeof(buf), "%s_%d", ifname, group);
+
+ lookup = g_hash_table_lookup(g_pcap_tables, buf);
+ if (!lookup) {
+ STC_LOGE("pcap loop not found");
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NO_DATA;
+ }
+
+ pcap_breakloop(lookup->handle);
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+API stc_plugin_pcap_s stc_plugin_pcap = {
+ .initialize_plugin =
+ stc_plugin_pcap_initialize,
+ .deinitialize_plugin =
+ stc_plugin_pcap_deinitialize,
+ .lookup_dev =
+ stc_plugin_pcap_lookup_dev,
+ .lookup_net =
+ stc_plugin_pcap_lookup_net,
+ .find_alldevs =
+ stc_plugin_pcap_find_alldevs,
+ .register_loop_pcap =
+ stc_plugin_pcap_register_loop_pcap,
+ .unregister_loop_pcap =
+ stc_plugin_pcap_unregister_loop_pcap
+};
+//LCOV_EXCL_STOP