Added --version option to get dabbad version info.
[dabba.git] / libdabba / pcap.c
blobdf632ee9c0bfe4532566cd73e0c92679cb287ba7
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>
38 #include <byteswap.h>
40 #include <sys/stat.h>
42 #include <libdabba/pcap.h>
44 /**
45 * \internal
46 * \brief Write the PCAP file header on a file descriptor
47 * \param[in] fd PCAP file descriptor
48 * \param[in] linktype PCAP link type
49 * \param[in] thiszone Timezone where the PCAP is created
50 * \param[in] snaplen Maximum length of a captured packet
51 * \return 0 on success, -1 if PCAP file header could not be written
54 static int
55 pcap_file_header_write(const int fd, const int linktype,
56 const int thiszone, const int snaplen)
58 struct pcap_file_header hdr;
60 assert(fd > 0);
62 memset(&hdr, 0, sizeof(hdr));
64 hdr.magic = TCPDUMP_MAGIC;
65 hdr.version_major = PCAP_VERSION_MAJOR;
66 hdr.version_minor = PCAP_VERSION_MINOR;
67 hdr.thiszone = thiszone;
68 hdr.snaplen = snaplen;
69 hdr.sigfigs = 0;
70 hdr.linktype = linktype;
72 if (write(fd, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
73 return (-1);
76 return (0);
79 /**
80 * \brief Get PCAP link type from NIC ARP type
81 * \param[in] arp_type ARP type value
82 * \param[out] pcap_link_type Pointer to the PCAP link type
83 * \return 0 on success, \c EINVAL when the ARP type is not supported
86 int pcap_link_type_get(int arp_type, enum pcap_linktype *pcap_link_type)
88 int rc = 0;
90 assert(pcap_link_type);
92 switch (arp_type) {
93 case ARPHRD_ETHER:
94 case ARPHRD_LOOPBACK:
95 *pcap_link_type = LINKTYPE_EN10MB;
96 break;
97 default:
98 rc = EINVAL;
99 break;
102 return (rc);
106 * \internal
107 * \brief Tells if the input linktype is valid
108 * \param[in] linktype Linktype to validate
109 * \return 1 if the linktype is valid, 0 if invalid
112 static int pcap_linktype_is_valid(const uint32_t linktype)
114 return (linktype == LINKTYPE_EN10MB);
118 * \internal
119 * \brief Validate PCAP file header
120 * Every PCAP file has a file header which contains:
121 * - the PCAP magic (\c 0xa1b2c3d4)
122 * - the PCAP version major/minor
123 * - the PCAP linktype
124 * - the timezone
125 * - the maximum packet length
126 * \param[in] fd PCAP file descriptor
127 * \return 0 if the PCAP file header is not valid \n
128 * 1 if it is. \n
129 * If PCAP file header is invalid, \c errno is set to \n
130 * \c EINVAL if PCAP file descriptor or file header is invalid \n
131 * \c EIO if PCAP file header could not be read
134 static int pcap_is_valid(const int fd)
136 struct pcap_file_header hdr;
138 if (fd < 0) {
139 errno = EINVAL;
140 return (0);
143 if (read(fd, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
144 errno = EIO;
145 return (0);
148 /* PCAP might have been created on a system with another endianness */
149 if (hdr.magic != TCPDUMP_MAGIC) {
150 hdr.magic = bswap_32(hdr.magic);
151 hdr.linktype = bswap_32(hdr.linktype);
152 hdr.version_major = bswap_16(hdr.version_major);
153 hdr.version_minor = bswap_16(hdr.version_minor);
156 if (hdr.magic != TCPDUMP_MAGIC
157 || hdr.version_major != PCAP_VERSION_MAJOR
158 || hdr.version_minor != PCAP_VERSION_MINOR
159 || !pcap_linktype_is_valid(hdr.linktype)) {
160 errno = EINVAL;
161 return (0);
164 return (1);
168 * \brief Create a PCAP file
169 * \param[in] pcap_path PCAP file path
170 * \param[in] linktype PCAP link type
171 * \return PCAP file descriptor on success, -1 on failure
172 * \note It creates a PCAP file with default permissions
173 * \note A created PCAP will have by default a snapshot length of 65535 bytes.
176 int pcap_create(const char *const pcap_path, const enum pcap_linktype linktype)
178 assert(pcap_path);
180 int fd;
182 if ((fd = creat(pcap_path, DEFFILEMODE)) < 0) {
183 return (-1);
186 /* TODO make it configurable instead of using default values */
187 if (pcap_file_header_write(fd, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN)) {
188 /* When the PCAP header cannot be written the file
189 * must be closed and then deleted
191 pcap_destroy(fd, pcap_path);
192 fd = -1;
195 return (fd);
199 * \brief Destroy a PCAP file
200 * \param[in] fd PCAP file descriptor
201 * \param[in] pcap_path PCAP file path
204 void pcap_destroy(const int fd, const char *const pcap_path)
206 assert(pcap_path);
207 assert(fd > 0);
209 close(fd);
210 unlink(pcap_path);
214 * \brief Open a PCAP file
215 * \param[in] pcap_path PCAP file path
216 * \param[in] flags flags for \c open(2)
217 * \return PCAP file descriptor on success, -1 on failure
218 * \note The flags given as parameter are directly given to \c open(2)
221 int pcap_open(const char *const pcap_path, int flags)
223 int append = 0;
224 int fd;
226 assert(pcap_path);
228 /* Deactivate append to be able to check pcap validity */
229 if ((flags & O_APPEND) == O_APPEND) {
230 append = 1;
231 flags &= ~O_APPEND;
234 if ((fd = open(pcap_path, flags)) < 0) {
235 return (-1);
238 if (pcap_is_valid(fd) == 0) {
239 pcap_close(fd);
240 return (-1);
243 if (append) {
244 /* Go to EOF */
245 if (lseek(fd, 0, SEEK_END) < 0) {
246 pcap_close(fd);
247 return (-1);
251 return (fd);
255 * \brief Close a PCAP file
256 * \param[in] fd PCAP file descriptor
257 * \return same error values as \c close(2)
260 int pcap_close(const int fd)
262 return (close(fd));
266 * \brief Write the packet payload on a file descriptor
267 * \param[in] fd PCAP file descriptor
268 * \param[in] pkt Pointer to the packet to write
269 * \param[in] pkt_len Valid length of the packet
270 * \param[in] pkt_snaplen Total length of the packet
271 * \param[in] tv_sec Seconds after Epoch
272 * \param[in] tv_usec Microseconds after Epoch
273 * \return Length of written packet on success,
274 * -1 if either the packet header or packet payload could not be written
277 ssize_t
278 pcap_write(const int fd, const uint8_t * const pkt,
279 const size_t pkt_len, const size_t pkt_snaplen,
280 const uint64_t tv_sec, const uint64_t tv_usec)
282 struct pcap_sf_pkthdr sf_hdr;
283 ssize_t written = 0;
285 assert(fd > 0);
286 assert(pkt);
287 assert(pkt_snaplen);
289 memset(&sf_hdr, 0, sizeof(sf_hdr));
291 sf_hdr.ts.tv_sec = tv_sec;
292 sf_hdr.ts.tv_usec = tv_usec;
293 sf_hdr.caplen = pkt_snaplen;
294 sf_hdr.len = pkt_len;
296 written = write(fd, &sf_hdr, sizeof(sf_hdr));
298 if (written != sizeof(sf_hdr)) {
299 return (-1);
302 written = write(fd, pkt, sf_hdr.caplen);
304 if (written != (ssize_t) sf_hdr.caplen) {
305 return (-1);
308 return (written);