1#include "ipf.h"
2#include "netinet/ipl.h"
3#include "ipmon.h"
4#include <ctype.h>
5
6static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 };
7/*
8 * Enterprise number OID:
9 * 1.3.6.1.4.1.9932
10 */
11static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
12static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
13
14static int writeint __P((u_char *, int));
15static int writelength __P((u_char *, u_int));
16static int maketrap_v2 __P((char *, u_char *, int, u_char *, int));
17static void snmpv2_destroy __P((void *));
18static void *snmpv2_dup __P((void *));
19static int snmpv2_match __P((void *, void *));
20static void *snmpv2_parse __P((char **));
21static void snmpv2_print __P((void *));
22static int snmpv2_send __P((void *, ipmon_msg_t *));
23
24
25int sendtrap_v2_0 __P((int, char *, char *, int));
26
27static char def_community[] = "public";	/* ublic */
28
29typedef struct snmpv2_opts_s {
30	char			*community;
31	char			*server;
32	int			fd;
33	int			v6;
34	int			ref;
35#ifdef USE_INET6
36	struct sockaddr_in6	sin6;
37#endif
38	struct sockaddr_in	sin;
39} snmpv2_opts_t;
40
41ipmon_saver_t snmpv2saver = {
42	"snmpv2",
43	snmpv2_destroy,
44	snmpv2_dup,		/* dup */
45	snmpv2_match,		/* match */
46	snmpv2_parse,
47	snmpv2_print,
48	snmpv2_send
49};
50
51
52static int
53snmpv2_match(ctx1, ctx2)
54	void *ctx1, *ctx2;
55{
56	snmpv2_opts_t *s1 = ctx1, *s2 = ctx2;
57
58	if (s1->v6 != s2->v6)
59		return 1;
60
61	if (strcmp(s1->community, s2->community))
62		return 1;
63
64#ifdef USE_INET6
65	if (s1->v6 == 1) {
66		if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
67			return 1;
68	} else
69#endif
70	{
71		if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
72			return 1;
73	}
74
75	return 0;
76}
77
78
79static void *
80snmpv2_dup(ctx)
81	void *ctx;
82{
83	snmpv2_opts_t *s = ctx;
84
85	s->ref++;
86	return s;
87}
88
89
90static void
91snmpv2_print(ctx)
92        void *ctx;
93{
94	snmpv2_opts_t *snmpv2 = ctx;
95
96	printf("%s ", snmpv2->community);
97#ifdef USE_INET6
98	if (snmpv2->v6 == 1) {
99		char buf[80];
100
101		printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf,
102				       sizeof(snmpv2->sin6.sin6_addr)));
103	} else
104#endif
105	{
106		printf("%s", inet_ntoa(snmpv2->sin.sin_addr));
107	}
108}
109
110
111static void *
112snmpv2_parse(char **strings)
113{
114	snmpv2_opts_t *ctx;
115	int result;
116	char *str;
117	char *s;
118
119	if (strings[0] == NULL || strings[0][0] == '\0')
120		return NULL;
121	if (strchr(*strings, ' ') == NULL)
122		return NULL;
123
124	str = strdup(*strings);
125
126	ctx = calloc(1, sizeof(*ctx));
127	if (ctx == NULL)
128		return NULL;
129
130	ctx->fd = -1;
131
132	s = strchr(str, ' ');
133	*s++ = '\0';
134	ctx->community = str;
135
136	while (ISSPACE(*s))
137		s++;
138	if (!*s) {
139		free(str);
140		free(ctx);
141		return NULL;
142	}
143
144#ifdef USE_INET6
145	if (strchr(s, ':') == NULL) {
146		result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
147		if (result == 1) {
148			ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
149			if (ctx->fd >= 0) {
150				ctx->sin.sin_family = AF_INET;
151				ctx->sin.sin_port = htons(162);
152				if (connect(ctx->fd,
153					    (struct sockaddr *)&ctx->sin,
154					    sizeof(ctx->sin)) != 0) {
155						snmpv2_destroy(ctx);
156						return NULL;
157				}
158			}
159		}
160	} else {
161		result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
162		if (result == 1) {
163			ctx->v6 = 1;
164			ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
165			if (ctx->fd >= 0) {
166				ctx->sin6.sin6_family = AF_INET6;
167				ctx->sin6.sin6_port = htons(162);
168				if (connect(ctx->fd,
169					    (struct sockaddr *)&ctx->sin6,
170					    sizeof(ctx->sin6)) != 0) {
171						snmpv2_destroy(ctx);
172						return NULL;
173				}
174			}
175		}
176	}
177#else
178	result = inet_aton(s, &ctx->sin.sin_addr);
179	if (result == 1) {
180		ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
181		if (ctx->fd >= 0) {
182			ctx->sin.sin_family = AF_INET;
183			ctx->sin.sin_port = htons(162);
184			if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
185				    sizeof(ctx->sin)) != 0) {
186					snmpv2_destroy(ctx);
187					return NULL;
188			}
189		}
190	}
191#endif
192
193	if (result != 1) {
194		free(str);
195		free(ctx);
196		return NULL;
197	}
198
199	ctx->ref = 1;
200
201	return ctx;
202}
203
204
205static void
206snmpv2_destroy(ctx)
207	void *ctx;
208{
209	snmpv2_opts_t *v2 = ctx;
210
211	v2->ref--;
212	if (v2->ref > 0)
213		return;
214
215	if (v2->community)
216		free(v2->community);
217	if (v2->fd >= 0)
218		close(v2->fd);
219	free(v2);
220}
221
222
223static int
224snmpv2_send(ctx, msg)
225	void *ctx;
226	ipmon_msg_t *msg;
227{
228	snmpv2_opts_t *v2 = ctx;
229
230	return sendtrap_v2_0(v2->fd, v2->community,
231			     msg->imm_msg, msg->imm_msglen);
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_v2(community, buffer, bufsize, msg, msglen)
300	char *community;
301	u_char *buffer;
302	int bufsize;
303	u_char *msg;
304	int msglen;
305{
306	u_char *s = buffer, *t, *pdulen;
307	u_char *varlen;
308	int basesize = 77;
309	u_short len;
310	int trapmsglen;
311	int pdulensz;
312	int varlensz;
313	int baselensz;
314	int n;
315
316	if (community == NULL || *community == '\0')
317		community = def_community;
318	basesize += strlen(community) + msglen;
319
320	if (basesize + 8 > bufsize)
321		return 0;
322
323	memset(buffer, 0xff, bufsize);
324	*s++ = 0x30;		/* Sequence */
325
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++ = 0x01;		/* version 2 */
336	*s++ = 0x04;		/* octet string */
337	*s++ = strlen(community);		/* length of "public" */
338	bcopy(community, s, s[-1]);
339	s += s[-1];
340	*s++ = 0xA7;		/* PDU(7) */
341	pdulen = s++;
342	if (basesize - (s - buffer) >= 128) {
343		pdulensz = 2;
344		basesize++;
345		s++;
346	} else {
347		pdulensz = 1;
348	}
349	/* request id */
350	*s++ = 0x2;	/* integer */
351	*s++ = 0x4;	/* len 4 */
352	*s++ = 0x0;	/* noError */
353	*s++ = 0x0;	/* noError */
354	*s++ = 0x0;	/* noError */
355	*s++ = 0x0;	/* noError */
356
357	/* error status */
358	*s++ = 0x2;	/* integer */
359	*s++ = 0x1;	/* len 1 */
360	*s++ = 0x0;	/* noError */
361
362	/* error-index */
363	*s++ = 0x2;	/* integer */
364	*s++ = 0x1;	/* len 1 */
365	*s++ = 0x0;	/* noError */
366
367	*s++ = 0x30;	/* sequence */
368	varlen = s++;
369	if (basesize - (s - buffer) >= 128) {
370		varlensz = 2;
371		basesize++;
372		s++;
373	} else {
374		varlensz = 1;
375	}
376
377	*s++ = 0x30;	/* sequence */
378	*s++ = sizeof(sysuptime) + 6;
379
380	bcopy(sysuptime, s, sizeof(sysuptime));
381	s += sizeof(sysuptime);
382
383	*s++ = 0x43;	/* Timestamp */
384	*s++ = 0x04;	/* TimeTicks */
385	*s++ = 0x0;
386	*s++ = 0x0;
387	*s++ = 0x0;
388	*s++ = 0x0;
389
390	*s++ = 0x30;
391	t = s + 1;
392	bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
393	t += sizeof(ipf_trap0_1);
394
395	*t++ = 0x2;		/* Integer */
396	n = writeint(t + 1, IPFILTER_VERSION);
397	*t = n;
398	t += n + 1;
399
400	len = t - s - 1;
401	writelength(s, len);
402
403	s = t;
404	*s++ = 0x30;
405	if (msglen < 128) {
406		if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128)
407			trapmsglen = 2;
408		else
409			trapmsglen = 1;
410	} else {
411		if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128)
412			trapmsglen = 2;
413		else
414			trapmsglen = 1;
415	}
416	t = s + trapmsglen;
417	bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
418	t += sizeof(ipf_trap0_2);
419
420	*t++ = 0x4;		/* Octet string */
421	n = writelength(t, msglen);
422	t += n;
423	bcopy(msg, t, msglen);
424	t += msglen;
425
426	len = t - s - trapmsglen;
427	writelength(s, len);
428
429	len = t - varlen - varlensz;
430	writelength(varlen, len);		/* pdu length */
431
432	len = t - pdulen - pdulensz;
433	writelength(pdulen, len);		/* pdu length */
434
435	len = t - buffer - baselensz - 1;
436	writelength(buffer + 1, len);	/* length of trap */
437
438	return t - buffer;
439}
440
441
442int
443sendtrap_v2_0(fd, community, msg, msglen)
444	int fd;
445	char *community, *msg;
446	int msglen;
447{
448
449	u_char buffer[1500];
450	int n;
451
452	n = maketrap_v2(community, buffer, sizeof(buffer),
453			(u_char *)msg, msglen);
454	if (n > 0) {
455		return send(fd, buffer, n, 0);
456	}
457
458	return 0;
459}
460