"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.
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 }