1 /*
2 * ap-trapd.c from Access Point SNMP Utils for Linux
3 * SNMP traps processing daemon code
4 *
5 * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License Version 2 from
9 * June 1991 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <pwd.h>
27 #include <syslog.h>
28 #include <stdio.h>
29 #include "ap-utils.h"
30
31 #define TRAPD_USER "nobody"
32
main(int argc,char ** argv)33 int main(int argc, char **argv)
34 {
35 extern char *optarg;
36 extern int optind;
37 extern int opterr;
38 extern int optopt;
39 int opt = 0;
40
41 char *user=NULL, *device=NULL;
42
43
44 pid_t pid;
45 struct passwd *pwd;
46 struct sockaddr_in server;
47 struct sockaddr_in client;
48 int sockfd, len;
49 unsigned int client_len = SIZE, hand, sec, min;
50 unsigned char buf[512], *start, snmp_version,
51 *community = NULL, generic_trap, specific_trap;
52 unsigned int i, atmel_ap_type = 0;
53 size_t time_stamp;
54 char mac[6], *enterprise_oid = NULL, c, mac_info[31], mac_flag = 0;
55 struct in_addr agent_addr;
56 char enterprise[] = { 0x2b, 0x06, 1, 4, 1, 0x83, 0x1a, 1, 1 };
57 char *generic_traps[8] = { "ColdStart",
58 "WarmStart",
59 "LinkDown",
60 "LinkUp",
61 "AuthenticationFailure",
62 "EgpNeighborLoss",
63 "EnterpriseSpecific",
64 "unknown"
65 };
66 char *specific_traps[22] = {
67 "Reassociation",
68 "RoamOut",
69 "Association",
70 "Disassociation",
71 "AssociationExpire",
72 "Reset",
73 "SettingPingIPAddress",
74 "StartUp",
75 "FailedToEraseFlash",
76 "APClientScanning",
77 "APClientAuthenticating",
78 "APClientAssociating",
79 "APClientReAssociating",
80 "APClientAuthenticationFailed",
81 "APClientAssociationFailed",
82 "APClientConnected",
83 "APClientDisconnected",
84 "APClientScanFailed",
85 "APClientJoinFailed",
86 "APClientJoining",
87 "unknown",
88 "APClientScanFinished" /* I think:) /roma */
89 };
90
91 char *specific_traps_sb[22] = {
92 "Reassociation",
93 "RoamOut",
94 "Association",
95 "Disassociation",
96 "AssociationExpire",
97 "Reset",
98 "SettingPingIPAddress",
99 "StartUp",
100 "FailedToEraseFlash",
101 "APClientAssociating",
102 "APClientScanning",
103 "MultiAttachedStation",
104 "unknown",
105 "unknown",
106 "unknown",
107 "unknown",
108 "unknown",
109 "unknown",
110 "unknown",
111 "unknown",
112 "unknown",
113 "unknown"
114 };
115
116 memset(&server, 0, sizeof server);
117 server.sin_family = AF_INET;
118 server.sin_port = htons(162);
119 server.sin_addr.s_addr = INADDR_ANY;
120
121 #ifdef HAVE_GETTEXT
122 /* locale support init */
123 setlocale(LC_ALL, "");
124 bindtextdomain("ap-utils", LOCALEDIR);
125 textdomain("ap-utils");
126 #endif
127
128 if (argc > 1)
129 do {
130 opterr = 0;
131 switch (opt = getopt(argc, argv, "u:i:s")) {
132 case 'i':
133 device = malloc(strlen(optarg) + 1);
134 strncpy(device, optarg, strlen(optarg) + 1);
135 break;
136 case 'u':
137 user = malloc(strlen(optarg) + 1);
138 strncpy(user, optarg, strlen(optarg) + 1);
139 break;
140 case 's':
141 atmel_ap_type = 1;
142 break;
143 }
144 } while (opt != -1);
145
146
147 openlog("ap-trapd", LOG_PID, LOG_LOCAL0);
148 syslog(LOG_INFO, _("ap-trapd %s started%s%s."), VERSION,
149 (device) ? _(" on ") : "", (device) ? device : "");
150
151 pid = fork();
152 if (pid > 0) { /* parent */
153 return 0;
154 } else if (pid < 0) { /* failed */
155 syslog(LOG_ERR, _("Unable to fork. Exiting."));
156 return 1;
157 }
158 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
159 syslog(LOG_ERR, _("Can't create socket. Exiting."));
160 return 1;
161 }
162
163
164 if (bind(sockfd, (struct sockaddr *) &server, SIZE) == -1) {
165 syslog(LOG_ERR, _("Can't bind socket. Exiting."));
166 return 1;
167 }
168 #ifdef OS_LINUX
169 if (device) {
170 if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, device,
171 strlen(device) + 1) == -1) {
172 syslog(LOG_ERR, _("Can't bind to device %s. Exiting."),
173 device);
174 return 1;
175 }
176 }
177 #endif
178
179 if (user == NULL)
180 user = TRAPD_USER;
181 /* after opening socket change userid */
182 if ((pwd = getpwnam(user)) == NULL) {
183 syslog(LOG_ERR, _("Unable to process username %s. Error: %m."),
184 user);
185 return 1;
186 }
187 if (setgid(pwd->pw_gid) == -1 || setuid(pwd->pw_uid) == -1) {
188 syslog(LOG_ERR, _("Unable to change to uid %d."), pwd->pw_uid);
189 return 1;
190 }
191
192 while (1) {
193 if ((len =
194 recvfrom(sockfd, buf, 512, 0, (struct sockaddr *) &client,
195 &client_len)) == -1)
196 continue;
197 if (buf[0] != ASN_HEADER) {
198 continue;
199 }
200 start = buf;
201 if (buf[1] & 0x80) {
202 start += (buf[1] & 0x7F) + 2;
203 } else {
204 start += 2;
205 }
206 snmp_version = start[2];
207
208 if (community)
209 free(community);
210 community = malloc(start[4] + 1);
211 memcpy(community, start + 5, start[4]);
212 community[start[4]] = '\0';
213 start += *(start + 4) + 5;
214
215 if (start[0] != TRAP) {
216 continue;
217 }
218
219 if (start[1] & 0x80) {
220 start += (start[1] & 0x7F) + 2;
221 } else {
222 start += 2;
223 }
224
225 if (enterprise_oid)
226 free(enterprise_oid);
227 enterprise_oid = malloc(start[1] + 1);
228 memcpy(enterprise_oid, start + 2, start[1]);
229 enterprise_oid[start[1]] = '\0';
230 start += start[1] + 2;
231 memcpy(&agent_addr.s_addr, start + 2, 4);
232 if (memcmp(enterprise_oid, enterprise, sizeof(enterprise))) {
233 syslog(LOG_INFO,
234 _
235 ("Received unknown SNMP ver %d trap. From %s:%d. Agent: %s. Community: %s."),
236 snmp_version + 1, inet_ntoa(client.sin_addr),
237 ntohs(client.sin_port), inet_ntoa(agent_addr),
238 community);
239 continue;
240 }
241
242 start += 6;
243 generic_trap = start[2];
244 if (generic_trap > 6)
245 generic_trap = 7;
246 specific_trap = start[5];
247 if (specific_trap > 22)
248 specific_trap = 21;
249
250 time_stamp = 0;
251 c = 0;
252 i = 1;
253 while (c < start[7]) {
254 time_stamp += (unsigned char) *(start + 7 + start[7] - c) * i;
255 i *= 256;
256 c++;
257 }
258 hand = time_stamp % 100;
259 time_stamp = time_stamp / 100;
260 sec = time_stamp % 60;
261 time_stamp = time_stamp / 60;
262 min = time_stamp % 60;
263 time_stamp = time_stamp / 60;
264
265 start += start[7] + 8;
266
267
268 mac_flag = 0;
269 if ((start - buf < len) && *(start) == ASN_HEADER) {
270
271 if (start[1] & 0x80) {
272 start += (start[1] & 0x7F) + 2;
273 len -= ((start[1] & 0x7F) + 2);
274 } else {
275 start += 2;
276 len -= 2;
277 }
278
279 if (*(start) == ASN_HEADER) {
280 if (start[1] & 0x80) {
281 start += (start[1] & 0x7F) + 2;
282 len -= ((start[1] & 0x7F) + 2);
283 } else {
284 start += 2;
285 len -= 2;
286 }
287 start += start[1] + 4;
288 memcpy(mac, start, 6);
289 if (generic_trap == 6 && specific_trap >= 1
290 && (specific_trap <= 5 || specific_trap >= 9)) {
291 sprintf(mac_info, "%02X%02X%02X%02X%02X%02X",
292 mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF,
293 mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF);
294 mac_flag = 1;
295 }
296 if (generic_trap == 6 && specific_trap == 7) {
297 sprintf(mac_info,
298 "%d.%d.%d.%d",
299 mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF,
300 mac[3] & 0xFF);
301 mac_flag = 1;
302 }
303 }
304 }
305 syslog(LOG_INFO,
306 _
307 ("Agent:v%d %s (%s@%s:%d) %s%s%s. SysUptime %d:%02d:%02d.%02d"),
308 snmp_version + 1, inet_ntoa(agent_addr),
309 community, inet_ntoa(client.sin_addr), ntohs(client.sin_port),
310 (generic_trap ==
311 6) ? (atmel_ap_type == 1) ? specific_traps[specific_trap-1] : specific_traps_sb[specific_trap-1] :
312 generic_traps[generic_trap], (mac_flag) ? " " : "",
313 (mac_flag) ? mac_info : "", time_stamp, min, sec, hand);
314 }
315
316 /* not reachable */
317 return 0;
318 }
319