File: linux.c

package info (click to toggle)
nfswatch 4.99.11-2
  • links: PTS
  • area: main
  • in suites: wheezy
  • size: 492 kB
  • sloc: ansic: 7,429; makefile: 186
file content (155 lines) | stat: -rw-r--r-- 2,985 bytes parent folder | download | duplicates (5)
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
/*
 * $Id: linux.c,v 1.5 2009/02/03 12:51:50 c4chris Exp $
 *
 * Christian Iseli
 * Ludwig Institute for Cancer Research
 * UNIL - BEP
 * CH-1015 Lausanne
 * Switzerland
 *
 */
#include "os.h"

#ifdef USE_LINUX

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <errno.h>

#include "nfswatch.h"
#include "externs.h"

static void
linux_get_def_dev(char **device)
{
	int n, s;
	struct ifreq *ifrp;
	struct ifconf ifc;
	char buf[BUFSIZ];

	/*
	 * Grab a socket.
	 */
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		error("socket");
		finish(-1);
	}

	ifc.ifc_buf = buf;
	ifc.ifc_len = sizeof(buf);

	/*
	 * See what devices we've got.
	 */
	if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
		error("ioctl: SIOCGIFCONF");
		finish(-1);
	}

	/*
	 * Take the first device we encounter.
	 */
	ifrp = ifc.ifc_req;
	for (n = ifc.ifc_len/sizeof(struct ifreq); n > 0; n--,ifrp++) {
		/*
		 * Skip the loopback interface.
		 */
		if (strcmp(ifrp->ifr_name, "lo") == 0)
			continue;

		*device = strdup(ifrp->ifr_name);
		break;
	}

	(void) close(s);
}

/*
 * setup_linux_dev - set up the network interface tap.
 */
int
setup_linux_dev(char **device, linux_socket_handle_p_t ls)
{
	char errbuf[PCAP_ERRBUF_SIZE];

	/*
	 * If the interface device was not specified,
	 * get the default one.
	 */
	if (device != NULL && *device == NULL) {
		linux_get_def_dev(device);
		if (*device == NULL) {
			error("linux: couldn't determine default device");
			finish(-1);
		}
	}
	errbuf[0] = 0;
	if (device == NULL) {
		ls->pcap = pcap_open_live(NULL, 65536, 0, 10, errbuf);
		ls->device = "any";
	} else {
		ls->pcap = pcap_open_live(*device, 65536, 1, 10, errbuf);
		ls->device = *device;
	}
	if (ls->pcap == NULL) {
		fprintf(stderr, "Failed to open device: %s\n", errbuf);
		finish(-1);
	}
	if (errbuf[0] != 0)
		fprintf(stderr, "Warning: %s\n", errbuf);
	ls->s = pcap_get_selectable_fd(ls->pcap);
	if (ls->s == -1) {
		fprintf(stderr, "Failed to get a selectable file descriptor\n");
		finish(-1);
	}

	/* Determine link type.  */
	ls->linktype = pcap_datalink(ls->pcap);
	ls->offset = 2;

	/* Grab a big enough buffer.  */
	ls->bufsize = 65536;
	ls->buffer = (u_char *)malloc(ls->bufsize + ls->offset);
	if (ls->buffer == NULL) {
		perror("malloc");
		finish(-1);
	}

	return(ls->s);
}

int
linux_read_packet(linux_socket_handle_p_t ls)
{
	u_char	*bp;
	int	res;
	struct pcap_pkthdr *hdr;
	const u_char *data;

	/* Receive a single packet from the kernel */
	bp = ls->buffer + ls->offset;
	res = pcap_next_ex(ls->pcap, &hdr, &data);
	if (res == -1) {
		pcap_perror(ls->pcap, "Error reading packet: ");
		return -1;
	}
	if (res <= 0)
		return 0;
	memcpy(bp, data, hdr->caplen);
	ls->len = hdr->caplen;
	ls->ts = hdr->ts;
	ls->bp = bp;

	return 1;
}
#endif /* USE_LINUX */