From 0b23a20ddb9cebc70d966936a54f5b1082ea38b7 Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Tue, 20 Nov 2018 17:44:09 +0900 Subject: [PATCH] Add packet capture functions Change-Id: I287425157c7ca377a585e8b11e502a29c7b189b6 Signed-off-by: hyunuktak --- include/stc-manager-gdbus.h | 1 + include/stc-manager-plugin-pcap.h | 35 + include/stc-manager.h | 1 + include/stc-pcap.h | 50 ++ interfaces/CMakeLists.txt | 1 + interfaces/stcmanager-iface-pcap.xml | 12 + packaging/stc-manager.spec | 11 + plugin/CMakeLists.txt | 1 + plugin/pcap/CMakeLists.txt | 36 + plugin/pcap/include/stc-plugin-pcap.h | 225 ++++++ plugin/pcap/stc-plugin-pcap.c | 1329 +++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 2 + src/stc-manager-gdbus.c | 46 ++ src/stc-manager-plugin-pcap.c | 171 +++++ src/stc-manager.c | 3 + src/stc-pcap.c | 160 ++++ 16 files changed, 2084 insertions(+) mode change 100644 => 100755 include/stc-manager-gdbus.h create mode 100755 include/stc-manager-plugin-pcap.h mode change 100644 => 100755 include/stc-manager.h create mode 100755 include/stc-pcap.h create mode 100644 interfaces/stcmanager-iface-pcap.xml create mode 100644 plugin/pcap/CMakeLists.txt create mode 100755 plugin/pcap/include/stc-plugin-pcap.h create mode 100755 plugin/pcap/stc-plugin-pcap.c mode change 100644 => 100755 src/stc-manager-gdbus.c create mode 100644 src/stc-manager-plugin-pcap.c mode change 100644 => 100755 src/stc-manager.c create mode 100755 src/stc-pcap.c diff --git a/include/stc-manager-gdbus.h b/include/stc-manager-gdbus.h old mode 100644 new mode 100755 index 860b766..263077d --- a/include/stc-manager-gdbus.h +++ b/include/stc-manager-gdbus.h @@ -26,6 +26,7 @@ #define STC_DBUS_SERVICE_STATISTICS_PATH "/net/stc/statistics" #define STC_DBUS_SERVICE_RESTRICTION_PATH "/net/stc/restriction" #define STC_DBUS_SERVICE_FIREWALL_PATH "/net/stc/firewall" +#define STC_DBUS_SERVICE_PCAP_PATH "/net/stc/pcap" #define STC_DBUS_SERVICE_MANAGER_PATH "/net/stc/manager" #define STC_DBUS_REPLY_ERROR_NONE(invocation) \ diff --git a/include/stc-manager-plugin-pcap.h b/include/stc-manager-plugin-pcap.h new file mode 100755 index 0000000..728004f --- /dev/null +++ b/include/stc-manager-plugin-pcap.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 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. + */ + +#ifndef __STC_MANAGER_PLUGIN_PCAP_H__ +#define __STC_MANAGER_PLUGIN_PCAP_H__ + +#define STC_PLUGIN_PCAP_FILEPATH "/usr/lib/stc-plugin-pcap.so" + +#include "stc-plugin-pcap.h" + +int stc_plugin_pcap_init(void); +int stc_plugin_pcap_deinit(void); + +int stc_plugin_pcap_lookup_dev(void); +int stc_plugin_pcap_lookup_net(void); +int stc_plugin_pcap_find_alldevs(void); +int stc_plugin_pcap_register_loop_pcap(const char *ifname, + int group); +int stc_plugin_pcap_unregister_loop_pcap(const char *ifname, + int group); + +#endif /* __STC_MANAGER_PLUGIN_PROCFS_H__ */ diff --git a/include/stc-manager.h b/include/stc-manager.h old mode 100644 new mode 100755 index d1f4d93..fabbbb1 --- a/include/stc-manager.h +++ b/include/stc-manager.h @@ -236,6 +236,7 @@ typedef struct { gpointer statistics_obj; gpointer restriction_obj; gpointer firewall_obj; + gpointer pcap_obj; gpointer manager_obj; GDBusObjectManagerServer *obj_mgr; diff --git a/include/stc-pcap.h b/include/stc-pcap.h new file mode 100755 index 0000000..d99d450 --- /dev/null +++ b/include/stc-pcap.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 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. + */ + +#ifndef __STC_PCAP_H__ +#define __STC_PCAP_H__ + +#include +#include "stc-manager.h" +#include "stc-manager-gdbus.h" + +/***************************************************************************** + * Macros and Typedefs + *****************************************************************************/ + +#define STC_PCAP_IFNAME "ifname" +#define STC_PCAP_NFLOG_GROUP "nflog_group" + +typedef struct { + char *ifname; + int nflog_group; +} stc_pcap_s; + +/***************************************************************************** + * Functions Declaration + *****************************************************************************/ + +gboolean handle_pcap_start(StcPcap *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data); + +gboolean handle_pcap_stop(StcPcap *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data); + +#endif /* __STC_PCAP_H__ */ diff --git a/interfaces/CMakeLists.txt b/interfaces/CMakeLists.txt index 8f03ebf..dc26fa1 100644 --- a/interfaces/CMakeLists.txt +++ b/interfaces/CMakeLists.txt @@ -10,6 +10,7 @@ ADD_CUSTOM_COMMAND( ${INTERFACES}/stcmanager-iface-restriction.xml ${INTERFACES}/stcmanager-iface-statistics.xml ${INTERFACES}/stcmanager-iface-firewall.xml + ${INTERFACES}/stcmanager-iface-pcap.xml COMMENT "Generating GDBus .c/.h") ADD_CUSTOM_TARGET(GENERATED_DBUS_CODE DEPENDS dbus) diff --git a/interfaces/stcmanager-iface-pcap.xml b/interfaces/stcmanager-iface-pcap.xml new file mode 100644 index 0000000..4320ab6 --- /dev/null +++ b/interfaces/stcmanager-iface-pcap.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index b4a267a..b14ee3f 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -57,6 +57,13 @@ Summary: STC manager exception proc file system plugin %description plugin-procfs A smart traffic control manager extension for proc file system plugin +%package plugin-pcap +Summary: STC manager exception packet capture plugin +BuildRequires: libpcap-devel + +%description plugin-pcap +A smart traffic control manager extension for packet capture plugin + %package plugin-tether Summary: Tethering plugin for data usage of tethering clients @@ -154,6 +161,10 @@ cp resources/dbus/stc-manager.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/st %manifest %{name}.manifest %attr(500,root,root) %{_libdir}/stc-plugin-procfs.so +%files plugin-pcap +%manifest %{name}.manifest +%attr(500,root,root) %{_libdir}/stc-plugin-pcap.so + %files plugin-tether %manifest %{name}.manifest %attr(500,root,root) %{_libdir}/stc-plugin-tether.so diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt index e591d7a..04c53b8 100644 --- a/plugin/CMakeLists.txt +++ b/plugin/CMakeLists.txt @@ -18,4 +18,5 @@ INCLUDE_DIRECTORIES(${MONITOR_SOURCE_DIR}/include) ADD_SUBDIRECTORY(appstatus) ADD_SUBDIRECTORY(exception) ADD_SUBDIRECTORY(procfs) +ADD_SUBDIRECTORY(pcap) ADD_SUBDIRECTORY(tether) diff --git a/plugin/pcap/CMakeLists.txt b/plugin/pcap/CMakeLists.txt new file mode 100644 index 0000000..be4b022 --- /dev/null +++ b/plugin/pcap/CMakeLists.txt @@ -0,0 +1,36 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(stc-plugin-pcap C) + +# Set required packages +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(pcap_plugin REQUIRED + dlog + gio-2.0 + gio-unix-2.0 + glib-2.0 + ) + +FOREACH(flag ${pcap_plugin_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -g -Werror -fvisibility=hidden") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") + +ADD_DEFINITIONS("-DUSE_DLOG") + +SET(SRCS_PLUGIN + stc-plugin-pcap.c + ) + +# library build +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS_PLUGIN}) +ADD_DEPENDENCIES(${PROJECT_NAME} GENERATED_DBUS_CODE) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pcap_plugin_LDFLAGS} -lpcap) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "" OUTPUT_NAME ${PROJECT_NAME}) + +# install +INSTALL(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${LIBDIR}) diff --git a/plugin/pcap/include/stc-plugin-pcap.h b/plugin/pcap/include/stc-plugin-pcap.h new file mode 100755 index 0000000..a2b8c34 --- /dev/null +++ b/plugin/pcap/include/stc-plugin-pcap.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2016 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. + */ + +#ifndef __STC_PLUGIN_PCAP_H__ +#define __STC_PLUGIN_PCAP_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stc-error.h" +#include "stc-manager.h" + +#define BUFF_SIZE_IP 16 +#define BUFF_SIZE_IP6 46 +#define BUFF_SIZE_HOST 32 +#define BUFF_SIZE_ID 64 +#define BUFF_SIZE_TIME 64 +#define BUFF_SIZE_NAME 256 + +#define PORT_FTP_DATA 20 +#define PORT_FTP_CTL 21 +#define PORT_SMTP 25 +#define PORT_DNS 53 +#define PORT_BOOTP_S 67 +#define PORT_BOOTP_C 68 +#define PORT_HTTP 80 +#define PORT_NTP 123 +#define PORT_HTTPS 443 +#define PORT_SMTP_MSG 587 + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 +#define ARP_RREQUEST 3 +#define ARP_RREPLY 4 + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define BOOTP_CHADDR_LEN 16 +#define BOOTP_SNAME_LEN 64 +#define BOOTP_FILE_LEN 128 +#define BOOTP_MOPTION_LEN 60 + +#define BOOTP_MAGIC_DHCP 0x63825363 + +#define DHCP_TAG_SUBNET_MASK 1 +#define DHCP_TAG_ROUTER 3 +#define DHCP_TAG_DNS 6 +#define DHCP_TAG_HOST_NAME 12 +#define DHCP_TAG_REQUESTED_IP 50 +#define DHCP_TAG_IP_LEASE_TIME 51 +#define DHCP_TAG_MSG_TYPE 53 +#define DHCP_TAG_SERVER_ID 54 +#define DHCP_TAG_MSG_SIZE 57 +#define DHCP_TAG_CLIENT_ID 61 +#define DHCP_TAG_END 255 + +#define DHCP_MSG_TYPE_DISCOVER 1 +#define DHCP_MSG_TYPE_OFFER 2 +#define DHCP_MSG_TYPE_REQUEST 3 +#define DHCP_MSG_TYPE_DECLINE 4 +#define DHCP_MSG_TYPE_ACK 5 +#define DHCP_MSG_TYPE_NAK 6 +#define DHCP_MSG_TYPE_RELEASE 7 +#define DHCP_MSG_TYPE_INFORM 8 + +#define DHCP_CLIENT_ID_ETHERNET 1 +#define DHCP_CLIENT_ID_IEEE802 2 +#define DHCP_CLIENT_ID_ARCNET 7 +#define DHCP_CLIENT_ID_LOCALTALK 11 +#define DHCP_CLIENT_ID_LOCALNET 12 +#define DHCP_CLIENT_ID_SMDS 14 +#define DHCP_CLIENT_ID_FRAMERELAY 15 +#define DHCP_CLIENT_ID_ATM1 16 +#define DHCP_CLIENT_ID_HDLC 17 +#define DHCP_CLIENT_ID_FIBRECHANNEL 18 +#define DHCP_CLIENT_ID_ATM2 19 +#define DHCP_CLIENT_ID_SERIALLINE 20 + +#define NTP_STRATUM_UNSPECIFIED 0 +#define NTP_STRATUM_PRIM_REF 1 +#define NTP_STRATUM_INFO_QUERY 62 +#define NTP_STRATUM_INFO_REPLY 63 + +#define NTP_JAN_1970 2208988800U /* 1970 - 1900 in seconds */ + +#define DNS_QTYPE_A 1 +#define DNS_QTYPE_CNAME 5 +#define DNS_QTYPE_AAAA 28 + +#define DNS_QCLASS_IN 1 +#define DNS_QCLASS_CHAOS 3 +#define DNS_QCLASS_HS 4 +#define DNS_QCLASS_ANY 255 + +typedef struct { + char *name; + int group; + GThread *thread; + pcap_t *handle; +} stc_pcap_data_s; + +typedef struct { + uint16_t id; + uint16_t flags; + uint16_t questions; + uint16_t answerRR; + uint16_t authorityRR; + uint16_t additionalRR; +} dns_t; + +typedef struct { + uint16_t type; + uint16_t class; +} dns_query_t; + +typedef struct { + uint16_t type; + uint16_t class; + uint16_t ttl; + uint16_t rdlen; + char rdata[]; +} dns_recode_t; + +typedef struct { + uint8_t op; /* packet opcode type */ + uint8_t htype; /* hardware addr type */ + uint8_t hlen; /* hardware addr length */ + uint8_t hops; /* gateway hops */ + uint32_t xid; /* transaction ID */ + uint16_t secs; /* seconds since boot began */ + uint16_t flags; /* flags */ + struct in_addr ciaddr; /* client IP address */ + struct in_addr yiaddr; /* 'your' IP address */ + struct in_addr siaddr; /* server IP address */ + struct in_addr giaddr; /* gateway(relay agent) IP address */ + uint8_t chaddr[BOOTP_CHADDR_LEN]; /* client hardware address */ + uint8_t sname[BOOTP_SNAME_LEN]; /* server host name */ + uint8_t file[BOOTP_FILE_LEN]; /* boot file name */ + uint32_t magic; /* must be 0x63825363 (network order) */ + uint8_t moption[BOOTP_MOPTION_LEN]; +} bootp_t; + +typedef struct { + uint16_t second; + uint16_t fraction; +} ntp_short_t; + +typedef struct { + uint32_t second; + uint32_t fraction; +} ntp_long_t; + +typedef struct { + uint8_t flags; /* Mode, version and leap indicator */ + uint8_t stratum; /* Stratum details */ + uint8_t poll; /* Maximum interval in log2 seconds */ + uint8_t precision; /* Clock precision in log2 seconds */ + ntp_short_t rootdelay; /* Root delay */ + ntp_short_t rootdisp; /* Root dispersion */ + uint32_t refid; /* Reference ID */ + ntp_long_t reftime; /* Reference timestamp */ + ntp_long_t orgtime; /* Origin timestamp */ + ntp_long_t rectime; /* Receive timestamp */ + ntp_long_t xmttime; /* Transmit timestamp */ +} ntp_t; + +typedef struct ether_header eth_t; +typedef struct ip ip_t; +typedef struct ip6_hdr ip6_t; +typedef struct arphdr arp_t; +typedef struct icmphdr icmp_t; +typedef struct tcphdr tcp_t; +typedef struct udphdr udp_t; + +#define SIZE_ETHER_HEADER sizeof(eth_t) +#define SIZE_IP_HEADER sizeof(ip_t) +#define SIZE_ARP_HEADER sizeof(arp_t) +#define SIZE_ICMP_HEADER sizeof(icmp_t) +#define SIZE_TCP_HEADER sizeof(tcp_t) +#define SIZE_UDP_HEADER sizeof(udp_t) +#define SIZE_DNS_HEADER sizeof(dns_t) + +#define IS_SRC_OR_DST_PORT(p) (source == (p) || dest == (p)) + +typedef struct { + int (*initialize_plugin) (void); + int (*deinitialize_plugin) (void); + int (*lookup_dev) (void); + int (*lookup_net) (void); + int (*find_alldevs) (void); + int (*register_loop_pcap) (const char *ifname, int group); + int (*unregister_loop_pcap) (const char *ifname, int group); +} stc_plugin_pcap_s; + +#endif /* __STC_PLUGIN_PCAP_H__ */ diff --git a/plugin/pcap/stc-plugin-pcap.c b/plugin/pcap/stc-plugin-pcap.c new file mode 100755 index 0000000..8cba6bd --- /dev/null +++ b/plugin/pcap/stc-plugin-pcap.c @@ -0,0 +1,1329 @@ +/* + * 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c845dd0..2ec0178 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ SET(PLUGIN_DIR ${CMAKE_SOURCE_DIR}/plugin) SET(APPSTATUS_SOURCE_DIR ${PLUGIN_DIR}/appstatus) SET(EXCEPTION_SOURCE_DIR ${PLUGIN_DIR}/exception) SET(PROCFS_SOURCE_DIR ${PLUGIN_DIR}/procfs) +SET(PCAP_SOURCE_DIR ${PLUGIN_DIR}/pcap) SET(TETHER_SOURCE_DIR ${PLUGIN_DIR}/tether) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) @@ -54,6 +55,7 @@ INCLUDE_DIRECTORIES(${LIMITATION_SOURCE_DIR}/include) INCLUDE_DIRECTORIES(${APPSTATUS_SOURCE_DIR}/include) INCLUDE_DIRECTORIES(${EXCEPTION_SOURCE_DIR}/include) INCLUDE_DIRECTORIES(${PROCFS_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${PCAP_SOURCE_DIR}/include) INCLUDE_DIRECTORIES(${TETHER_SOURCE_DIR}/include) FILE(GLOB SOURCE_SRCS ${SOURCE_DIR}/*.c) diff --git a/src/stc-manager-gdbus.c b/src/stc-manager-gdbus.c old mode 100644 new mode 100755 index b265c80..ef74b17 --- a/src/stc-manager-gdbus.c +++ b/src/stc-manager-gdbus.c @@ -19,6 +19,7 @@ #include "stc-statistics.h" #include "stc-restriction.h" #include "stc-firewall.h" +#include "stc-pcap.h" #include "stc-connection.h" #include "stc-manager-util.h" #include "stc-manager-plugin-appstatus.h" @@ -232,6 +233,45 @@ static gboolean __stc_manager_gdbus_firewall_init(stc_s *stc) return ret; } +static gboolean __stc_manager_gdbus_pcap_init(stc_s *stc) +{ + __STC_LOG_FUNC_ENTER__; + gboolean ret = TRUE; + gchar *s = NULL; + + StcObjectSkeleton *object = NULL; + StcPcap *pcap = NULL; + s = g_strdup_printf(STC_DBUS_SERVICE_PCAP_PATH); + + /* Add interface to default object path */ + object = stc_object_skeleton_new(s); + g_free(s); + + pcap = stc_pcap_skeleton_new(); + stc_object_skeleton_set_pcap(object, pcap); + g_object_unref(pcap); + + /* Register for method callbacks as signal callbacks */ + + g_signal_connect(pcap, "handle-start", + G_CALLBACK(handle_pcap_start), + stc); + + g_signal_connect(pcap, "handle-stop", + G_CALLBACK(handle_pcap_stop), + stc); + + /* Export the object (@manager takes its own reference to @object) */ + g_dbus_object_manager_server_export(stc->obj_mgr, + G_DBUS_OBJECT_SKELETON(object)); + g_object_unref(object); + + stc->pcap_obj = (gpointer)pcap; + + __STC_LOG_FUNC_EXIT__; + return ret; +} + static gboolean __stc_manager_gdbus_manager_init(stc_s *stc) { __STC_LOG_FUNC_ENTER__; @@ -297,6 +337,11 @@ static void __stc_manager_gdbus_on_bus_acquired(GDBusConnection *connection, /* Deinitialize and quit manager */ } + if (__stc_manager_gdbus_pcap_init(stc) == FALSE) { + STC_LOGE("Cannot signal connect to pcap"); //LCOV_EXCL_LINE + /* Deinitialize and quit manager */ + } + if (__stc_manager_gdbus_manager_init(stc) == FALSE) { STC_LOGE("Cannot signal connect to manager"); //LCOV_EXCL_LINE /* Deinitialize and quit manager */ @@ -362,6 +407,7 @@ void stc_manager_gdbus_deinit(gpointer stc_data) stc->statistics_obj = NULL; stc->restriction_obj = NULL; stc->firewall_obj = NULL; + stc->pcap_obj = NULL; stc->manager_obj = NULL; __STC_LOG_FUNC_EXIT__; } diff --git a/src/stc-manager-plugin-pcap.c b/src/stc-manager-plugin-pcap.c new file mode 100644 index 0000000..c9432a2 --- /dev/null +++ b/src/stc-manager-plugin-pcap.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2016 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 + +#include "stc-manager.h" +#include "stc-manager-plugin-pcap.h" + +static gboolean stc_plugin_enabled = FALSE; +static void *handle_plugin; +static stc_plugin_pcap_s *stc_plugin; + +//LCOV_EXCL_START +int stc_plugin_pcap_init(void) +{ + __STC_LOG_FUNC_ENTER__; + + handle_plugin = dlopen(STC_PLUGIN_PCAP_FILEPATH, RTLD_NOW); + if (!handle_plugin) { + STC_LOGE("Can't load %s: %s", STC_PLUGIN_PCAP_FILEPATH, dlerror()); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + stc_plugin = dlsym(handle_plugin, "stc_plugin_pcap"); + if (!stc_plugin) { + STC_LOGE("Can't load symbol: %s", dlerror()); + dlclose(handle_plugin); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + stc_plugin->initialize_plugin(); + stc_plugin_enabled = TRUE; + + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; +} + +int stc_plugin_pcap_deinit(void) +{ + __STC_LOG_FUNC_ENTER__; + + if (!stc_plugin_enabled) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + stc_plugin->deinitialize_plugin(); + stc_plugin_enabled = FALSE; + dlclose(handle_plugin); + + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; +} + +int stc_plugin_pcap_lookup_dev(void) +{ + __STC_LOG_FUNC_ENTER__; + + if (!stc_plugin_enabled) { + STC_LOGE("Plugin wasn't enabled"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + if (!stc_plugin) { + STC_LOGE("Plugin wasn't loaded"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + __STC_LOG_FUNC_EXIT__; + return stc_plugin->lookup_dev(); +} + +int stc_plugin_pcap_lookup_net(void) +{ + __STC_LOG_FUNC_ENTER__; + + if (!stc_plugin_enabled) { + STC_LOGE("Plugin wasn't enabled"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + if (!stc_plugin) { + STC_LOGE("Plugin wasn't loaded"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + __STC_LOG_FUNC_EXIT__; + return stc_plugin->lookup_net(); +} + +int stc_plugin_pcap_find_alldevs(void) +{ + __STC_LOG_FUNC_ENTER__; + + if (!stc_plugin_enabled) { + STC_LOGE("Plugin wasn't enabled"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + if (!stc_plugin) { + STC_LOGE("Plugin wasn't loaded"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + __STC_LOG_FUNC_EXIT__; + return stc_plugin->find_alldevs(); +} + +int stc_plugin_pcap_register_loop_pcap(const char *ifname, + int group) +{ + __STC_LOG_FUNC_ENTER__; + + if (!stc_plugin_enabled) { + STC_LOGE("Plugin wasn't enabled"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + if (!stc_plugin) { + STC_LOGE("Plugin wasn't loaded"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + __STC_LOG_FUNC_EXIT__; + return stc_plugin->register_loop_pcap(ifname, group); +} + +int stc_plugin_pcap_unregister_loop_pcap(const char *ifname, + int group) +{ + __STC_LOG_FUNC_ENTER__; + + if (!stc_plugin_enabled) { + STC_LOGE("Plugin wasn't enabled"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + if (!stc_plugin) { + STC_LOGE("Plugin wasn't loaded"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_UNINITIALIZED; + } + + __STC_LOG_FUNC_EXIT__; + return stc_plugin->unregister_loop_pcap(ifname, group); +} +//LCOV_EXCL_STOP diff --git a/src/stc-manager.c b/src/stc-manager.c old mode 100644 new mode 100755 index 79acd88..46401fb --- a/src/stc-manager.c +++ b/src/stc-manager.c @@ -32,6 +32,7 @@ #include "stc-manager-plugin-exception.h" #include "stc-manager-plugin-procfs.h" #include "stc-manager-plugin-tether.h" +#include "stc-manager-plugin-pcap.h" #define BUF_SIZE_FOR_ERR 100 @@ -91,6 +92,7 @@ static void __stc_manager_deinit(void) stc_plugin_exception_deinit(); stc_plugin_procfs_deinit(); stc_plugin_tether_deinit(); + stc_plugin_pcap_deinit(); inotify_deregister(INFO_STORAGE_DIR); inotify_deinitialize(); @@ -133,6 +135,7 @@ static stc_s *__stc_manager_init(void) stc_plugin_exception_init(); stc_plugin_procfs_init(); stc_plugin_tether_init(); + stc_plugin_pcap_init(); #endif stc_firewall_init(); diff --git a/src/stc-pcap.c b/src/stc-pcap.c new file mode 100755 index 0000000..368971e --- /dev/null +++ b/src/stc-pcap.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2016 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-db.h" +#include "stc-pcap.h" +#include "stc-manager-plugin-pcap.h" + +#define PCAP_DBUS_ERROR_NAME "net.stc.pcap.Error.Failed" + +#define STC_PCAP_DBUS_REPLY_ERROR(invocation, err_num) \ + g_dbus_method_invocation_return_dbus_error((invocation), \ + PCAP_DBUS_ERROR_NAME, \ + stc_err_strs[-(err_num)]) + +static const gchar *stc_err_strs[] = { + "ERROR_NONE", + "FAIL", + "DB_FAILED", + "OUT_OF_MEMORY", + "INVALID_PARAMETER", + "NO_DATA", + "ALREADY_DATA", + "UNINITIALIZED", + "PERMISSION_DENIED", + "NOTIMPL" +}; + +gboolean __validate_pcap(stc_pcap_s *pcap) +{ + __STC_LOG_FUNC_ENTER__; + + if (pcap == NULL) { + __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE + return FALSE; //LCOV_EXCL_LINE + } + + if (pcap->ifname == NULL || + pcap->ifname[0] == '\0') { + __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE + return FALSE; //LCOV_EXCL_LINE + } + + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +static void __stc_extract_pcap(const char *key, GVariant *value, + void *user_data) +{ + stc_pcap_s *pcap = (stc_pcap_s *) user_data; + if (pcap == NULL) { + __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE + return; //LCOV_EXCL_LINE + } + + if (!g_strcmp0(key, STC_PCAP_IFNAME)) { + guint str_length; + const gchar *str = g_variant_get_string(value, &str_length); + pcap->ifname = g_strdup(str); + STC_LOGD("ifname: [%s]", pcap->ifname); + + } else if (!g_strcmp0(key, STC_PCAP_NFLOG_GROUP)) { + pcap->nflog_group = g_variant_get_uint32(value); + STC_LOGD("nflog group: [%d]", pcap->nflog_group); + + } else { + STC_LOGD("Unknown select rule"); //LCOV_EXCL_LINE + } +} + +gboolean handle_pcap_start(StcPcap *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantIter *iter = NULL; + stc_pcap_s pcap; + int ret = STC_ERROR_NONE; + + memset(&pcap, 0, sizeof(stc_pcap_s)); + + g_variant_get(parameters, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_pcap, + &pcap); + g_variant_iter_free(iter); + } + + if (__validate_pcap(&pcap) == FALSE) { + STC_PCAP_DBUS_REPLY_ERROR(invocation, //LCOV_EXCL_LINE + STC_ERROR_INVALID_PARAMETER); + __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE + return TRUE; + } + + ret = stc_plugin_pcap_register_loop_pcap(pcap.ifname, pcap.nflog_group); + if (ret != STC_ERROR_NONE) { + STC_PCAP_DBUS_REPLY_ERROR(invocation, ret); //LCOV_EXCL_LINE + __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE + return TRUE; + } + + STC_DBUS_REPLY_ERROR_NONE(invocation); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_pcap_stop(StcPcap *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantIter *iter = NULL; + stc_pcap_s pcap; + int ret = STC_ERROR_NONE; + + memset(&pcap, 0, sizeof(stc_pcap_s)); + + g_variant_get(parameters, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_pcap, + &pcap); + g_variant_iter_free(iter); + } + + if (__validate_pcap(&pcap) == FALSE) { + STC_PCAP_DBUS_REPLY_ERROR(invocation, //LCOV_EXCL_LINE + STC_ERROR_INVALID_PARAMETER); + __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE + return TRUE; + } + + ret = stc_plugin_pcap_unregister_loop_pcap(pcap.ifname, pcap.nflog_group); + if (ret != STC_ERROR_NONE) { + STC_PCAP_DBUS_REPLY_ERROR(invocation, ret); //LCOV_EXCL_LINE + __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE + return TRUE; + } + + STC_DBUS_REPLY_ERROR_NONE(invocation); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} -- 2.7.4