1#include "ipf.h"
2#include "netinet/ipl.h"
3#include "ipmon.h"
4#include <ctype.h>
5
6#define	IPF_ENTERPRISE	9932
7/*
8 * Enterprise number OID:
9 * 1.3.6.1.4.1.9932
10 */
11static u_char ipf_enterprise[] = { 6, 7, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c };
12static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
13static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
14
15static int writeint __P((u_char *, int));
16static int writelength __P((u_char *, u_int));
17static int maketrap_v1 __P((char *, u_char *, int, u_char *, int, u_32_t,
18			    time_t));
19static void snmpv1_destroy __P((void *));
20static void *snmpv1_dup __P((void *));
21static int snmpv1_match __P((void *, void *));
22static void *snmpv1_parse __P((char **));
23static void snmpv1_print __P((void *));
24static int snmpv1_send __P((void *, ipmon_msg_t *));
25
26typedef struct snmpv1_opts_s {
27	char			*community;
28	int			fd;
29	int			v6;
30	int			ref;
31#ifdef USE_INET6
32	struct sockaddr_in6	sin6;
33#endif
34	struct sockaddr_in	sin;
35} snmpv1_opts_t;
36
37ipmon_saver_t snmpv1saver = {
38	"snmpv1",
39	snmpv1_destroy,
40	snmpv1_dup,		/* dup */
41	snmpv1_match,		/* match */
42	snmpv1_parse,
43	snmpv1_print,
44	snmpv1_send
45};
46
47
48static int
49snmpv1_match(ctx1, ctx2)
50	void *ctx1, *ctx2;
51{
52	snmpv1_opts_t *s1 = ctx1, *s2 = ctx2;
53
54	if (s1->v6 != s2->v6)
55		return 1;
56
57	if (strcmp(s1->community, s2->community))
58		return 1;
59
60#ifdef USE_INET6
61	if (s1->v6 == 1) {
62		if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
63			return 1;
64	} else
65#endif
66	{
67		if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
68			return 1;
69	}
70
71	return 0;
72}
73
74
75static void *
76snmpv1_dup(ctx)
77	void *ctx;
78{
79	snmpv1_opts_t *s = ctx;
80
81	s->ref++;
82	return s;
83}
84
85
86static void
87snmpv1_print(ctx)
88	void *ctx;
89{
90	snmpv1_opts_t *snmpv1 = ctx;
91
92	printf("%s ", snmpv1->community);
93#ifdef USE_INET6
94	if (snmpv1->v6 == 1) {
95		char buf[80];
96
97		printf("%s", inet_ntop(AF_INET6, &snmpv1->sin6.sin6_addr, buf,
98				       sizeof(snmpv1->sin6.sin6_addr)));
99	} else
100#endif
101	{
102		printf("%s", inet_ntoa(snmpv1->sin.sin_addr));
103	}
104}
105
106
107static void *
108snmpv1_parse(char **strings)
109{
110	snmpv1_opts_t *ctx;
111	int result;
112	char *str;
113	char *s;
114
115	if (strings[0] == NULL || strings[0][0] == '\0')
116		return NULL;
117
118	if (strchr(*strings, ' ') == NULL)
119		return NULL;
120
121	str = strdup(*strings);
122
123	ctx = calloc(1, sizeof(*ctx));
124	if (ctx == NULL)
125		return NULL;
126
127	ctx->fd = -1;
128
129	s = strchr(str, ' ');
130	*s++ = '\0';
131	ctx->community = str;
132
133	while (ISSPACE(*s))
134		s++;
135	if (!*s) {
136		free(str);
137		free(ctx);
138		return NULL;
139	}
140
141#ifdef USE_INET6
142	if (strchr(s, ':') == NULL) {
143		result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
144		if (result == 1) {
145			ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
146			if (ctx->fd >= 0) {
147				ctx->sin.sin_family = AF_INET;
148				ctx->sin.sin_port = htons(162);
149				if (connect(ctx->fd,
150					    (struct sockaddr *)&ctx->sin,
151					    sizeof(ctx->sin)) != 0) {
152						snmpv1_destroy(ctx);
153						return NULL;
154				}
155			}
156		}
157	} else {
158		result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
159		if (result == 1) {
160			ctx->v6 = 1;
161			ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
162			if (ctx->fd >= 0) {
163				ctx->sin6.sin6_family = AF_INET6;
164				ctx->sin6.sin6_port = htons(162);
165				if (connect(ctx->fd,
166					    (struct sockaddr *)&ctx->sin6,
167					    sizeof(ctx->sin6)) != 0) {
168						snmpv1_destroy(ctx);
169						return NULL;
170				}
171			}
172		}
173	}
174#else
175	result = inet_aton(s, &ctx->sin.sin_addr);
176	if (result == 1) {
177		ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
178		if (ctx->fd >= 0) {
179			ctx->sin.sin_family = AF_INET;
180			ctx->sin.sin_port = htons(162);
181			if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
182				    sizeof(ctx->sin)) != 0) {
183					snmpv1_destroy(ctx);
184					return NULL;
185			}
186		}
187	}
188#endif
189
190	if (result != 1) {
191		free(str);
192		free(ctx);
193		return NULL;
194	}
195
196	ctx->ref = 1;
197
198	return ctx;
199}
200
201
202static void
203snmpv1_destroy(ctx)
204	void *ctx;
205{
206	snmpv1_opts_t *v1 = ctx;
207
208	v1->ref--;
209	if (v1->ref > 0)
210		return;
211
212	if (v1->community)
213		free(v1->community);
214	if (v1->fd >= 0)
215		close(v1->fd);
216	free(v1);
217}
218
219
220static int
221snmpv1_send(ctx, msg)
222	void *ctx;
223	ipmon_msg_t *msg;
224{
225	snmpv1_opts_t *v1 = ctx;
226
227	return sendtrap_v1_0(v1->fd, v1->community,
228			     msg->imm_msg, msg->imm_msglen, msg->imm_when);
229}
230
231static char def_community[] = "public";	/* ublic */
232
233static int
234writelength(buffer, value)
235	u_char *buffer;
236	u_int value;
237{
238	u_int n = htonl(value);
239	int len;
240
241	if (value < 128) {
242		*buffer = value;
243		return 1;
244	}
245	if (value > 0xffffff)
246		len = 4;
247	else if (value > 0xffff)
248		len = 3;
249	else if (value > 0xff)
250		len = 2;
251	else
252		len = 1;
253
254	*buffer = 0x80 | len;
255
256	bcopy((u_char *)&n + 4 - len, buffer + 1, len);
257
258	return len + 1;
259}
260
261
262static int
263writeint(buffer, value)
264	u_char *buffer;
265	int value;
266{
267	u_char *s = buffer;
268	u_int n = value;
269
270	if (value == 0) {
271		*buffer = 0;
272		return 1;
273	}
274
275	if (n >  4194304) {
276		*s++ = 0x80 | (n / 4194304);
277		n -= 4194304 * (n / 4194304);
278	}
279	if (n >  32768) {
280		*s++ = 0x80 | (n / 32768);
281		n -= 32768 * (n / 327678);
282	}
283	if (n > 128) {
284		*s++ = 0x80 | (n / 128);
285		n -= (n / 128) * 128;
286	}
287	*s++ = (u_char)n;
288
289	return s - buffer;
290}
291
292
293
294/*
295 * First style of traps is:
296 * 1.3.6.1.4.1.9932.1.1
297 */
298static int
299maketrap_v1(community, buffer, bufsize, msg, msglen, ipaddr, when)
300	char *community;
301	u_char *buffer;
302	int bufsize;
303	u_char *msg;
304	int msglen;
305	u_32_t ipaddr;
306	time_t when;
307{
308	u_char *s = buffer, *t, *pdulen, *varlen;
309	int basesize = 73;
310	u_short len;
311	int trapmsglen;
312	int pdulensz;
313	int varlensz;
314	int baselensz;
315	int n;
316
317	if (community == NULL || *community == '\0')
318		community = def_community;
319	basesize += strlen(community) + msglen;
320
321	if (basesize + 8 > bufsize)
322		return 0;
323
324	memset(buffer, 0xff, bufsize);
325	*s++ = 0x30;		/* Sequence */
326	if (basesize - 1 >= 128) {
327		baselensz = 2;
328		basesize++;
329	} else {
330		baselensz = 1;
331	}
332	s += baselensz;
333	*s++ = 0x02;		/* Integer32 */
334	*s++ = 0x01;		/* length 1 */
335	*s++ = 0x00;		/* version 1 */
336	*s++ = 0x04;		/* octet string */
337	*s++ = strlen(community);		/* length of "public" */
338	bcopy(community, s, s[-1]);
339	s += s[-1];
340	*s++ = 0xA4;		/* PDU(4) */
341	pdulen = s++;
342	if (basesize - (s - buffer) >= 128) {
343		pdulensz = 2;
344		basesize++;
345		s++;
346	} else {
347		pdulensz = 1;
348	}
349
350	/* enterprise */
351	bcopy(ipf_enterprise, s, sizeof(ipf_enterprise));
352	s += sizeof(ipf_enterprise);
353
354	/* Agent address */
355	*s++ = 0x40;
356	*s++ = 0x4;
357	bcopy(&ipaddr, s, 4);
358	s += 4;
359
360	/* Generic Trap code */
361	*s++ = 0x2;
362	n = writeint(s + 1, 6);
363	if (n == 0)
364		return 0;
365	*s = n;
366	s += n + 1;
367
368	/* Specific Trap code */
369	*s++ = 0x2;
370	n = writeint(s + 1, 0);
371	if (n == 0)
372		return 0;
373	*s = n;
374	s += n + 1;
375
376	/* Time stamp */
377	*s++ = 0x43;			/* TimeTicks */
378	*s++ = 0x04;			/* TimeTicks */
379	s[0] = when >> 24;
380	s[1] = when >> 16;
381	s[2] = when >> 8;
382	s[3] = when & 0xff;
383	s += 4;
384
385	/*
386	 * The trap0 message is "ipfilter_version" followed by the message
387	 */
388	*s++ = 0x30;
389	varlen = s;
390	if (basesize - (s - buffer) >= 128) {
391		varlensz = 2;
392		basesize++;
393	} else {
394		varlensz = 1;
395	}
396	s += varlensz;
397
398	*s++ = 0x30;
399	t = s + 1;
400	bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
401	t += sizeof(ipf_trap0_1);
402
403	*t++ = 0x2;		/* Integer */
404	n = writeint(t + 1, IPFILTER_VERSION);
405	*t = n;
406	t += n + 1;
407
408	len = t - s - 1;
409	writelength(s, len);
410
411	s = t;
412	*s++ = 0x30;
413	if (basesize - (s - buffer) >= 128) {
414		trapmsglen = 2;
415		basesize++;
416	} else {
417		trapmsglen = 1;
418	}
419	t = s + trapmsglen;
420	bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
421	t += sizeof(ipf_trap0_2);
422
423	*t++ = 0x4;		/* Octet string */
424	n = writelength(t, msglen);
425	t += n;
426	bcopy(msg, t, msglen);
427	t += msglen;
428
429	len = t - s - trapmsglen;
430	writelength(s, len);
431
432	len = t - varlen - varlensz;
433	writelength(varlen, len);		/* pdu length */
434
435	len = t - pdulen - pdulensz;
436	writelength(pdulen, len);		/* pdu length */
437
438	len = t - buffer - baselensz - 1;
439	writelength(buffer + 1, len);	/* length of trap */
440
441	return t - buffer;
442}
443
444
445int
446sendtrap_v1_0(fd, community, msg, msglen, when)
447	int fd;
448	char *community, *msg;
449	int msglen;
450	time_t when;
451{
452
453	u_char buffer[1500];
454	int n;
455
456	n = maketrap_v1(community, buffer, sizeof(buffer),
457			(u_char *)msg, msglen, 0, when);
458	if (n > 0) {
459		return send(fd, buffer, n, 0);
460	}
461
462	return 0;
463}
464