Add packet capture functions
[platform/core/connectivity/stc-manager.git] / plugin / pcap / stc-plugin-pcap.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "stc-plugin-pcap.h"
18
19 //LCOV_EXCL_START
20 static GHashTable *g_pcap_tables = NULL;
21 static bool g_pcap_start_fm = false;
22 static struct timeval g_pcap_tv = { 0, };
23
24 static void __pcap_data_free(gpointer value)
25 {
26         stc_pcap_data_s *data = (stc_pcap_data_s *)value;
27
28         g_thread_unref(data->thread);
29
30         FREE(data->name);
31         FREE(data);
32 }
33
34 /*
35 static void __pcap_data_info(const u_char *packet, int len)
36 {
37         GString *data;
38
39         data = g_string_sized_new(len);
40         if (data == NULL)
41                 return;
42
43         while(len--)
44                 g_string_append_printf(data, "%02x", *(packet++));
45
46         STC_LOGD("[%s]", g_string_free(data, FALSE));
47 }
48 */
49
50 static void __pcap_ntp_time_info(uint32_t s, char *time)
51 {
52         time_t seconds; 
53         char *curr = NULL;
54         int len = 0;
55         uint32_t sec = ntohl(s);
56
57         if (sec) {
58                 seconds = sec - NTP_JAN_1970;
59                 curr = ctime(&seconds);
60                 len = strlen(curr);
61                 curr[len - 1] = '\0';
62
63                 snprintf(time, len, "%s", curr);
64         } else {
65                 snprintf(time, 10, "00:00:00");
66         }
67 }
68
69 static void __pcap_ntp_refid_info(ntp_t *ntp_h, char *refid)
70 {
71         switch (ntp_h->stratum) {
72         case NTP_STRATUM_UNSPECIFIED:
73                 snprintf(refid, BUFF_SIZE_ID, "%s", "(unspec)");
74                 break;
75         case NTP_STRATUM_PRIM_REF:
76                 snprintf(refid, BUFF_SIZE_ID, "%s", "(prim_ref)");
77                 break;
78         case NTP_STRATUM_INFO_QUERY:
79                 snprintf(refid, BUFF_SIZE_ID, "%s INFO_QEURY",
80                         inet_ntoa(*((struct in_addr *)&ntp_h->refid)));
81                 break;
82         case NTP_STRATUM_INFO_REPLY:
83                 snprintf(refid, BUFF_SIZE_ID, "%s INFO_REPLY",
84                         inet_ntoa(*((struct in_addr *)&ntp_h->refid)));
85                 break;
86         default:
87                 snprintf(refid, BUFF_SIZE_ID, "%s",
88                         inet_ntoa(*((struct in_addr *)&ntp_h->refid)));
89                 break;
90         }
91 }
92
93 static uint16_t __pcap_ntp_fraction_info(uint16_t f)
94 {
95         uint16_t fraction;
96         double ff;
97
98         ff = ntohs(f) / 65536.0;
99         fraction = (uint16_t)(ff * 1000000.0);
100
101         return fraction;
102 }
103
104 static void __pcap_ntp_info(const u_char *packet)
105 {
106         ntp_t *ntp_h = (ntp_t *)(packet +
107                 SIZE_ETHER_HEADER + SIZE_IP_HEADER + SIZE_UDP_HEADER);
108         char refid[BUFF_SIZE_ID];
109         char reftime[BUFF_SIZE_TIME];
110         char orgtime[BUFF_SIZE_TIME];
111         char rectime[BUFF_SIZE_TIME];
112         char xmttime[BUFF_SIZE_TIME];
113
114         __pcap_ntp_refid_info(ntp_h, refid);
115         __pcap_ntp_time_info(ntp_h->reftime.second, reftime);
116         __pcap_ntp_time_info(ntp_h->orgtime.second, orgtime);
117         __pcap_ntp_time_info(ntp_h->rectime.second, rectime);
118         __pcap_ntp_time_info(ntp_h->xmttime.second, xmttime);
119
120         STC_LOGD("Flags[0x%02x] Stratum[%u] Poll[%u:%us] Precision[%u] "
121                 "Root delay[%u.%06us] Root dispersion[%u.%06us] Ref ID[%s]",
122                 ntp_h->flags, ntp_h->stratum, ntp_h->poll,
123                 ntp_h->precision, 1 << ntp_h->precision,
124                 ntohs(ntp_h->rootdelay.second),
125                 __pcap_ntp_fraction_info(ntp_h->rootdelay.fraction),
126                 ntohs(ntp_h->rootdisp.second),
127                 __pcap_ntp_fraction_info(ntp_h->rootdisp.fraction),
128                 refid);
129
130         STC_LOGD("Reference[%s] Origin[%s] Receive[%s] Transmit[%s]",
131                 reftime, orgtime, rectime, xmttime);
132 }
133
134 static const char *__pcap_dhcp_client_id_info(uint8_t data)
135 {
136         char *info = NULL;
137
138         switch (data) {
139         case DHCP_CLIENT_ID_ETHERNET:
140                 info = "Ethernet";
141                 break;
142         case DHCP_CLIENT_ID_IEEE802:
143                 info = "IEEE 802 Networks";
144                 break;
145         case DHCP_CLIENT_ID_ARCNET:
146                 info = "ARCNET";
147                 break;
148         case DHCP_CLIENT_ID_LOCALTALK:
149                 info = "LocalTalk";
150                 break;
151         case DHCP_CLIENT_ID_LOCALNET:
152                 info = "LocalNet";
153                 break;
154         case DHCP_CLIENT_ID_SMDS:
155                 info = "SMDS";
156                 break;
157         case DHCP_CLIENT_ID_FRAMERELAY:
158                 info = "Frame Relay";
159                 break;
160         case DHCP_CLIENT_ID_ATM1:
161                 info = "ATM(Async Transfer Mode)";
162                 break;
163         case DHCP_CLIENT_ID_HDLC:
164                 info = "HDLC";
165                 break;
166         case DHCP_CLIENT_ID_FIBRECHANNEL:
167                 info = "Fibre Channel";
168                 break;
169         case DHCP_CLIENT_ID_ATM2:
170                 info = "ATM(Async Transfer Mode)";
171                 break;
172         case DHCP_CLIENT_ID_SERIALLINE:
173                 info = "Serial Line";
174                 break;
175         default:
176                 info = "Unknown";
177                 break;
178         }
179
180         return info;
181 }
182
183 static const char *__pcap_dhcp_msg_type_info(uint8_t type)
184 {
185         char *info = NULL;
186
187         switch (type) {
188         case DHCP_MSG_TYPE_DISCOVER:
189                 info = "Discover";
190                 break;
191         case DHCP_MSG_TYPE_OFFER:
192                 info = "Offer";
193                 break;
194         case DHCP_MSG_TYPE_REQUEST:
195                 info = "Request";
196                 break;
197         case DHCP_MSG_TYPE_DECLINE:
198                 info = "Decline";
199                 break;
200         case DHCP_MSG_TYPE_ACK:
201                 info = "ACK";
202                 break;
203         case DHCP_MSG_TYPE_NAK:
204                 info = "NAK";
205                 break;
206         case DHCP_MSG_TYPE_RELEASE:
207                 info = "Release";
208                 break;
209         case DHCP_MSG_TYPE_INFORM:
210                 info = "Inform";
211                 break;
212         default:
213                 info = "Unknown";
214                 break;
215         }
216
217         return info;
218 }
219
220 static void __pcap_bootp_magic_info(uint32_t magic,
221                                         uint8_t *moption, u_int16_t len)
222 {
223         if (ntohl(magic) == BOOTP_MAGIC_DHCP) {
224                 char buf[BOOTP_MOPTION_LEN];
225                 uint8_t *opt = moption;
226
227                 STC_LOGD("Magic cookie[DHCP]");
228
229                 while(len > 0) {
230                         uint8_t tag = opt[0];
231                         uint8_t length = opt[1];
232                         uint8_t *data = &opt[2];
233                         char addr[BUFF_SIZE_IP];
234                         char host[BUFF_SIZE_HOST];
235
236                         switch (tag) {
237                         case DHCP_TAG_SUBNET_MASK:
238                                 inet_ntop(AF_INET, (struct in_addr *)data,
239                                         addr, BUFF_SIZE_IP);
240                                 STC_LOGD("Subnet mask[%s]", addr);
241                                 break;
242                         case DHCP_TAG_ROUTER:
243                                 inet_ntop(AF_INET, (struct in_addr *)data,
244                                         addr, BUFF_SIZE_IP);
245                                 STC_LOGD("Router[%s]", addr);
246                                 break;
247                         case DHCP_TAG_DNS:
248                                 inet_ntop(AF_INET, (struct in_addr *)data,
249                                         addr, BUFF_SIZE_IP);
250                                 STC_LOGD("Domain name server[%s]", addr);
251                                 break;
252                         case DHCP_TAG_HOST_NAME:
253                                 snprintf(buf, ((length < BOOTP_MOPTION_LEN) ?
254                                                 (length + 1) : BOOTP_MOPTION_LEN), "%s", (char *)data);
255                                 STC_LOGD("Host name[%s]", buf);
256                                 break;
257                         case DHCP_TAG_REQUESTED_IP:
258                                 inet_ntop(AF_INET, (struct in_addr *)data,
259                                         addr, BUFF_SIZE_IP);
260                                 STC_LOGD("Requested IP[%s]", addr);
261                                 break;
262                         case DHCP_TAG_IP_LEASE_TIME:
263                                 STC_LOGD("IP address lease time[%us]",
264                                         ntohl(*(uint32_t *)data));
265                                 break;
266                         case DHCP_TAG_MSG_TYPE:
267                                 STC_LOGD("DHCP message type[%u:%s]", *data,
268                                         __pcap_dhcp_msg_type_info(*data));
269                                 break;
270                         case DHCP_TAG_SERVER_ID:
271                                 inet_ntop(AF_INET, (struct in_addr *)data,
272                                         addr, BUFF_SIZE_IP);
273                                 STC_LOGD("DHCP server identifier[%s]", addr);
274                                 break;
275                         case DHCP_TAG_MSG_SIZE:
276                                 STC_LOGD("Maximum DHCP message size[%u]",
277                                         ntohs(*(uint16_t *)data));
278                                 break;
279                         case DHCP_TAG_CLIENT_ID:
280                                 STC_LOGD("Client identifier HW type[0x%02x:%s]", *data,
281                                         __pcap_dhcp_client_id_info(*data));
282                                 if (*data == DHCP_CLIENT_ID_ETHERNET) {
283                                         g_strlcpy(host,
284                                                 ether_ntoa((const struct ether_addr *)&data[1]),
285                                                 sizeof(host));
286                                         STC_LOGD("Client identifier MAC[%s]", host);
287                                 }
288                                 break;
289                         case DHCP_TAG_END:
290                                 STC_LOGD("End");
291                                 return;
292                         default:
293                                 STC_LOGD("Unknown[%u]", tag);
294                                 break;
295                         }
296
297                         opt += (2 + length);
298                         len -= (2 + length);
299                 }
300         }
301 }
302
303 static const char *__pcap_bootp_op_info(uint8_t op)
304 {
305         char *info = NULL;
306
307         switch (op) {
308         case BOOTP_REQUEST:
309                 info = "Request";
310                 break;
311         case BOOTP_REPLY:
312                 info = "Reply";
313                 break;
314         default:
315                 info = "Unknown";
316                 break;
317         }
318
319         return info;
320 }
321
322 static void __pcap_bootp_info(const u_char *packet)
323 {
324         udp_t *udp_h = (udp_t *)(packet
325                 + SIZE_ETHER_HEADER + SIZE_IP_HEADER);
326         bootp_t *bootp_h = (bootp_t *)(packet +
327                 SIZE_ETHER_HEADER + SIZE_IP_HEADER + SIZE_UDP_HEADER);
328         char ciaddr[BUFF_SIZE_IP];
329         char yiaddr[BUFF_SIZE_IP];
330         char siaddr[BUFF_SIZE_IP];
331         char giaddr[BUFF_SIZE_IP];
332         char chaddr[BUFF_SIZE_HOST];
333         u_int16_t len;
334
335         inet_ntop(AF_INET, &bootp_h->ciaddr, ciaddr, BUFF_SIZE_IP);
336         inet_ntop(AF_INET, &bootp_h->yiaddr, yiaddr, BUFF_SIZE_IP);
337         inet_ntop(AF_INET, &bootp_h->siaddr, siaddr, BUFF_SIZE_IP);
338         inet_ntop(AF_INET, &bootp_h->giaddr, giaddr, BUFF_SIZE_IP);
339
340         g_strlcpy(chaddr,
341                 ether_ntoa((const struct ether_addr *)bootp_h->chaddr),
342                 sizeof(chaddr));
343
344         STC_LOGD("Message type[%u:%s] HW type[0x%02x] HW len[%u] Hops[%u] "
345                 "Transaction ID[0x%08x] Seconds elapsed[%u] Flags[0x%04x]",
346                 bootp_h->op, __pcap_bootp_op_info(bootp_h->op),
347                 bootp_h->htype, bootp_h->hlen, bootp_h->hops,
348                 ntohl(bootp_h->xid), ntohs(bootp_h->secs), ntohs(bootp_h->flags));
349
350         STC_LOGD("Client[%s] Your(client)[%s] Next server[%s] "
351                 "Relay agent[%s] Client MAC[%s]",
352                 ciaddr, yiaddr, siaddr, giaddr, chaddr);
353
354         len = ntohs(udp_h->len);
355         __pcap_bootp_magic_info(bootp_h->magic, bootp_h->moption, len);
356 }
357
358 static char *__pcap_dns_type_info(uint16_t type)
359 {
360         char *info = NULL;
361
362         switch (type) {
363         case DNS_QTYPE_A:
364                 info = "A";
365                 break;
366         case DNS_QTYPE_CNAME:
367                 info = "CNAME";
368                 break;
369         case DNS_QTYPE_AAAA:
370                 info = "AAAA";
371                 break;
372         default:
373                 info = "Unknown";
374                 break;
375         }
376
377         return info;
378 }
379
380 static char *__pcap_dns_class_info(uint16_t class)
381 {
382         char *info = NULL;
383
384         switch (class) {
385         case DNS_QCLASS_IN:
386                 info = "IN";
387                 break;
388         case DNS_QCLASS_CHAOS:
389                 info = "CHAOS";
390                 break;
391         case DNS_QCLASS_HS:
392                 info = "HS";
393                 break;
394         case DNS_QCLASS_ANY:
395                 info = "ANY";
396                 break;
397         default:
398                 info = "Unknown";
399                 break;
400         }
401
402         return info;
403 }
404
405 static uint8_t * __pcap_dns_name_info(uint8_t *dns_h,
406                                 uint8_t *data, u_char *name)
407 {
408         uint8_t *sec = data;
409         u_char *dname = name;
410         uint8_t *nxt = NULL;
411
412         *name = '\0';
413         while (1) {
414                 if ((*sec & 0xC0)) {
415                         nxt = sec + 2;
416                         sec = (uint8_t *)dns_h +
417                                 (htons(*(uint16_t *)sec) & 0x3FFF);
418                 } else {
419                         if (*sec == 0) {
420                                 *dname = '\0';
421                                 sec += 1;
422                                 break;
423                         }
424
425                         if (dname - name + *sec + 1 > BUFF_SIZE_NAME - 1) {
426                                 *name = '\0';
427                                 return NULL;
428                         }
429
430                         memcpy(dname, sec + 1, *sec);
431                         dname += *sec;
432                         sec += *sec + 1;
433                         *dname = '.';
434                         dname++;
435                 }
436         }
437
438         *(--dname) = '\0';
439
440         if (nxt == NULL)
441                 nxt = sec;
442
443         return (uint8_t *)nxt;
444 }
445
446 static void __pcap_dns_data_info(const u_char *packet)
447 {
448         dns_t *dns_h = (dns_t *)(packet +
449                 SIZE_ETHER_HEADER + SIZE_IP_HEADER +
450                 SIZE_UDP_HEADER);
451         uint8_t *data = (uint8_t *)(packet +
452                 SIZE_ETHER_HEADER + SIZE_IP_HEADER +
453                 SIZE_UDP_HEADER + SIZE_DNS_HEADER);
454         uint16_t qdcount = ntohs(dns_h->questions);
455         uint16_t ancount = ntohs(dns_h->answerRR);
456         int i = 0;
457
458         for (i = 0; i < qdcount; ++i) {
459                 u_char name[BUFF_SIZE_NAME];
460                 uint16_t type;
461                 uint16_t class;
462
463                 if (i == 0)
464                         STC_LOGD("[Queries]");
465
466                 data = __pcap_dns_name_info((uint8_t *)dns_h, data, name);
467                 if (data == NULL)
468                         return;
469
470                 type = ntohs(*(uint16_t *)&data[0]);
471                 class = ntohs(*(uint16_t *)&data[2]);
472
473                 STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s]",
474                         name, type, __pcap_dns_type_info(type),
475                         class, __pcap_dns_class_info(class));
476
477                 data += 4;
478         }
479
480         for (i = 0; i < ancount; ++i) {
481                 u_char name[BUFF_SIZE_NAME];
482                 u_char cname[BUFF_SIZE_NAME];
483                 uint16_t type;
484                 uint16_t class;
485                 uint32_t ttl;
486                 uint16_t length;
487                 char ip[BUFF_SIZE_IP];
488
489                 if (i == 0)
490                         STC_LOGD("[Answers]");
491
492                 data = __pcap_dns_name_info((uint8_t *)dns_h, data, name);
493                 if (data == NULL)
494                         return;
495
496                 type = ntohs(*(uint16_t *)&data[0]);
497                 class = ntohs(*(uint16_t *)&data[2]);
498                 ttl = ntohl(*(uint32_t *)&data[4]);
499                 length = ntohs(*(uint16_t *)&data[8]);
500
501                 if (class == DNS_QCLASS_IN) {
502                         switch (type) {
503                         case DNS_QTYPE_A:
504                                 inet_ntop(AF_INET, (struct in_addr *)&data[10],
505                                         ip, BUFF_SIZE_IP);
506                                 STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s] "
507                                         "TTL[%u] Data length[%u] Address[%s]",
508                                         name, type, __pcap_dns_type_info(type),
509                                         class, __pcap_dns_class_info(class),
510                                         ttl, length, ip);
511                                 break;
512                         case DNS_QTYPE_CNAME:
513                                 __pcap_dns_name_info((uint8_t *)dns_h, &data[10], cname);
514                                 if (data == NULL)
515                                         return;
516                                 STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s] "
517                                         "TTL[%u] Data length[%u] CName[%s]",
518                                         name, type, __pcap_dns_type_info(type),
519                                         class, __pcap_dns_class_info(class),
520                                         ttl, length, cname);
521                                 break;
522                         case DNS_QTYPE_AAAA:
523                                 break;
524                         default:
525                                 STC_LOGD("Name[%s] Type[%u:%s] Class[0x%04x:%s] "
526                                         "TTL[%u] Data length[%u]",
527                                         name, type, __pcap_dns_type_info(type),
528                                         class, __pcap_dns_class_info(class),
529                                         ttl, length);
530                                 break;
531                         }
532                 }
533
534                 data += (length + 10);
535         }
536 }
537
538 static void __pcap_dns_info(const u_char *packet)
539 {
540         dns_t *dns_h = (dns_t *)(packet +
541                 SIZE_ETHER_HEADER + SIZE_IP_HEADER + SIZE_UDP_HEADER);
542
543         STC_LOGD("Transaction ID[0x%x] Flags[0x%x] Questions[%u] "
544                 "Answer RRs[%u] Authority RRs[%u] Additional RRs[%u]",
545                 ntohs(dns_h->id), ntohs(dns_h->flags),
546                 ntohs(dns_h->questions), ntohs(dns_h->answerRR),
547                 ntohs(dns_h->authorityRR), ntohs(dns_h->additionalRR));
548
549         __pcap_dns_data_info(packet);
550 }
551
552 static const char *__pcap_icmp_code_info(u_int8_t type, u_int8_t code)
553 {
554         char *info = NULL;
555
556         switch (type) {
557         case ICMP_DEST_UNREACH:
558                 switch (code) {
559                 case ICMP_NET_UNREACH:
560                         info = "Network Unreachable";
561                         break;
562                 case ICMP_HOST_UNREACH:
563                         info = "Host Unreachable";
564                         break;
565                 case ICMP_PROT_UNREACH:
566                         info = "Protocol Unreachable";
567                         break;
568                 case ICMP_PORT_UNREACH:
569                         info = "Port Unreachable";
570                         break;
571                 case ICMP_FRAG_NEEDED:
572                         info = "Fragmentation Needed/DF set";
573                         break;
574                 case ICMP_SR_FAILED:
575                         info = "Source Route failed";
576                         break;
577                 case ICMP_NET_UNKNOWN:
578                         break;
579                 case ICMP_HOST_UNKNOWN:
580                         break;
581                 case ICMP_HOST_ISOLATED:
582                         break;
583                 case ICMP_NET_ANO:
584                         break;
585                 case ICMP_HOST_ANO:
586                         break;
587                 case ICMP_NET_UNR_TOS:
588                         break;
589                 case ICMP_HOST_UNR_TOS:
590                         break;
591                 case ICMP_PKT_FILTERED:
592                         info = "Packet filtered";
593                         break;
594                 case ICMP_PREC_VIOLATION:
595                         info = "Precedence violation";
596                         break;
597                 case ICMP_PREC_CUTOFF:
598                         info = "Precedence cut off";
599                         break;
600                 default:
601                         info = "Unknown";
602                         break;
603                 }
604                 break;
605         case ICMP_REDIRECT:
606                 switch (code) {
607                 case ICMP_REDIR_NET:
608                         info = "Redirect Net";
609                         break;
610                 case ICMP_REDIR_HOST:
611                         info = "Redirect Host";
612                         break;
613                 case ICMP_REDIR_NETTOS:
614                         info = "Redirect Net for TOS";
615                         break;
616                 case ICMP_REDIR_HOSTTOS:
617                         info = "Redirect Host for TOS";
618                         break;
619                 default:
620                         info = "Unknown";
621                         break;
622                 }
623                 break;
624         case ICMP_TIME_EXCEEDED:
625                 switch (code) {
626                 case ICMP_EXC_TTL:
627                         info = "TTL count exceeded";
628                         break;
629                 case ICMP_EXC_FRAGTIME:
630                         info = "Fragment Reass time exceeded";
631                         break;
632                 default:
633                         info = "Unknown";
634                         break;
635                 }
636                 break;
637         default:
638                 info = "Unknown";
639                 break;
640         }
641
642         return info;
643 }
644
645 static const char *__pcap_icmp_type_info(u_int8_t type)
646 {
647         char *info = NULL;
648
649         switch (type) {
650         case ICMP_ECHOREPLY:
651                 info = "Echo Reply";
652                 break;
653         case ICMP_DEST_UNREACH:
654                 info = "Destination Unreachable";
655                 break;
656         case ICMP_SOURCE_QUENCH:
657                 info = "Source Quench";
658                 break;
659         case ICMP_REDIRECT:
660                 info = "Redirect";
661                 break;
662         case ICMP_ECHO:
663                 info = "Echo Request";
664                 break;
665         case ICMP_TIME_EXCEEDED:
666                 info = "Time Exceeded";
667                 break;
668         case ICMP_PARAMETERPROB:
669                 info = "Parameter Problem";
670                 break;
671         case ICMP_TIMESTAMP:
672                 info = "Timestamp Request";
673                 break;
674         case ICMP_TIMESTAMPREPLY:
675                 info = "Timestamp Reply";
676                 break;
677         case ICMP_INFO_REQUEST:
678                 info = "Information Request";
679                 break;
680         case ICMP_INFO_REPLY:
681                 info = "Information Reply";
682                 break;
683         case ICMP_ADDRESS:
684                 info = "Address Mask Request";
685                 break;
686         case ICMP_ADDRESSREPLY:
687                 info = "Address Mask Reply";
688                 break;
689         default:
690                 info = "Unknown";
691                 break;
692         }
693
694         return info;
695 }
696
697 static void __pcap_icmp_info(const u_char *packet)
698 {
699         icmp_t *icmp_h = (icmp_t *)(packet +
700                 SIZE_ETHER_HEADER + SIZE_IP_HEADER);
701
702         STC_LOGD("Type[%u:%s] Code[%u:%s] Checksum[0x%x]",
703                 icmp_h->type, __pcap_icmp_type_info(icmp_h->type),
704                 icmp_h->code, __pcap_icmp_code_info(icmp_h->type, icmp_h->code),
705                 ntohs(icmp_h->checksum));
706 }
707
708 static void __pcap_tcp_info(const u_char *packet)
709 {
710         tcp_t *tcp_h = (tcp_t *)(packet +
711                 SIZE_ETHER_HEADER + SIZE_IP_HEADER);
712         u_int16_t source = ntohs(tcp_h->source);
713         u_int16_t dest = ntohs(tcp_h->dest);
714
715         STC_LOGD("Source[%u] Destination[%u] Sequence[%u] "
716                 "Acknowledgment seq[%u] Window size[%u] ",
717                 ntohs(tcp_h->source), ntohs(tcp_h->dest),
718                 ntohl(tcp_h->seq), ntohl(tcp_h->ack_seq),
719                 ntohs(tcp_h->window));
720
721         STC_LOGD("Checksum[0x%x] URG[%u] ACK[%u] PUSH[%u] "
722                 "RST[%u] SYN[%u] FIN[%u]",
723                 ntohs(tcp_h->check),
724                 tcp_h->urg, tcp_h->ack, tcp_h->psh,
725                 tcp_h->rst, tcp_h->syn, tcp_h->fin);
726
727         if (IS_SRC_OR_DST_PORT(PORT_DNS))
728                 __pcap_dns_info(packet);
729 }
730
731 static void __pcap_udp_info(const u_char *packet)
732 {
733         udp_t *udp_h = (udp_t *)(packet
734                 + SIZE_ETHER_HEADER + SIZE_IP_HEADER);
735         u_int16_t source = ntohs(udp_h->source);
736         u_int16_t dest = ntohs(udp_h->dest);
737
738         STC_LOGD("Source[%u] Destination[%u] Len[%u] Checksum[0x%x]",
739                 source, dest, ntohs(udp_h->len), ntohs(udp_h->check));
740
741         if (IS_SRC_OR_DST_PORT(PORT_DNS))
742                 __pcap_dns_info(packet);
743         else if (IS_SRC_OR_DST_PORT(PORT_BOOTP_C) ||
744                 IS_SRC_OR_DST_PORT(PORT_BOOTP_S))
745                 __pcap_bootp_info(packet);
746         else if (IS_SRC_OR_DST_PORT(PORT_NTP))
747                 __pcap_ntp_info(packet);        
748 }
749
750 static const char *__pcap_eth_type_info(u_int16_t type)
751 {
752         char *info = NULL;
753
754         switch (type) {
755         case ETHERTYPE_IP:
756                 info = "IP";
757                 break;
758         case ETHERTYPE_IPV6:
759                 info = "IPv6";
760                 break;
761         case ETHERTYPE_ARP:
762                 info = "ARP";
763                 break;
764         case ETHERTYPE_REVARP:
765                 info = "REVARP";
766                 break;
767         case ETHERTYPE_LOOPBACK:
768                 info = "LOOPBACK";
769                 break;
770         default:
771                 info = "Unknown";
772                 break;
773         }
774
775         return info;
776 }
777
778 static const char *__pcap_arp_opcode_info(u_int16_t opcode)
779 {
780         char *info = NULL;
781
782         switch (opcode) {
783         case ARP_REQUEST:
784                 info = "Request";
785                 break;
786         case ARP_REPLY:
787                 info = "Reply";
788                 break;
789         case ARP_RREQUEST:
790                 info = "RRequest";
791                 break;
792         case ARP_RREPLY:
793                 info = "RReply";
794                 break;
795         default:
796                 info = "Unknown";
797                 break;
798         }
799
800         return info;
801 }
802
803 static void __pcap_arp_info(const u_char *packet)
804 {
805         arp_t *arp_h = (arp_t *)(packet + SIZE_ETHER_HEADER);
806         u_int8_t *sha = (u_int8_t *)(packet +
807                 SIZE_ETHER_HEADER + SIZE_ARP_HEADER);
808         u_int8_t *spa = (u_int8_t *)(sha + arp_h->ar_hln);
809         u_int8_t *tha = (u_int8_t *)(spa + arp_h->ar_pln);
810         u_int8_t *tpa = (u_int8_t *)(tha + arp_h->ar_hln);
811         u_int16_t ar_op = ntohs(arp_h->ar_op);
812         char sma[BUFF_SIZE_HOST];
813         char sia[BUFF_SIZE_IP];
814         char tma[BUFF_SIZE_HOST];
815         char tia[BUFF_SIZE_IP];
816         u_int16_t ar_pro;
817
818         g_strlcpy(sma,
819                 ether_ntoa((const struct ether_addr *)sha),
820                 sizeof(sma));
821         g_strlcpy(tma,
822                 ether_ntoa((const struct ether_addr *)tha),
823                 sizeof(tma));
824
825         inet_ntop(AF_INET, (struct in_addr *)spa, sia, BUFF_SIZE_IP);
826         inet_ntop(AF_INET, (struct in_addr *)tpa, tia, BUFF_SIZE_IP);
827
828         ar_pro = ntohs(arp_h->ar_pro);
829
830         STC_LOGD("HW type[%u] Protocol type[0x%04x:%s] "
831                 "HW size[%u] Protocol size[%u] Opcode[%u:%s] ",
832                 ntohs(arp_h->ar_hrd), ar_pro,
833                 __pcap_eth_type_info(ar_pro),
834                 arp_h->ar_hln, arp_h->ar_pln,
835                 ar_op, __pcap_arp_opcode_info(ar_op));
836
837         STC_LOGD("Sender MAC[%s] Sender IP[%s] "
838                 "Target MAC[%s] Target IP[%s]",
839                 sma, sia, tma, tia);
840 }
841
842 static const char *__pcap_ip_protocol_info(u_int8_t p)
843 {
844         char *info = NULL;
845
846         switch (p) {
847         case IPPROTO_IP:
848                 info = "IP";
849                 break;
850         case IPPROTO_ICMP:
851                 info = "ICMP";
852                 break;
853         case IPPROTO_IPIP:
854                 info = "IPIP";
855                 break;
856         case IPPROTO_TCP:
857                 info = "TCP";
858                 break;
859         case IPPROTO_UDP:
860                 info = "UDP";
861                 break;
862         case IPPROTO_IPV6:
863                 info = "IPv6";
864                 break;
865         case IPPROTO_ICMPV6:
866                 info = "ICMPv6";
867                 break;
868         default:
869                 info = "Unknown";
870                 break;
871         }
872
873         return info;
874 }
875
876 static void __pcap_ipv6_info(const u_char *packet)
877 {
878         ip6_t *ip6_h = (ip6_t *)(packet + SIZE_ETHER_HEADER);
879         char ip6_src[BUFF_SIZE_IP6];
880         char ip6_dst[BUFF_SIZE_IP6];
881
882         inet_ntop(AF_INET6, &ip6_h->ip6_src, ip6_src, BUFF_SIZE_IP6);
883         inet_ntop(AF_INET6, &ip6_h->ip6_dst, ip6_dst, BUFF_SIZE_IP6);
884
885         STC_LOGD("Flow[0x%08x] Payload len[%u] Next hdr[%u:%s] "
886                 "Hop limit[%u] Source[%s] Destination[%s]",
887                 ntohl(ip6_h->ip6_flow), ntohs(ip6_h->ip6_plen),
888                 ip6_h->ip6_nxt, __pcap_ip_protocol_info(ip6_h->ip6_nxt),
889                 ip6_h->ip6_hlim, ip6_src, ip6_dst);
890
891         switch (ip6_h->ip6_nxt) {
892         case IPPROTO_IP:
893                 break;
894         case IPPROTO_ICMP:
895                 break;
896         case IPPROTO_IPIP:
897                 break;
898         case IPPROTO_TCP:
899                 break;
900         case IPPROTO_UDP:
901                 break;
902         case IPPROTO_IPV6:
903                 break;
904         case IPPROTO_ICMPV6:
905                 break;
906         default:
907                 break;
908         }
909 }
910
911 static void __pcap_ip_info(const u_char *packet)
912 {
913         ip_t *ip_h = (ip_t *)(packet + SIZE_ETHER_HEADER);
914         char ip_src[BUFF_SIZE_IP];
915         char ip_dst[BUFF_SIZE_IP];
916
917         inet_ntop(AF_INET, &ip_h->ip_src, ip_src, BUFF_SIZE_IP);
918         inet_ntop(AF_INET, &ip_h->ip_dst, ip_dst, BUFF_SIZE_IP);
919
920         STC_LOGD("Header len[%u] TOS[0x%02x] Total len[%u] "
921                 "ID[0x%04x] Flags[0x%02x] TTL[%u] Protocol[%u:%s] "
922                 "Checksum[0x%04x] Source[%s] Destination[%s]",
923                 ip_h->ip_hl << 2, ip_h->ip_tos,
924                 ntohs(ip_h->ip_len), ntohs(ip_h->ip_id),
925                 (ntohs(ip_h->ip_off) & 0xe000) >> 13,
926                 ip_h->ip_ttl, ip_h->ip_p,
927                 __pcap_ip_protocol_info(ip_h->ip_p),
928                 ntohs(ip_h->ip_sum), ip_src, ip_dst);
929
930         switch (ip_h->ip_p) {
931         case IPPROTO_ICMP:
932                 __pcap_icmp_info(packet);
933                 break;
934         case IPPROTO_TCP:
935                 __pcap_tcp_info(packet);
936                 break;
937         case IPPROTO_UDP:
938                 __pcap_udp_info(packet);
939                 break;
940         default:
941                 break;
942         }
943 }
944
945 static void __pcap_eth_info(const u_char *packet)
946 {
947         eth_t *eth_h = (eth_t *)packet;
948         u_int8_t *eth_shost = eth_h->ether_shost;
949         u_int8_t *eth_dhost = eth_h->ether_dhost;
950         char shost[BUFF_SIZE_HOST];
951         char dhost[BUFF_SIZE_HOST];
952         u_int16_t ether_type;
953
954         g_strlcpy(shost,
955                 ether_ntoa((const struct ether_addr *)eth_shost),
956                 sizeof(shost));
957
958         g_strlcpy(dhost,
959                 ether_ntoa((const struct ether_addr *)eth_dhost),
960                 sizeof(dhost));
961
962         ether_type = ntohs(eth_h->ether_type);
963
964         STC_LOGD("Source[%s] Destination[%s] Type[0x%04x:%s]",
965                 shost, dhost, ether_type, __pcap_eth_type_info(ether_type));
966 }
967
968 static void __pcap_fm_info(const struct pcap_pkthdr *pkthdr)
969 {
970         char *curr = NULL;
971         int len = 0;
972         struct timeval ts = pkthdr->ts;
973         __time_t tv_sec = ts.tv_sec;
974         __suseconds_t tv_usec = tv_usec;
975
976         if (g_pcap_start_fm == false) {
977                 g_pcap_tv = ts;
978                 g_pcap_start_fm = true;
979         }
980
981         curr = ctime((const time_t *)&tv_sec);
982         len = strlen(curr);
983         curr[len - 1] = '\0';
984
985         STC_LOGD("Arrival time[%s] Timeval[%.06f] "
986                 "Frame len[%u] Capture len[%u]", curr,
987                 (float)((tv_sec - g_pcap_tv.tv_sec) * 1000000 +
988                 (tv_usec - g_pcap_tv.tv_usec)) / 1000000,
989                 pkthdr->len, pkthdr->caplen);
990 }
991
992 static void __pcap_handler(u_char *param,
993                         const struct pcap_pkthdr *pkthdr,
994                         const u_char *packet) {
995         eth_t *eth_h;
996         unsigned short eth_type;
997         /* int len = pkthdr->len; */
998
999         __pcap_fm_info(pkthdr);
1000
1001         eth_h = (eth_t *)packet;
1002         __pcap_eth_info(packet);
1003
1004         eth_type = ntohs(eth_h->ether_type);
1005         switch (eth_type) {
1006         case ETHERTYPE_IP:
1007                 __pcap_ip_info(packet);
1008                 /* __pcap_data_info(pcaket, len); */
1009                 break;
1010         case ETHERTYPE_IPV6:
1011                 __pcap_ipv6_info(packet);
1012                 break;
1013         case ETHERTYPE_ARP:
1014         case ETHERTYPE_REVARP:
1015                 __pcap_arp_info(packet);
1016                 break;
1017         case ETHERTYPE_LOOPBACK:
1018                 break;
1019         default:
1020                 break;
1021         }
1022 }
1023
1024 static gboolean __pcap_thread_source_func(gpointer data)
1025 {
1026         char buf[MAX_IFACE_LENGTH];
1027         stc_pcap_data_s *lookup;
1028         stc_pcap_data_s *pcap_data = (stc_pcap_data_s *)data;
1029
1030         g_pcap_tv.tv_sec = 0;
1031         g_pcap_tv.tv_usec = 0;
1032         g_pcap_start_fm = false;
1033
1034         if (g_pcap_tables == NULL)
1035                 return false;
1036
1037         snprintf(buf, sizeof(buf), "%s_%d",
1038                 pcap_data->name, pcap_data->group);
1039
1040         lookup = g_hash_table_lookup(g_pcap_tables, buf);
1041         if (!lookup) {
1042                 STC_LOGE("pcap loop not found");
1043                 return false;
1044         }
1045
1046         g_hash_table_remove(g_pcap_tables, buf);
1047         STC_LOGD("Successfully removed pcap loop [%s]", buf);
1048
1049         return false;
1050 }
1051
1052 static gpointer __pcap_thread_func(gpointer data)
1053 {
1054         __STC_LOG_FUNC_ENTER__;
1055
1056         char errbuf[PCAP_ERRBUF_SIZE];
1057         pcap_if_t *alldevs = NULL;
1058         pcap_if_t *dev = NULL;
1059         char *name = NULL;
1060         GSource *source = NULL;
1061         GMainContext *context = NULL;
1062         stc_pcap_data_s *pcap_data = (stc_pcap_data_s *)data;
1063
1064         if (pcap_findalldevs(&alldevs, errbuf) < 0 ||
1065                 alldevs == NULL) {
1066                 STC_LOGE("Failed to find all devs [%s]", errbuf);
1067                 goto thread_exit;
1068         }
1069
1070         for (dev = alldevs; dev; dev = dev->next) {
1071                 if (g_strcmp0(dev->name, pcap_data->name) == 0) {
1072                         name = g_strdup(dev->name);
1073                         break;
1074                 }
1075         }
1076
1077         pcap_freealldevs(alldevs);
1078
1079         if (name == NULL) {
1080                 STC_LOGE("Failed to find dev [%s]", pcap_data->name);
1081                 goto thread_exit;
1082         }
1083
1084         STC_LOGD("Pcap source dev [%s]", name);
1085
1086         pcap_data->handle = pcap_open_live(name, 65535, 1, 1000, errbuf);
1087         if (pcap_data->handle == NULL) {
1088                 STC_LOGE("Failed to open live [%s]", errbuf);
1089                 goto thread_exit;
1090         }
1091
1092         pcap_loop(pcap_data->handle, 0, __pcap_handler, NULL);
1093
1094         pcap_close(pcap_data->handle);
1095
1096 thread_exit:
1097         FREE(name);
1098
1099         context = g_main_context_default();
1100
1101         source = g_idle_source_new();
1102
1103         g_source_set_callback(source,
1104                 __pcap_thread_source_func, pcap_data, NULL);
1105         g_source_attach(source, context);
1106
1107         g_source_unref(source);
1108         
1109         __STC_LOG_FUNC_EXIT__;
1110         return NULL;
1111 }
1112
1113 int stc_plugin_pcap_initialize(void)
1114 {
1115         __STC_LOG_FUNC_ENTER__;
1116
1117         g_pcap_tables = g_hash_table_new_full(g_str_hash,
1118                 g_str_equal, g_free, __pcap_data_free);
1119
1120         __STC_LOG_FUNC_EXIT__;
1121         return STC_ERROR_NONE;
1122 }
1123
1124 int stc_plugin_pcap_deinitialize(void)
1125 {
1126         __STC_LOG_FUNC_ENTER__;
1127
1128         if (g_pcap_tables) {
1129                 g_hash_table_destroy(g_pcap_tables);
1130                 g_pcap_tables = NULL;
1131         }
1132
1133         __STC_LOG_FUNC_EXIT__;
1134         return STC_ERROR_NONE;
1135 }
1136
1137 int stc_plugin_pcap_lookup_dev(void)
1138 {
1139         __STC_LOG_FUNC_ENTER__;
1140
1141         char *dev = NULL;
1142         char errbuf[PCAP_ERRBUF_SIZE];
1143
1144         dev = pcap_lookupdev(errbuf);
1145         if (dev == NULL) {
1146                 STC_LOGE("Failed to look up dev [%s]", errbuf);
1147                 __STC_LOG_FUNC_EXIT__;
1148                 return STC_ERROR_FAIL;
1149         }
1150
1151         STC_LOGD("Dev [%s]", dev);
1152
1153         __STC_LOG_FUNC_EXIT__;
1154         return STC_ERROR_NONE;
1155 }
1156
1157 int stc_plugin_pcap_lookup_net(void)
1158 {
1159         __STC_LOG_FUNC_ENTER__;
1160
1161         char *dev = NULL;
1162         char net[BUFF_SIZE_IP];
1163         char mask[BUFF_SIZE_IP];
1164         char errbuf[PCAP_ERRBUF_SIZE];
1165         int ret;
1166         bpf_u_int32 netp;
1167         bpf_u_int32 maskp;
1168
1169         dev = pcap_lookupdev(errbuf);
1170         if (dev == NULL) {
1171                 STC_LOGE("Failed to look up dev [%s]", errbuf);
1172                 __STC_LOG_FUNC_EXIT__;
1173                 return STC_ERROR_FAIL;
1174         }
1175
1176         STC_LOGD("Dev [%s]", dev);
1177
1178         ret = pcap_lookupnet(dev, &netp, &maskp, errbuf);
1179         if (ret == -1) {
1180                 STC_LOGE("Failed to look up net [%s]", errbuf);
1181                 __STC_LOG_FUNC_EXIT__;
1182                 return STC_ERROR_FAIL;
1183         }
1184
1185         inet_ntop(AF_INET, &netp, net, BUFF_SIZE_IP);
1186         STC_LOGD("Net [%s]", net);
1187
1188         inet_ntop(AF_INET, &maskp, mask, BUFF_SIZE_IP);
1189         STC_LOGD("Mask [%s]", mask);
1190
1191         __STC_LOG_FUNC_EXIT__;
1192         return STC_ERROR_NONE;
1193 }
1194
1195 int stc_plugin_pcap_find_alldevs(void)
1196 {
1197         __STC_LOG_FUNC_ENTER__;
1198
1199         char net[BUFF_SIZE_IP];
1200         char mask[BUFF_SIZE_IP];
1201         char errbuf[PCAP_ERRBUF_SIZE];
1202         pcap_if_t *alldevs = NULL;
1203         pcap_if_t *dev = NULL;
1204         bpf_u_int32 netp;
1205         bpf_u_int32 maskp;
1206
1207         if (pcap_findalldevs(&alldevs, errbuf) < 0 ||
1208                 alldevs == NULL) {
1209                 STC_LOGE("Failed to find all devs [%s]", errbuf);
1210                 __STC_LOG_FUNC_EXIT__;
1211                 return STC_ERROR_FAIL;
1212         }
1213
1214         for (dev = alldevs; dev; dev = dev->next) {
1215                 STC_LOGD("Dev [%s]", dev->name);
1216
1217                 if (dev->description)
1218                         STC_LOGD("Decs [%s]", dev->description);
1219
1220                 if (pcap_lookupnet(dev->name, &netp, &maskp, errbuf) == -1) {
1221                         STC_LOGE("Failed to look up net [%s]", errbuf);
1222                         continue;
1223                 }
1224
1225                 inet_ntop(AF_INET, &netp, net, BUFF_SIZE_IP);
1226                 STC_LOGD("Net [%s]", net);
1227
1228                 inet_ntop(AF_INET, &maskp, mask, BUFF_SIZE_IP);
1229                 STC_LOGD("Mask [%s]", mask);
1230         }
1231
1232         pcap_freealldevs(alldevs);
1233
1234         __STC_LOG_FUNC_EXIT__;
1235         return STC_ERROR_NONE;
1236 }
1237
1238 int stc_plugin_pcap_register_loop_pcap(const char *ifname,
1239                         int group)
1240 {
1241         __STC_LOG_FUNC_ENTER__;
1242
1243         stc_pcap_data_s *data;
1244         stc_pcap_data_s *lookup;
1245         char buf[MAX_IFACE_LENGTH];
1246
1247         ret_value_msg_if(g_pcap_tables == NULL,
1248                 STC_ERROR_FAIL,
1249                 "pcap tables is not initialized!");
1250
1251         ret_value_msg_if(ifname == NULL,
1252                 STC_ERROR_FAIL,
1253                 "Invalid parameter [ifname]");
1254
1255         snprintf(buf, sizeof(buf), "%s_%d", ifname, group);
1256
1257         lookup = g_hash_table_lookup(g_pcap_tables, buf);
1258         if (lookup) {
1259                 STC_LOGD("pcap loop already present");
1260                 __STC_LOG_FUNC_EXIT__;
1261                 return STC_ERROR_ALREADY_DATA;
1262         }
1263
1264         data = MALLOC0(stc_pcap_data_s, 1);
1265         if (!data) {
1266                 STC_LOGE("data allocation failed");
1267                 __STC_LOG_FUNC_EXIT__;
1268                 return STC_ERROR_OUT_OF_MEMORY;
1269         }
1270
1271         data->name = g_strdup(ifname);
1272         data->group = group;
1273         data->thread = g_thread_new(buf, __pcap_thread_func, data);
1274
1275         g_hash_table_insert(g_pcap_tables, g_strdup(buf), data);
1276         STC_LOGD("Successfully added pcap loop [%s]", buf);
1277
1278         __STC_LOG_FUNC_EXIT__;
1279         return STC_ERROR_NONE;
1280 }
1281
1282 int stc_plugin_pcap_unregister_loop_pcap(const char *ifname,
1283                         int group)
1284 {
1285         __STC_LOG_FUNC_ENTER__;
1286
1287         stc_pcap_data_s *lookup;
1288         char buf[MAX_IFACE_LENGTH];
1289
1290         ret_value_msg_if(g_pcap_tables == NULL,
1291                 STC_ERROR_FAIL,
1292                 "pcap tables is not initialized!");
1293
1294         ret_value_msg_if(ifname == NULL,
1295                 STC_ERROR_FAIL,
1296                 "Invalid parameter [ifname]");
1297
1298         snprintf(buf, sizeof(buf), "%s_%d", ifname, group);
1299
1300         lookup = g_hash_table_lookup(g_pcap_tables, buf);
1301         if (!lookup) {
1302                 STC_LOGE("pcap loop not found");
1303                 __STC_LOG_FUNC_EXIT__;
1304                 return STC_ERROR_NO_DATA;
1305         }
1306
1307         pcap_breakloop(lookup->handle);
1308
1309         __STC_LOG_FUNC_EXIT__;
1310         return STC_ERROR_NONE;
1311 }
1312
1313 API stc_plugin_pcap_s stc_plugin_pcap = {
1314         .initialize_plugin =
1315                 stc_plugin_pcap_initialize,
1316         .deinitialize_plugin =
1317                 stc_plugin_pcap_deinitialize,
1318         .lookup_dev =
1319                 stc_plugin_pcap_lookup_dev,
1320         .lookup_net =
1321                 stc_plugin_pcap_lookup_net,
1322         .find_alldevs =
1323                 stc_plugin_pcap_find_alldevs,
1324         .register_loop_pcap =
1325                 stc_plugin_pcap_register_loop_pcap,
1326         .unregister_loop_pcap =
1327                 stc_plugin_pcap_unregister_loop_pcap
1328 };
1329 //LCOV_EXCL_STOP