File: pcap.c

package info (click to toggle)
ipfm 0.11.5-4.3
  • links: PTS
  • area: main
  • in suites: bookworm
  • size: 356 kB
  • sloc: ansic: 1,148; yacc: 328; sh: 210; makefile: 148; lex: 130
file content (278 lines) | stat: -rw-r--r-- 6,695 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*
 *  pcap.c - interface to libpcap
 *
 *  Copyright (C) 1999 Robert Cheramy <tibob@via.ecp.fr>
 *  Copyright (C) 1999 Andres Krapf <dae@via.ecp.fr>
 *

 20001107 : tibob : SIGUSR1 support

 */

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <unistd.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <pcap.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>

#include "config.h"
#include "data.h"
#include "filter.h"
#include "init.h"
#include "pcap.h"
#include "utils.h"

#define SNAPLEN 200

/* dirty code */
extern int promisc;

/* Global variable. This forbids to open 2 pcap descriptors. */
pcap_t  *pcap_global_descriptor = NULL;
struct bpf_program pcap_filter;
int pcap_filter_initialized = 0;

int     offset;

int SigHup = 0;
int SigDump = 0;
extern struct AllLogsType * pAllLogs;

int iphdr_chksum(u_char *iphead, int size)
{
  unsigned long int sum = 0;
  int i;

  for (i = (size * 4) - 2; i > -1; i-=2) {
    sum += iphead[i] + 256 * iphead[i+1];
  }
  sum = (sum & 0xffff) + (sum >> 16);
  /* mmm I'm not sure the "(sum >> 16)" is useful, but better be sure */
  sum += (sum >> 16) + 1;
  return (sum & 0xffff);
}


/*
 * Find a defaultpcap device
 */
char *pcap_default_device() {
  char errbuf[PCAP_ERRBUF_SIZE];
  char *tdev;

  tdev = pcap_lookupdev(errbuf);
  if (!tdev) { 
    fprintf(stderr, "[pcap] pcap_lookupdev error: %s\n", errbuf);
    exit(1);
  }
  return (tdev);
}


/*
 * Opens a Pcap descriptor
 * promisc = 0 for no promisc mode, 1 for this mode.
*/
int openpcap(char *device, int promisc) {
  char errbuf[PCAP_ERRBUF_SIZE];
  int datalink;
  
  if (NULL != pcap_global_descriptor) {
    printf("[pcap] I can't open two pcap descriptors\n");
    return 0 ;
  }

  pcap_global_descriptor = pcap_open_live(device, SNAPLEN, promisc, 1000, errbuf);
  if (NULL == pcap_global_descriptor) {
    fprintf(stderr, "[pcap] error opening pcap: %s\n", errbuf);
    return 0;
  }

  /* compile the IPv4 filter and assign it to the global descriptor */
  if (pcap_compile(pcap_global_descriptor, &pcap_filter,
                   "ip", 1, 0) == 1) {
    fprintf(stderr, "[pcap] error compiling filter \"ip and not ip6\": %s\n",
            pcap_geterr(pcap_global_descriptor));
    return 0;
  }
  pcap_filter_initialized = 1;
  if (pcap_setfilter(pcap_global_descriptor, &pcap_filter) == -1) {
    fprintf(stderr, "[pcap] error assigning filter to descriptor: %s",
            pcap_geterr(pcap_global_descriptor));
    return 0;
  }

  /* set the offset to the beginning of the iphdr */
  if ((datalink = pcap_datalink(pcap_global_descriptor)) < 0) {
    fprintf(stderr, "[pcap] error getting datalink info : %s\n",pcap_geterr(pcap_global_descriptor));
    return 0;
  }

  /*
    these offsets were taken from libpcap source.
    See file gencode.c for more information.
  */
  switch(datalink) {
  case DLT_ARCNET:
    offset = 6;
    break;
  case DLT_EN10MB:
    offset = 14;
    break;
  case DLT_SLIP:
    offset = 16;
    break;
  case DLT_SLIP_BSDOS:
    offset = 24;
    break;
  case DLT_NULL:
  case DLT_LOOP:
    offset = 4;
    break;
  case DLT_PPP:
  case DLT_C_HDLC:             /* BSD/OS Cisco HDLC */
  case DLT_PPP_SERIAL:         /* NetBSD sync/async serial PPP */
    offset = 4;
    break;
#ifdef DLT_PPP_ETHER
  case DLT_PPP_ETHER:
    offset = 8;
    break;
#endif
  case DLT_PPP_BSDOS:
    offset = 24;
    break;
    /*
[RC, 2002/10/20] Commented out FDDI since there is a strange pad complication
on NetBSD, DEC OSF/1 aka Digital Unix aka Tru64 Unix and Ultrix.
If someone yells because she needs FDDI, we'll have a closer look...

  case DLT_FDDI:
     *
     * FDDI doesn't really have a link-level type field.
     * We set "off_linktype" to the offset of the LLC header.
     *
     * To check for Ethernet types, we assume that SSAP = SNAP
     * is being used and pick out the encapsulated Ethernet type.
     * XXX - should we generate code to check for SNAP?
     *
    offset = 21;
#ifdef PCAP_FDDIPAD
    offset += pcap_fddipad;
#endif
    break;
    */
  case DLT_IEEE802:
    break;
  case DLT_IEEE802_11:
    offset = 30;
    break;
#ifdef DLT_PRISM_HEADER
  case DLT_PRISM_HEADER:
    offset = 144+30;
    break;
#endif
  case DLT_ATM_RFC1483:
    offset = 8;
    break;
  case DLT_RAW:
    offset = 0;
    break;
  case DLT_ATM_CLIP:   /* Linux ATM defines this */
    offset = 8;
    break;
  case DLT_LINUX_SLL:  /* fake header for Linux cooked socket */
    offset = 16;
    break;
#ifdef DLT_LTALK
  case DLT_LTALK:
    offset = 0;
    break;
#endif
  default:
    fprintf(stderr, "[pcap] Unknown datalink type : %d.", datalink);
    return 0;
  }
  return 1;
}

void closepcap()
{
  if (NULL == pcap_global_descriptor) {
    /* nothing to do */
  } else {
    pcap_close(pcap_global_descriptor);
    pcap_global_descriptor = NULL;
  }
  if (pcap_filter_initialized) {
    pcap_freecode(&pcap_filter);
    pcap_filter_initialized = 0;
  }
}

u_char *getnextippkt()
{
  struct pcap_pkthdr useless;
  u_char * packet;

  if (NULL == pcap_global_descriptor) {
    fprintf(stderr, "[pcap] Can't read non-opened pcap descriptor");
  }

  for (;;) {
    packet = (u_char *) pcap_next(pcap_global_descriptor, &useless);
    if (NULL == packet) 
      continue;
    packet = packet + offset;

    if ( ((struct ip *) packet)->ip_hl < 5 || ((struct ip *) packet)->ip_v != 4 || iphdr_chksum(packet, ((struct ip *) packet)->ip_hl) != 0 ) {
      /* Not an IP packet */
      continue;
    }

    /* handle HUP signal */

    if (SigHup) {
      struct AllLogsType *pTempLog;
      for (pTempLog = pAllLogs; pTempLog; pTempLog = pTempLog->Next) {
	data_dump(pTempLog);
	data_clear(pTempLog);
      }

      Clean();
      ReInit();
      SigHup = 0;
    }
    /* handle USR1 signal */

    if (SigDump) {
      struct AllLogsType * pTempLog;
      for (pTempLog = pAllLogs; pTempLog; pTempLog = pTempLog->Next) {
	data_dump(pTempLog);
      }
      SigDump = 0;
    }
    break;
  }
  return (packet);
}