1 /*-
2 * Copyright (c) 2001, 2003, 2004 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: psrc.c,v 1.12 2005/07/07 05:54:53 vlm Exp $
27 */
28
29 #include "ipcad.h"
30 #include "sf_lite.h"
31 #include "opt.h"
32
33 static int ifIndexes; /* Ever-increasing interface name */
34
35 packet_source_t *
create_packet_source(char * ifname,int iflags,char * filter)36 create_packet_source(char *ifname, int iflags, char *filter) {
37 packet_source_t *ps;
38
39 /*
40 * Create a new interface structure.
41 */
42 ps = calloc(1, sizeof *ps);
43 if(ps == NULL) return NULL;
44
45 ps->fd = -1; /* Packet source file descriptor */
46
47 /*
48 * Fill-up the common parameters.
49 */
50 strncpy( ps->ifName, ifname, sizeof(ps->ifName) );
51 ps->ifName[sizeof(ps->ifName) - 1] = 0;
52 ps->iflags = iflags;
53 ps->custom_filter = filter;
54
55 ps->avg_period = 300; /* 5 minutes */
56 ps->bytes_lp = -1; /* Initial value */
57 ps->packets_lp = -1; /* Initial value */
58
59 ps->state = PST_EMBRYONIC;
60
61
62 /*
63 * Initialize packet source descriptors.
64 */
65 if(strchr(ifname, '*')) {
66 /*
67 * The interface does not exist, so it might be dynamic.
68 */
69 fprintf(stderr, "[DYNAMIC] ");
70 ps->process_ptr = process_dynamic;
71 ps->print_stats = print_stats_dynamic;
72 ps->iface_type = IFACE_DYNAMIC;
73 ps->iface.dynamic.already_got = genhash_new(cmpf_string,
74 hashf_string,
75 NULL, (void (*)(void *))destroy_packet_source);
76 if(ps->iface.dynamic.already_got == NULL)
77 goto failure;
78 } else if(strncasecmp(ifname, "ulog", 5) == 0) {
79 #ifdef PSRC_ulog
80 u_int32_t m = 0x80000000;
81 char *p;
82 int i;
83 ps->process_ptr = process_ulog;
84 ps->print_stats = print_stats_ulog;
85
86 ps->iface_type = IFACE_ULOG;
87 ps->iface.ulog.groupmask = strtoul(ps->custom_filter, NULL, 10);
88 ps->iface.ulog.uName = p = calloc(1, 1 + 32 * (2 + 1) + 1);
89 if(!p) goto failure;
90 *p++ = 'u'; /* "u"log */
91 for(i = 32; m; m >>= 1, i--) {
92 assert(i >= 1);
93 if(ps->iface.ulog.groupmask & m) {
94 int ret = snprintf(p, 3, "%d,", i);
95 assert(ret >= 1 && ret <= 3);
96 p += ret;
97 }
98 }
99 *(--p) = '\0';
100 if(p == ps->iface.ulog.uName) {
101 ps->iface.ulog.uName = NULL;
102 free(p);
103 }
104 #else /* !PSRC_ulog */
105 fprintf(stderr, "Linux ULOG is not supported\n");
106 errno = EINVAL;
107 goto failure;
108 #endif /* PSRC_ulog */
109 } else if(strncasecmp(ifname, "ipq", 4) == 0) {
110 #ifdef PSRC_ipq
111 ps->process_ptr = process_ipq;
112 ps->print_stats = print_stats_ipq;
113
114 ps->iface_type = IFACE_IPQ;
115 ps->iface.ipq.peer.nl_family = AF_NETLINK;
116 #else /* !PSRC_ipq */
117 fprintf(stderr,
118 "Linux IPQ interface is not supported\n");
119 errno = EINVAL;
120 goto failure;
121 #endif /* PSRC_ipq */
122 } else if(strncasecmp(ifname, "divert", 7) == 0
123 || strncasecmp(ifname, "tee", 4) == 0) {
124 #ifdef IPPROTO_DIVERT
125 ps->process_ptr = process_divert;
126 ps->print_stats = print_stats_divert;
127
128 if(strncasecmp(ifname, "d", 1) == 0)
129 ps->iface_type = IFACE_DIVERT;
130 else
131 ps->iface_type = IFACE_TEE;
132 ps->iface.divert.port = atoi(ps->custom_filter);
133 ps->bufsize = 65536 + 4096;
134 ps->buf = malloc(ps->bufsize);
135 if(ps->buf == NULL) {
136 ps->bufsize = 0;
137 goto failure;
138 }
139 #else /* !IPPROTO_DIVERT */
140 fprintf(stderr,
141 "BSD divert(4)/tee interface is not supported\n");
142 errno = EINVAL;
143 goto failure;
144 #endif /* IPPROTO_DIVERT */
145 } else if(strcmp(ifname, "file") == 0) {
146 ps->iface_type = IFACE_FILE;
147 ps->process_ptr = process_file;
148 ps->print_stats = print_stats_file;
149 ps->iface.file.name = filter;
150 ps->iface.file.dev = NULL;
151 } else {
152 #ifdef PSRC_bpf
153 ps->process_ptr = process_bpf;
154 ps->print_stats = print_stats_bpf;
155
156 ps->iface_type = IFACE_BPF;
157 #endif /* PSRC_bpf */
158 #ifdef PSRC_pcap
159 ps->process_ptr = process_pcap;
160 ps->print_stats = print_stats_pcap;
161
162 ps->iface_type = IFACE_PCAP;
163 ps->iface.pcap.dev = NULL;
164 if(pthread_mutex_init(&ps->iface.pcap.dev_mutex, NULL) == -1)
165 goto failure;
166 #endif /* PSRC_pcap */
167 }
168
169 switch(ps->iface_type) {
170 case IFACE_DYNAMIC:
171 break;
172 #ifdef IPPROTO_DIVERT
173 case IFACE_DIVERT:
174 /* Special interface index */
175 ps->ifIndex = IFINDEX_DIVERT_MASK | ps->iface.divert.port;
176 break;
177 case IFACE_TEE:
178 /* Special interface index */
179 ps->ifIndex = IFINDEX_TEE_MASK | ps->iface.divert.port;
180 break;
181 #endif /* IPPROTO_DIVERT */
182 default:
183 ps->ifIndex = ++ifIndexes;
184 }
185
186 return ps;
187
188 failure:
189 free(ps);
190 return NULL;
191 }
192
193
194 int
init_packet_source(packet_source_t * ps,int retry_mode)195 init_packet_source(packet_source_t *ps, int retry_mode) {
196
197 switch(ps->iface_type) {
198 case IFACE_FILE:
199 return init_packet_source_file(ps);
200 case IFACE_DYNAMIC:
201 return init_packet_source_dynamic(ps);
202 case IFACE_ULOG:
203 return init_packet_source_ulog(ps, retry_mode);
204 case IFACE_IPQ:
205 return init_packet_source_ipq(ps, retry_mode);
206 case IFACE_DIVERT:
207 case IFACE_TEE:
208 return init_packet_source_divert(ps);
209 default:
210 #ifdef PSRC_bpf
211 return init_packet_source_bpf(ps, retry_mode);
212 #elif PSRC_pcap
213 return init_packet_source_pcap(ps);
214 #else
215 #error unknown packet source
216 #endif
217 }
218 }
219
220 void
destroy_packet_source(packet_source_t * ps)221 destroy_packet_source(packet_source_t *ps) {
222 if(ps == NULL) return;
223
224 if(ps->buf)
225 free(ps->buf);
226
227 if(ps->fd != -1)
228 close(ps->fd);
229
230 switch(ps->iface_type) {
231 case IFACE_DYNAMIC:
232 genhash_destroy(ps->iface.dynamic.already_got);
233 break;
234 #ifdef PSRC_pcap
235 case IFACE_PCAP:
236 if(ps->iface.pcap.dev)
237 pcap_close(ps->iface.pcap.dev);
238 pthread_mutex_destroy(&ps->iface.pcap.dev_mutex);
239 break;
240 #endif
241 default:
242 break;
243 }
244
245 free(ps);
246 }
247
248 const char *
IFNameBySource(void * psrc)249 IFNameBySource(void *psrc) {
250 packet_source_t *ps = psrc;
251 if(ps) {
252 switch(ps->iface_type) {
253 case IFACE_FILE:
254 return ps->iface.file.name;
255 #ifdef PSRC_ulog
256 case IFACE_ULOG:
257 if(ps->iface.ulog.uName)
258 return ps->iface.ulog.uName;
259 /* Fall through */
260 #endif
261 case IFACE_DIVERT:
262 case IFACE_TEE:
263 return ps->custom_filter;
264 default:
265 return ps->ifName;
266 }
267 } else {
268 return "<?>";
269 }
270 }
271