"Fossies" - the Fresh Open Source Software Archive 
Member "scanssh-2.1/interface.c" (17 Mar 2004, 9521 Bytes) of package /linux/privat/old/scanssh-2.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "interface.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Copyright 2003 Niels Provos <provos@citi.umich.edu>
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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Niels Provos.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/param.h>
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <sys/ioctl.h>
39 #include <sys/tree.h>
40 #include <sys/queue.h>
41 #ifdef HAVE_SYS_TIME_H
42 #include <sys/time.h>
43 #endif
44
45 #include <err.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <unistd.h>
52
53 #include <event.h>
54 #include <pcap.h>
55 #include <dnet.h>
56
57 #include "interface.h"
58
59 /* Prototypes */
60 static int pcap_dloff(pcap_t *);
61
62 void ss_recv_cb(u_char *, const struct pcap_pkthdr *, const u_char *);
63
64 static char *interface_expandips(int, char **, int);
65 static void interface_recv(int, short, void *);
66 static void interface_poll_recv(int, short, void *);
67
68 #define SS_POLL_INTERVAL {0, 10000}
69
70 int ss_dopoll;
71
72 static TAILQ_HEAD(ifq, interface) interfaces;
73 intf_t *ss_intf;
74 extern struct interface *ss_inter;
75
76 void
77 interface_initialize(void)
78 {
79 TAILQ_INIT(&interfaces);
80
81 if ((ss_intf = intf_open()) == NULL)
82 err(1, "intf_open");
83 }
84
85 /* Get a new interface structure */
86
87 static struct interface *
88 interface_new(char *dev)
89 {
90 char ebuf[PCAP_ERRBUF_SIZE];
91 struct interface *inter;
92
93 if ((inter = calloc(1, sizeof(struct interface))) == NULL)
94 err(1, "%s: calloc", __func__);
95
96 if (dev == NULL) {
97 if ((dev = pcap_lookupdev(ebuf)) == NULL)
98 errx(1, "pcap_lookupdev: %s", ebuf);
99 }
100
101 TAILQ_INSERT_TAIL(&interfaces, inter, next);
102
103 inter->if_ent.intf_len = sizeof(struct intf_entry);
104 strlcpy(inter->if_ent.intf_name, dev, sizeof(inter->if_ent.intf_name));
105
106 if (intf_get(ss_intf, &inter->if_ent) < 0)
107 err(1, "%s: intf_get", __func__);
108
109 if (inter->if_ent.intf_addr.addr_type != ADDR_TYPE_IP)
110 errx(1, "%s: bad interface configuration: %s is not IP",
111 __func__, dev);
112
113 return (inter);
114 }
115
116 struct interface *
117 interface_find(char *name)
118 {
119 struct interface *inter;
120
121 TAILQ_FOREACH(inter, &interfaces, next) {
122 if (strcasecmp(inter->if_ent.intf_name, name) == 0)
123 return (inter);
124 }
125
126 return (NULL);
127 }
128
129 struct interface *
130 interface_find_addr(struct addr *addr)
131 {
132 struct interface *inter;
133
134 TAILQ_FOREACH(inter, &interfaces, next) {
135 if (addr_cmp(addr, &inter->if_ent.intf_addr) == 0)
136 return (inter);
137 }
138
139 return (NULL);
140 }
141
142 void
143 interface_close(struct interface *inter)
144 {
145 TAILQ_REMOVE(&interfaces, inter, next);
146
147 if (inter->if_eth != NULL)
148 eth_close(inter->if_eth);
149 pcap_close(inter->if_pcap);
150
151 free(inter);
152 }
153
154 void
155 interface_close_all(void)
156 {
157 struct interface *inter;
158
159 while((inter = TAILQ_FIRST(&interfaces)) != NULL)
160 interface_close(inter);
161 }
162
163 void
164 interface_init(char *dev, int naddresses, char **addresses, char *filter)
165 {
166 struct bpf_program fcode;
167 char ebuf[PCAP_ERRBUF_SIZE], *dst;
168 struct interface *inter;
169 int time;
170
171 if (dev != NULL && interface_find(dev) != NULL) {
172 fprintf(stderr, "Warning: Interface %s already configured\n",
173 dev);
174 return;
175 }
176
177 ss_inter = inter = interface_new(dev);
178
179 /*
180 * Compute the monitored IP addresses. If we are ethernet,
181 * ignore our own packets.
182 */
183
184 /* Destination addresses only */
185 dst = interface_expandips(naddresses, addresses, 1);
186
187 if (snprintf(inter->if_filter, sizeof(inter->if_filter),
188 "(%s) %s%s%s",
189 filter,
190 dst ? "and (" : "", dst ? dst : "", dst ? ")" : "") >=
191 sizeof(inter->if_filter))
192 errx(1, "%s: pcap filter exceeds maximum length", __func__);
193
194 inter->if_ent.intf_addr.addr_bits = IP_ADDR_BITS;
195
196 time = ss_dopoll ? 10 : 30;
197 if ((inter->if_pcap = pcap_open_live(inter->if_ent.intf_name,
198 128 /* inter->if_ent.intf_mtu + 40 */,
199 0, time, ebuf)) == NULL)
200 errx(1, "pcap_open_live: %s", ebuf);
201
202 /* Get offset to packet data */
203 inter->if_dloff = pcap_dloff(inter->if_pcap);
204
205 if (pcap_compile(inter->if_pcap, &fcode, inter->if_filter, 1, 0) < 0 ||
206 pcap_setfilter(inter->if_pcap, &fcode) < 0)
207 errx(1, "bad pcap filter: %s", pcap_geterr(inter->if_pcap));
208 #if defined(BSD) && defined(BIOCIMMEDIATE)
209 {
210 int on = 1;
211 if (ioctl(pcap_fileno(inter->if_pcap), BIOCIMMEDIATE, &on) < 0)
212 warn("BIOCIMMEDIATE");
213 }
214 #endif
215
216 syslog(LOG_INFO, "listening on %s: %s",
217 inter->if_ent.intf_name, inter->if_filter);
218
219 if (!ss_dopoll) {
220 event_set(&inter->if_recvev, pcap_fileno(inter->if_pcap),
221 EV_READ, interface_recv, inter);
222 event_add(&inter->if_recvev, NULL);
223 } else {
224 struct timeval tv = SS_POLL_INTERVAL;
225
226 syslog(LOG_INFO, "switching to polling mode");
227 timeout_set(&inter->if_recvev, interface_poll_recv, inter);
228 timeout_add(&inter->if_recvev, &tv);
229 }
230 }
231
232 /*
233 * Expands several command line arguments into a complete pcap filter string.
234 * Deals with normal CIDR notation and IP-IP ranges.
235 */
236
237 static char *
238 interface_expandips(int naddresses, char **addresses, int dstonly)
239 {
240 static char filter[1024];
241 char line[1024], *p;
242 struct addr dst;
243
244 if (naddresses == 0)
245 return (NULL);
246
247 filter[0] = '\0';
248
249 while (naddresses--) {
250 /* Get current address */
251 p = *addresses++;
252
253 if (filter[0] != '\0') {
254 if (strlcat(filter, " or ", sizeof(filter)) >= sizeof(filter))
255 errx(1, "%s: too many address for filter",
256 __func__);
257 }
258
259 if (addr_pton(p, &dst) != -1) {
260 snprintf(line, sizeof(line), "%s%s%s",
261 dstonly ? "dst " : "",
262 dst.addr_bits != 32 ? "net ": "", p);
263 } else {
264 char *first, *second;
265 struct addr astart, aend;
266 struct in_addr in;
267 ip_addr_t istart, iend;
268
269 second = p;
270
271 first = strsep(&second, "-");
272 if (second == NULL)
273 errx(1, "%s: Invalid network range: %s",
274 __func__, p);
275
276 line[0] = '\0';
277 if (addr_pton(first, &astart) == -1 ||
278 addr_pton(second, &aend) == -1)
279 errx(1, "%s: bad addresses %s-%s", __func__,
280 first, second);
281 if (addr_cmp(&astart, &aend) >= 0)
282 errx(1, "%s: inverted range %s-%s", __func__,
283 first, second);
284
285 /* Completely, IPv4 specific */
286 istart = ntohl(astart.addr_ip);
287 iend = ntohl(aend.addr_ip);
288 while (istart <= iend) {
289 char single[32];
290 int count = 0, done = 0;
291 ip_addr_t tmp;
292
293 do {
294 ip_addr_t bit = 1 << count;
295 ip_addr_t mask;
296
297 mask = ~(~0 << count);
298 tmp = istart | mask;
299
300 if (istart & bit)
301 done = 1;
302
303 if (iend < tmp) {
304 count--;
305 mask = ~(~0 << count);
306 tmp = istart | mask;
307 break;
308 } else if (done)
309 break;
310
311 count++;
312 } while (count < IP_ADDR_BITS);
313
314 if (line[0] != '\0')
315 strlcat(line, " or ", sizeof(line));
316 in.s_addr = htonl(istart);
317 snprintf(single, sizeof(single),
318 "dst net %s/%d",
319 inet_ntoa(in), 32 - count);
320
321 strlcat(line, single, sizeof(line));
322
323 istart = tmp + 1;
324 }
325 }
326
327 if (strlcat(filter, line, sizeof(filter)) >= sizeof(filter))
328 errx(1, "%s: too many address for filter",
329 __func__);
330 }
331
332 return (filter);
333 }
334
335 /* Interface receiving functions */
336
337 static void
338 interface_recv(int fd, short type, void *arg)
339 {
340 struct interface *inter = arg;
341
342 if (!ss_dopoll)
343 event_add(&inter->if_recvev, NULL);
344
345 if (pcap_dispatch(inter->if_pcap, -1,
346 ss_recv_cb, (u_char *)inter) < 0)
347 syslog(LOG_ERR, "pcap_dispatch: %s",
348 pcap_geterr(inter->if_pcap));
349 }
350
351 static void
352 interface_poll_recv(int fd, short type, void *arg)
353 {
354 struct interface *inter = arg;
355 struct timeval tv = SS_POLL_INTERVAL;
356
357 timeout_add(&inter->if_recvev, &tv);
358
359 interface_recv(fd, type, arg);
360 }
361
362 static int
363 pcap_dloff(pcap_t *pd)
364 {
365 int offset = -1;
366
367 switch (pcap_datalink(pd)) {
368 case DLT_EN10MB:
369 offset = 14;
370 break;
371 case DLT_IEEE802:
372 offset = 22;
373 break;
374 case DLT_FDDI:
375 offset = 21;
376 break;
377 #ifdef DLT_PPP
378 case DLT_PPP:
379 offset = 24;
380 break;
381 #endif
382 #ifdef DLT_LINUX_SLL
383 case DLT_LINUX_SLL:
384 offset = 16;
385 break;
386 #endif
387 #ifdef DLT_LOOP
388 case DLT_LOOP:
389 #endif
390 case DLT_NULL:
391 offset = 4;
392 break;
393 default:
394 warnx("unsupported datalink type");
395 break;
396 }
397 return (offset);
398 }