Browse code

First draft

git-svn: trunk@3051

Nigel Horne authored on 2007/05/03 03:06:27
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,361 @@
0
+/*
1
+ *  Copyright (C) 2007 Nigel Horne <njh@bandsman.co.uk>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ *  MA 02110-1301, USA.
17
+ *
18
+ * Compare the results of scanning files on a set of machines
19
+ *	This is useful for regression testing versions, and for testing
20
+ *	across different operating systems and architectures
21
+ * The file is always copied which is slow, and could be removed for regression
22
+ *	testing, if we have some mechanism to sync the data
23
+ */
24
+
25
+#include <stdio.h>
26
+#include <stdlib.h>
27
+#include <sys/types.h>
28
+#include <dirent.h>
29
+#include <sys/socket.h>
30
+#include <netinet/in.h>
31
+#include <arpa/inet.h>
32
+#include <netdb.h>
33
+#include <memory.h>
34
+#include <unistd.h>
35
+#include <pthread.h>
36
+#include <string.h>
37
+
38
+#define	PORT	3310
39
+#define	LEN	128
40
+
41
+/*
42
+ * Ensure you don't have StreamMaxLength on any of the servers, or that it's
43
+ *	big enough for all your samples
44
+ * Uses SESSIONS, which isn't good
45
+ * If localhost is one of them, it's probably best to put it last so that it
46
+ *	can be scanning while waiting for the remote machines to respond
47
+ */
48
+static struct machine {
49
+	const	char	*name;
50
+	in_addr_t	ip;
51
+	int	sock;
52
+} machines[] = {
53
+	{	"eric",		0,	-1	},
54
+	/*{	"motorola",	0,	-1	},*/
55
+	{	"ultra60",	0,	-1	},
56
+	{	"localhost",	0,	-1	},
57
+	{	NULL,		0,	-1	}
58
+};
59
+
60
+struct args {
61
+	const	char	*filename;
62
+	const	struct	machine	*m;
63
+	char	*ret;
64
+};
65
+
66
+static	void	dir(const char *dirname);
67
+static	in_addr_t	resolve(const char *machine);
68
+static	int	start(in_addr_t ip);
69
+static	void	*scan(void *v);
70
+
71
+int
72
+main(int argc, char **argv)
73
+{
74
+	struct machine *m;
75
+
76
+	if(argc <= 1) {
77
+		fputs("Arg count\n", stderr);
78
+		return 1;
79
+	}
80
+
81
+	for(m = machines; m->name; m++) {
82
+		m->ip = resolve(m->name);
83
+
84
+		if(m->ip == INADDR_NONE) {
85
+			fprintf(stderr, "Can't resolve %s\n", m->name);
86
+			return 1;
87
+		}
88
+		m->sock = start(m->ip);
89
+		if(m->sock < 0)
90
+			fprintf(stderr, "%s is down\n", m->name);
91
+	}
92
+	while(*++argv)
93
+		dir(*argv);
94
+
95
+	return 0;
96
+}
97
+
98
+static void
99
+dir(const char *dirname)
100
+{
101
+	int i, nmachines;
102
+	const struct dirent *dirent;
103
+	struct machine *m;
104
+	DIR *d = opendir(dirname);
105
+	char **results;
106
+
107
+	if(d == NULL) {
108
+		perror(dirname);
109
+		return;
110
+	}
111
+	for(nmachines = 0, m = machines; m->name; m++)
112
+		if(m->sock >= 0)
113
+			nmachines++;
114
+
115
+	if(nmachines < 2) {
116
+		fputs("Needs at least 2 machines up to run\n", stderr);
117
+		closedir(d);
118
+		return;
119
+	}
120
+
121
+	results = (char **)malloc(nmachines * sizeof(char *));
122
+	if(results == NULL)
123
+		return;
124
+	for(i = 0, m = machines; m->name; m++)
125
+		if(m->sock >= 0) {
126
+			results[i] = malloc(LEN);
127
+			if(results[i++] == NULL) {
128
+				free(results);
129
+				closedir(d);
130
+				return;
131
+			}
132
+		}
133
+
134
+	if(i != nmachines) {
135
+		fputs("Failed sanity check\n", stderr);
136
+		closedir(d);
137
+		return;
138
+	}
139
+
140
+	while((dirent = readdir(d)) != NULL) {
141
+		int nthreads, founddiffs;
142
+		pthread_t *tids;
143
+		struct args *args;
144
+		char name[PATH_MAX];
145
+
146
+		if(dirent->d_ino == (ino_t)0)
147
+			continue;
148
+		if(dirent->d_name[0] == '.')
149
+			continue;
150
+
151
+		tids = malloc(nmachines * sizeof(pthread_t));
152
+		if(tids == NULL) {
153
+			free(results);
154
+			closedir(d);
155
+			return;
156
+		}
157
+		args = malloc(nmachines * sizeof(struct args));
158
+		if(args == NULL) {
159
+			free(tids);
160
+			free(results);
161
+			closedir(d);
162
+			return;
163
+		}
164
+
165
+		snprintf(name, sizeof(name) -1, "%s/%s", dirname, dirent->d_name);
166
+		for(nthreads = 0, m = machines; m->name; m++) {
167
+			if(m->sock < 0)
168
+				continue;
169
+
170
+			args[nthreads].filename = name;
171
+			args[nthreads].m = m;
172
+			args[nthreads].ret = results[nthreads];
173
+			pthread_create(&tids[nthreads], NULL, scan, &args[nthreads]);
174
+			nthreads++;
175
+		}
176
+		printf("Scanning %s\n", name);
177
+		founddiffs = 0;
178
+		while(--nthreads >= 0)
179
+			/* TODO: timeout */
180
+			pthread_join(tids[nthreads], NULL);
181
+
182
+		free(args);
183
+		free(tids);
184
+		for(i = 0; i <= nmachines - 2; i++) {
185
+			int j;
186
+
187
+			for(j = i + 1; j <= nmachines - 1; j++) {
188
+				const char *s, *t;
189
+
190
+				s = strchr(results[i], ' ');
191
+				t = strchr(results[j], ' ');
192
+				if((s == NULL) || (t == NULL) || (strcmp(s, t) != 0)) {
193
+					printf("%s:\n", name);
194
+					printf("\t%s: %s\n", machines[i].name, s ? s : "null");
195
+					printf("\t%s: %s\n", machines[j].name, t ? t : "null");
196
+					founddiffs = 1;
197
+				}
198
+			}
199
+		}
200
+
201
+		if(!founddiffs)
202
+			printf("%s passed\n", name);
203
+	}
204
+	closedir(d);
205
+}
206
+
207
+static in_addr_t
208
+resolve(const char *machine)
209
+{
210
+	in_addr_t ret = inet_addr(machine);
211
+
212
+	if(ret == INADDR_NONE) {
213
+		const struct hostent *h = gethostbyname(machine);
214
+
215
+		if(h == NULL) {
216
+			fprintf(stderr, "Unknown host %s\n", machine);
217
+			return INADDR_NONE;
218
+		}
219
+
220
+		memcpy((char *)&ret, h->h_addr, sizeof(in_addr_t));
221
+	}
222
+	return ret;
223
+}
224
+
225
+static int
226
+start(in_addr_t ip)
227
+{
228
+	int sock;
229
+	const struct protoent *proto;
230
+	struct sockaddr_in server;
231
+
232
+	memset((char *)&server, 0, sizeof(struct sockaddr_in));
233
+	server.sin_family = AF_INET;
234
+	server.sin_port = (in_port_t)htons(PORT);
235
+	server.sin_addr.s_addr = ip;
236
+
237
+	proto = getprotobyname("tcp");
238
+	if(proto == NULL) {
239
+		fputs("Unknown prototol tcp, check /etc/protocols\n", stderr);
240
+		return -1;
241
+	} else if((sock = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) {
242
+		perror("socket");
243
+		return -1;
244
+	} else if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
245
+		perror("connect");
246
+		close(sock);
247
+		return -1;
248
+	} else if(send(sock, "SESSION\n", 8, 0) < 8) {
249
+		perror("send");
250
+		close(sock);
251
+		return -1;
252
+	}
253
+	return sock;
254
+}
255
+
256
+static void *
257
+scan(void *v)
258
+{
259
+	struct args *args;
260
+	FILE *fin;
261
+	int sock;
262
+	ssize_t nbytes;
263
+	size_t buflen;
264
+	in_port_t port;
265
+	struct sockaddr_in data;
266
+	const struct machine *m;
267
+	char buf[1024];	/* must be less than MTU */
268
+
269
+	args = (struct args *)v;
270
+	m = args->m;
271
+	if(m->sock < 0)
272
+		return NULL;
273
+	if(m->ip == htonl(INADDR_LOOPBACK)) {
274
+		char cmd[NAME_MAX + 7];
275
+
276
+		snprintf(cmd, sizeof(cmd) - 1, "SCAN %s\n", args->filename);
277
+		buflen = strlen(cmd);
278
+
279
+		if(send(m->sock, cmd, buflen, 0) != (ssize_t)buflen) {
280
+			perror(m->name);
281
+			return NULL;
282
+		}
283
+		nbytes = recv(m->sock, args->ret, LEN, 0);
284
+		if(nbytes < 0) {
285
+			perror(m->name);
286
+			return NULL;
287
+		}
288
+		args->ret[nbytes - 1] = '\0';	/* remove the trailing \n */
289
+
290
+		return NULL;
291
+	}
292
+	fin = fopen(args->filename, "r");
293
+	if(fin == NULL) {
294
+		perror(args->filename);
295
+		return NULL;
296
+	}
297
+	if(send(m->sock, "STREAM\n", 7, 0) != 7) {
298
+		perror(m->name);
299
+		fclose(fin);
300
+		return NULL;
301
+	}
302
+
303
+	if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
304
+		perror("socket");
305
+		fputs("Failed to create TCPSocket to talk to clamd\n", stderr);
306
+		fclose(fin);
307
+		return NULL;
308
+	}
309
+
310
+	shutdown(sock, SHUT_RD);
311
+
312
+	nbytes = recv(m->sock, buf, sizeof(buf), 0);
313
+	if(nbytes <= 0) {
314
+		perror(m->name);
315
+		close(sock);
316
+		fclose(fin);
317
+		return NULL;
318
+	}
319
+	buf[nbytes] = '\0';
320
+
321
+	if(sscanf(buf, "PORT %hu\n", &port) != 1) {
322
+		fprintf(stderr, "Expected port information from clamd, got '%s'",
323
+			buf);
324
+		close(sock);
325
+		fclose(fin);
326
+		return NULL;
327
+	}
328
+
329
+	memset((char *)&data, 0, sizeof(struct sockaddr_in));
330
+	data.sin_family = AF_INET;
331
+	data.sin_port = (in_port_t)htons(port);
332
+	data.sin_addr.s_addr = m->ip;
333
+
334
+	if(connect(sock, (struct sockaddr *)&data, sizeof(struct sockaddr_in)) < 0) {
335
+		perror(m->name);
336
+		fprintf(stderr, "Couldn't connect to port %d\n", port);
337
+		close(sock);
338
+		fclose(fin);
339
+		return NULL;
340
+	}
341
+	while((buflen = fread(buf, 1, sizeof(buf), fin)) > 0)
342
+		if(send(sock, buf, buflen, 0) != (ssize_t)buflen) {
343
+			/* Proably hit scanstream len */
344
+			perror(m->name);
345
+			break;
346
+		}
347
+
348
+	close(sock);
349
+	fclose(fin);
350
+
351
+	/* TODO: timeout */
352
+	nbytes = recv(m->sock, args->ret, LEN, 0);
353
+	if(nbytes < 0) {
354
+		perror(m->name);
355
+		return NULL;
356
+	}
357
+	args->ret[nbytes - 1] = '\0';	/* remove the trailing \n */
358
+
359
+	return NULL;
360
+}