pcap_parse.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * SpanDSP - a series of DSP components for telephony
  3. *
  4. * pcap_parse.c
  5. *
  6. * Written by Steve Underwood <steveu@coppice.org>
  7. *
  8. * Copyright (C) 2009 Steve Underwood
  9. *
  10. * All rights reserved.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2, as
  14. * published by the Free Software Foundation.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24. *
  25. * Some code from SIPP (http://sf.net/projects/sipp) was used as a model
  26. * for how to work with PCAP files. That code was authored by Guillaume
  27. * TEISSIER from FTR&D 02/02/2006, and released under the GPL2 licence.
  28. */
  29. #if defined(HAVE_CONFIG_H)
  30. #include "config.h"
  31. #endif
  32. #include <inttypes.h>
  33. #include <stdlib.h>
  34. #include <stdio.h>
  35. #if defined(HAVE_PCAP_H)
  36. #include <pcap.h>
  37. #endif
  38. #include <netinet/in.h>
  39. #include <netinet/udp.h>
  40. #if defined(__HPUX) || defined(__CYGWIN__) || defined(__FreeBSD__)
  41. #include <netinet/in_systm.h>
  42. #endif
  43. #include <netinet/ip.h>
  44. #if !defined(__CYGWIN__)
  45. #include <netinet/ip6.h>
  46. #endif
  47. #include <string.h>
  48. #include <netinet/in.h>
  49. #include <netinet/udp.h>
  50. #include <time.h>
  51. #include "udptl.h"
  52. #include "spandsp.h"
  53. #include "pcap_parse.h"
  54. #if defined(__HPUX) || defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
  55. struct iphdr
  56. {
  57. #if defined(_HPUX_LI)
  58. unsigned int ihl:4;
  59. unsigned int version:4;
  60. #else
  61. unsigned int version:4;
  62. unsigned int ihl:4;
  63. #endif
  64. uint8_t tos;
  65. uint16_t tot_len;
  66. uint16_t id;
  67. uint16_t frag_off;
  68. uint8_t ttl;
  69. uint8_t protocol;
  70. uint16_t check;
  71. uint32_t saddr;
  72. uint32_t daddr;
  73. /*The options start here. */
  74. };
  75. #endif
  76. /* We define our own structures for Ethernet Header and IPv6 Header as they are not available on CYGWIN.
  77. * We only need the fields, which are necessary to determine the type of the next header.
  78. * we could also define our own structures for UDP and IPv4. We currently use the structures
  79. * made available by the platform, as we had no problems to get them on all supported platforms.
  80. */
  81. typedef struct _ether_hdr
  82. {
  83. char ether_dst[6];
  84. char ether_src[6];
  85. uint16_t ether_type;
  86. } ether_hdr;
  87. typedef struct _linux_sll_hdr
  88. {
  89. uint16_t packet_type;
  90. uint16_t arphrd;
  91. uint16_t slink_length;
  92. uint8_t bytes[8];
  93. uint16_t ether_type;
  94. } linux_sll_hdr;
  95. typedef struct _null_hdr
  96. {
  97. uint32_t pf_type;
  98. } null_hdr;
  99. #if !defined(__CYGWIN__)
  100. typedef struct _ipv6_hdr
  101. {
  102. char dontcare[6];
  103. u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
  104. char dontcare2[33];
  105. } ipv6_hdr;
  106. #endif
  107. char errbuf[PCAP_ERRBUF_SIZE];
  108. int pcap_scan_pkts(const char *file,
  109. uint32_t src_addr,
  110. uint16_t src_port,
  111. uint32_t dest_addr,
  112. uint16_t dest_port,
  113. pcap_timing_update_handler_t *timing_update_handler,
  114. pcap_packet_handler_t *packet_handler,
  115. void *user_data)
  116. {
  117. pcap_t *pcap;
  118. struct pcap_pkthdr *pkthdr;
  119. uint8_t *pktdata;
  120. const uint8_t *body;
  121. int body_len;
  122. int total_pkts;
  123. uint32_t pktlen;
  124. ether_hdr *ethhdr;
  125. linux_sll_hdr *sllhdr;
  126. null_hdr *nullhdr;
  127. struct iphdr *iphdr;
  128. #if !defined(__CYGWIN__)
  129. ipv6_hdr *ip6hdr;
  130. #endif
  131. struct udphdr *udphdr;
  132. int datalink;
  133. int packet_type;
  134. total_pkts = 0;
  135. if ((pcap = pcap_open_offline(file, errbuf)) == NULL)
  136. {
  137. fprintf(stderr, "Can't open PCAP file '%s'\n", file);
  138. return -1;
  139. }
  140. datalink = pcap_datalink(pcap);
  141. /* DLT_EN10MB seems to apply to all forms of ethernet, not just the 10MB kind. */
  142. switch (datalink)
  143. {
  144. case DLT_EN10MB:
  145. printf("Datalink type ethernet\n");
  146. break;
  147. case DLT_LINUX_SLL:
  148. printf("Datalink type cooked Linux socket\n");
  149. break;
  150. case DLT_NULL:
  151. printf("Datalink type NULL\n");
  152. break;
  153. default:
  154. fprintf(stderr, "Unsupported data link type %d\n", datalink);
  155. return -1;
  156. }
  157. pkthdr = NULL;
  158. pktdata = NULL;
  159. #if defined(HAVE_PCAP_NEXT_EX)
  160. while (pcap_next_ex(pcap, &pkthdr, (const uint8_t **) &pktdata) == 1)
  161. {
  162. #else
  163. if ((pkthdr = (struct pcap_pkthdr *) malloc(sizeof(*pkthdr))) == NULL)
  164. {
  165. fprintf(stderr, "Can't allocate memory for pcap pkthdr\n");
  166. return -1;
  167. }
  168. while ((pktdata = (uint8_t *) pcap_next(pcap, pkthdr)) != NULL)
  169. {
  170. #endif
  171. switch (datalink)
  172. {
  173. case DLT_EN10MB:
  174. ethhdr = (ether_hdr *) pktdata;
  175. packet_type = ntohs(ethhdr->ether_type);
  176. #if !defined(__CYGWIN__)
  177. if (packet_type != 0x0800 /* IPv4 */
  178. &&
  179. packet_type != 0x86DD) /* IPv6 */
  180. #else
  181. if (packet_type != 0x0800) /* IPv4 */
  182. #endif
  183. {
  184. continue;
  185. }
  186. iphdr = (struct iphdr *) ((uint8_t *) ethhdr + sizeof(*ethhdr));
  187. break;
  188. case DLT_LINUX_SLL:
  189. sllhdr = (linux_sll_hdr *) pktdata;
  190. packet_type = ntohs(sllhdr->ether_type);
  191. #if !defined(__CYGWIN__)
  192. if (packet_type != 0x0800 /* IPv4 */
  193. &&
  194. packet_type != 0x86DD) /* IPv6 */
  195. #else
  196. if (packet_type != 0x0800) /* IPv4 */
  197. #endif
  198. {
  199. continue;
  200. }
  201. iphdr = (struct iphdr *) ((uint8_t *) sllhdr + sizeof(*sllhdr));
  202. break;
  203. case DLT_NULL:
  204. nullhdr = (null_hdr *) pktdata;
  205. if (nullhdr->pf_type != PF_INET && nullhdr->pf_type != PF_INET6)
  206. continue;
  207. iphdr = (struct iphdr *) ((uint8_t *) nullhdr + sizeof(*nullhdr));
  208. break;
  209. default:
  210. continue;
  211. }
  212. #if 0
  213. {
  214. int i;
  215. printf("--- %d -", pkthdr->caplen);
  216. for (i = 0; i < pkthdr->caplen; i++)
  217. printf(" %02x", pktdata[i]);
  218. printf("\n");
  219. }
  220. #endif
  221. #if !defined(__CYGWIN__)
  222. if (iphdr && iphdr->version == 6)
  223. {
  224. /* ipv6 */
  225. pktlen = (uint32_t) pkthdr->len - sizeof(*ethhdr) - sizeof(*ip6hdr);
  226. ip6hdr = (ipv6_hdr *) (void *) iphdr;
  227. if (ip6hdr->nxt_header != IPPROTO_UDP)
  228. continue;
  229. udphdr = (struct udphdr *) ((uint8_t *) ip6hdr + sizeof(*ip6hdr));
  230. }
  231. else
  232. #endif
  233. {
  234. /* ipv4 */
  235. if (iphdr->protocol != IPPROTO_UDP)
  236. continue;
  237. #if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
  238. udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2) + 4);
  239. pktlen = (uint32_t) ntohs(udphdr->uh_ulen);
  240. #elif defined ( __HPUX)
  241. udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2));
  242. pktlen = (uint32_t) pkthdr->len - sizeof(*ethhdr) - sizeof(*iphdr);
  243. #else
  244. udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2));
  245. pktlen = (uint32_t) ntohs(udphdr->len);
  246. #endif
  247. }
  248. timing_update_handler(user_data, &pkthdr->ts);
  249. if (src_addr && ntohl(iphdr->saddr) != src_addr)
  250. continue;
  251. #if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
  252. if (src_port && ntohs(udphdr->uh_sport) != src_port)
  253. #else
  254. if (src_port && ntohs(udphdr->source) != src_port)
  255. #endif
  256. continue;
  257. if (dest_addr && ntohl(iphdr->daddr) != dest_addr)
  258. continue;
  259. #if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__)
  260. if (dest_port && ntohs(udphdr->uh_dport) != dest_port)
  261. #else
  262. if (dest_port && ntohs(udphdr->dest) != dest_port)
  263. #endif
  264. continue;
  265. if (pkthdr->len != pkthdr->caplen)
  266. {
  267. fprintf(stderr, "Truncated packet - total len = %d, captured len = %d\n", pkthdr->len, pkthdr->caplen);
  268. exit(2);
  269. }
  270. #if 0
  271. printf("%d:%d -> %d:%d\n", ntohl(iphdr->saddr), ntohs(udphdr->source), ntohl(iphdr->daddr), ntohs(udphdr->dest));
  272. #endif
  273. body = (const uint8_t *) udphdr;
  274. body += sizeof(struct udphdr);
  275. body_len = pktlen - sizeof(struct udphdr);
  276. packet_handler(user_data, body, body_len);
  277. total_pkts++;
  278. }
  279. fprintf(stderr, "In pcap %s there were %d accepted packets\n", file, total_pkts);
  280. pcap_close(pcap);
  281. return 0;
  282. }
  283. /*- End of function --------------------------------------------------------*/
  284. /*- End of file ------------------------------------------------------------*/