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