Added unit tests to check dabba help output.
[dabba.git] / libdabba / pcap.c
blob9f3ceb8f9a8d718ba20d842932ece61f3cc9bdaf
1 /**
2 * \file pcap.c
3 * \author written by Emmanuel Roullit emmanuel.roullit@gmail.com (c) 2011
4 * \date 2011
5 */
7 /* __LICENSE_HEADER_BEGIN__ */
9 /*
10 * Copyright (C) 2011 Emmanuel Roullit <emmanuel.roullit@gmail.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
28 /* __LICENSE_HEADER_END__ */
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <fcntl.h>
39 #include <sys/stat.h>
41 #include <libdabba/pcap.h>
43 /**
44 * \internal
45 * \brief Write the PCAP file header on a file descriptor
46 * \param[in] fd PCAP file descriptor
47 * \param[in] linktype PCAP link type
48 * \param[in] thiszone Timezone where the PCAP is created
49 * \param[in] snaplen Maximum length of a captured packet
50 * \return 0 on success, -1 if PCAP file header could not be written
53 static int pcap_file_header_write(const int fd, const int linktype,
54 const int thiszone, const int snaplen)
56 struct pcap_file_header hdr;
58 assert(fd > 0);
60 memset(&hdr, 0, sizeof(hdr));
62 hdr.magic = TCPDUMP_MAGIC;
63 hdr.version_major = PCAP_VERSION_MAJOR;
64 hdr.version_minor = PCAP_VERSION_MINOR;
65 hdr.thiszone = thiszone;
66 hdr.snaplen = snaplen;
67 hdr.sigfigs = 0;
68 hdr.linktype = linktype;
70 if (write(fd, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
71 return (-1);
74 return (0);
77 /**
78 * \brief Get PCAP link type from NIC ARP type
79 * \param[in] arp_type ARP type value
80 * \param[out] pcap_link_type Pointer to the PCAP link type
81 * \return 0 on success, \c EINVAL when the ARP type is not supported
84 int pcap_link_type_get(int arp_type, enum pcap_linktype *pcap_link_type)
86 int rc = 0;
88 assert(pcap_link_type);
90 switch (arp_type) {
91 case ARPHRD_ETHER:
92 case ARPHRD_LOOPBACK:
93 *pcap_link_type = LINKTYPE_EN10MB;
94 break;
95 default:
96 rc = EINVAL;
97 break;
100 return (rc);
104 * \brief Validate PCAP file header
105 * Every PCAP file has a file header which contains:
106 * - the PCAP magic (\c 0xa1b2c3d4)
107 * - the PCAP version major/minor
108 * - the PCAP linktype
109 * - the timezone
110 * - the maximum packet length
111 * \param[in] fd PCAP file descriptor
112 * \return 0 if the PCAP file header is not valid \n
113 * 1 if it is. \n
114 * If PCAP file header is invalid, \c errno is set to \n
115 * \c EINVAL if PCAP file descriptor or file header is invalid \n
116 * \c EIO if PCAP file header could not be read
119 int pcap_is_valid(const int fd)
121 struct pcap_file_header hdr;
123 if (fd < 0) {
124 errno = EINVAL;
125 return (0);
128 if (read(fd, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
129 errno = EIO;
130 return (0);
133 if (hdr.magic != TCPDUMP_MAGIC
134 || hdr.version_major != PCAP_VERSION_MAJOR
135 || hdr.version_minor != PCAP_VERSION_MINOR
136 || !is_linktype_valid(hdr.linktype)) {
137 errno = EINVAL;
138 return (0);
141 return (1);
145 * \brief Create a PCAP file
146 * \param[in] pcap_path PCAP file path
147 * \param[in] linktype PCAP link type
148 * \return PCAP file descriptor on success, -1 on failure
149 * \note It creates a PCAP file with default permissions
150 * \note A created PCAP will have by default a snapshot length of 65535 bytes.
153 int pcap_create(const char *const pcap_path, const enum pcap_linktype linktype)
155 assert(pcap_path);
157 int fd;
159 if ((fd = creat(pcap_path, DEFFILEMODE)) < 0) {
160 return (-1);
163 /* TODO make it configurable instead of using default values */
164 if (pcap_file_header_write(fd, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN)) {
165 /* When the PCAP header cannot be written the file
166 * must be closed and then deleted
168 pcap_destroy(fd, pcap_path);
169 fd = -1;
172 return (fd);
176 * \brief Destroy a PCAP file
177 * \param[in] fd PCAP file descriptor
178 * \param[in] pcap_path PCAP file path
181 void pcap_destroy(const int fd, const char *const pcap_path)
183 assert(pcap_path);
184 assert(fd > 0);
186 close(fd);
187 unlink(pcap_path);
191 * \brief Open a PCAP file
192 * \param[in] pcap_path PCAP file path
193 * \param[in] flags flags for \c open(2)
194 * \return PCAP file descriptor on success, -1 on failure
195 * \note The flags given as parameter are directly given to \c open(2)
198 int pcap_open(const char *const pcap_path, int flags)
200 int append = 0;
201 int fd;
203 assert(pcap_path);
205 /* Deactivate append to be able to check pcap validity */
206 if ((flags & O_APPEND) == O_APPEND) {
207 append = 1;
208 flags &= ~O_APPEND;
211 if ((fd = open(pcap_path, flags)) < 0) {
212 return (-1);
215 if (pcap_is_valid(fd) == 0) {
216 pcap_close(fd);
217 return (-1);
220 if (append) {
221 /* Go to EOF */
222 if (lseek(fd, 0, SEEK_END) < 0) {
223 pcap_close(fd);
224 return (-1);
228 return (fd);
232 * \brief Close a PCAP file
233 * \param[in] fd PCAP file descriptor
234 * \return same error values as \c close(2)
237 int pcap_close(const int fd)
239 return (close(fd));
243 * \brief Write the packet payload on a file descriptor
244 * \param[in] fd PCAP file descriptor
245 * \param[in] pkt Pointer to the packet to write
246 * \param[in] pkt_len Valid length of the packet
247 * \param[in] pkt_snaplen Total length of the packet
248 * \param[in] tv_sec Seconds after Epoch
249 * \param[in] tv_usec Microseconds after Epoch
250 * \return Length of written packet on success,
251 * -1 if either the packet header or packet payload could not be written
254 ssize_t pcap_write(const int fd, const uint8_t * const pkt,
255 const size_t pkt_len, const size_t pkt_snaplen,
256 const uint64_t tv_sec, const uint64_t tv_usec)
258 struct pcap_sf_pkthdr sf_hdr;
259 ssize_t written = 0;
261 assert(fd > 0);
262 assert(pkt);
263 assert(pkt_snaplen);
265 memset(&sf_hdr, 0, sizeof(sf_hdr));
267 sf_hdr.ts.tv_sec = tv_sec;
268 sf_hdr.ts.tv_usec = tv_usec;
269 sf_hdr.caplen = pkt_snaplen;
270 sf_hdr.len = pkt_len;
272 if ((written = write(fd, &sf_hdr, sizeof(sf_hdr))) != sizeof(sf_hdr)) {
273 return (-1);
276 if ((written = write(fd, pkt, sf_hdr.len)) != sf_hdr.len) {
277 return (-1);
280 return (written);