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