]> git.sur5r.net Git - ngadmin/blob - spy/src/spy.c
Spy: show specific attributes details
[ngadmin] / spy / src / spy.c
1
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <poll.h>
5 #include <ctype.h>
6 #include <signal.h>
7 #include <arpa/inet.h>
8
9 #include <ngadmin.h> /* FIXME */
10 #include <nsdp/protocol.h>
11 #include <nsdp/attr.h>
12 #include <nsdp/net.h>
13 #include <nsdp/misc.h>
14
15
16 static void print_password (const char *pass, unsigned int len)
17 {
18         unsigned int i;
19         char *s;
20         
21         
22         for (i = 0; i < len; i++) {
23                 if (!isprint(pass[i]))
24                         break;
25         }
26         
27         if (i == len) {
28                 /* all characters are printable, cleartext password assumed */
29                 printf("(clear) \"%s\"", pass);
30                 return;
31         }
32         
33         s = malloc(len + 1);
34         if (s == NULL)
35                 return;
36         memcpy(s, pass, len);
37         s[len] = '\0';
38         
39         passwordEndecode(s, len);
40         
41         for (i = 0; i < len; i++) {
42                 if (!isprint(s[i]))
43                         break;
44         }
45         
46         if (i == len) {
47                 /* all characters are printable, encrypted password assumed */
48                 printf("(encrypted) \"%s\"", s);
49                 free(s);
50                 return;
51         }
52         
53         free(s);
54         
55         /* unknown encoding, fallback to hex display */
56         printf("(hex) ");
57         for (i = 0; i < len; i++)
58                 printf("%02x ", (unsigned char)pass[i]);
59 }
60
61
62 static const char* port_status_str (unsigned char status)
63 {
64         switch (status) {
65         
66         case SPEED_DOWN:
67                 return "down";
68         
69         case SPEED_10:
70                 return "10M";
71         
72         case SPEED_100:
73                 return "100M";
74         
75         case SPEED_1000:
76                 return "1000M";
77         
78         default:
79                 return "unknown";
80         }
81 }
82
83
84 static const char* vlan_type_code (unsigned char type)
85 {
86         switch (type) {
87         
88         case VLAN_DISABLED:
89                 return "disabled";
90         
91         case VLAN_PORT_BASIC:
92                 return "basic port based";
93         
94         case VLAN_PORT_ADV:
95                 return "advanced port based";
96         
97         case VLAN_DOT_BASIC:
98                 return "basic 802.1Q";
99         
100         case VLAN_DOT_ADV:
101                 return "advanced 802.1Q";
102         
103         default:
104                 return "unknown";
105         }
106 }
107
108
109 static const char* vlan_code_str (unsigned char code)
110 {
111         switch (code) {
112         
113         case VLAN_NO:
114                 return "no";
115         
116         case VLAN_UNTAGGED:
117                 return "untagged";
118         
119         case VLAN_TAGGED:
120                 return "tagged";
121         
122         default:
123                 return "unknown";
124         }
125 }
126
127
128 static const char* qos_type_str (unsigned char type)
129 {
130         switch (type) {
131         
132         case QOS_PORT:
133                 return "port";
134         
135         case QOS_DOT:
136                 return "802.1p";
137         
138         default:
139                 return "unknown";
140         }
141 }
142
143
144 static const char* qos_prio_str (unsigned char prio)
145 {
146         switch (prio) {
147         
148         case PRIO_HIGH:
149                 return "high";
150         
151         case PRIO_MED:
152                 return "medium";
153         
154         case PRIO_NORM:
155                 return "normal";
156         
157         case PRIO_LOW:
158                 return "low";
159         
160         default:
161                 return "unknown";
162         }
163 }
164
165
166 static const char* bitrate_str (unsigned int bitrate)
167 {
168         switch (bitrate) {
169         
170         case BITRATE_NOLIMIT:
171                 return "unlimited";
172         
173         case BITRATE_512K:
174                 return "512K";
175         
176         case BITRATE_1M:
177                 return "1M";
178         
179         case BITRATE_2M:
180                 return "2M";
181         
182         case BITRATE_4M:
183                 return "4M";
184         
185         case BITRATE_8M:
186                 return "8M";
187         
188         case BITRATE_16M:
189                 return "16M";
190         
191         case BITRATE_32M:
192                 return "32M";
193         
194         case BITRATE_64M:
195                 return "64M";
196         
197         case BITRATE_128M:
198                 return "128M";
199         
200         case BITRATE_256M:
201                 return "256M";
202         
203         case BITRATE_512M:
204                 return "512M";
205         
206         default:
207                 return "unknown";
208         }
209 }
210
211
212 static void print_attr (const struct attr *at)
213 {
214         unsigned char p, ports, *byte = at->data;
215         unsigned short *word = at->data;
216         char *s = at->data;
217         struct ether_addr *eth = at->data;
218         struct in_addr *ip = at->data;
219         struct attr_port_status *apsu = at->data;
220         struct attr_port_stat *apsi = at->data;
221         struct attr_cabletest_do *acd = at->data;
222         struct attr_cabletest_result *acr = at->data;
223         struct attr_vlan_conf *avc = at->data;
224         struct attr_pvid *ap = at->data;
225         struct attr_qos *aq = at->data;
226         struct attr_bitrate *ab = at->data;
227         struct attr_mirror *am = at->data;
228         struct attr_igmp_vlan *aiv = at->data;
229         
230         
231         printf("code = %04X, length = %d\n", at->attr, at->size);
232         
233         if (at->size == 0) {
234                 printf("\tempty\n\n");
235                 return;
236         }
237         
238         switch (at->attr) {
239         
240         case ATTR_PRODUCT:
241                 trim(s, at->size);
242                 printf("\tproduct = %s\n", s);
243                 break;
244         
245         case ATTR_NAME:
246                 trim(s, at->size);
247                 printf("\tname = %s\n", s);
248                 break;
249         
250         case ATTR_MAC:
251                 printf("\tMAC = %s\n", ether_ntoa(eth));
252                 break;
253         
254         case ATTR_IP:
255                 printf("\tIP = %s\n", inet_ntoa(*ip));
256                 break;
257         
258         case ATTR_NETMASK:
259                 printf("\tnetmask = %s\n", inet_ntoa(*ip));
260                 break;
261         
262         case ATTR_GATEWAY:
263                 printf("\tgateway = %s\n", inet_ntoa(*ip));
264                 break;
265         
266         case ATTR_NEW_PASSWORD:
267                 printf("\tnew password = ");
268                 print_password(s, at->size);
269                 printf("\n");
270                 break;
271         
272         case ATTR_PASSWORD:
273                 printf("\tpassword = ");
274                 print_password(s, at->size);
275                 printf("\n");
276                 break;
277         
278         case ATTR_DHCP:
279                 printf("\tDHCP = %s\n", *byte ? "yes" : "no");
280                 break;
281         
282         case ATTR_FIRM_VER:
283                 trim(s, at->size);
284                 printf("\tfirmware = %s\n", s);
285                 break;
286         
287         case ATTR_FIRM_UPGRADE:
288                 printf("\tfirmware upgrade requested\n");
289                 break;
290         
291         case ATTR_RESTART:
292                 printf("\trestart requested\n");
293                 break;
294         
295         case ATTR_ENCPASS:
296                 printf("\tpassword must be encrypted\n");
297                 break;
298         
299         case ATTR_DEFAULTS:
300                 printf("\treset parameters requested\n");
301                 break;
302         
303         case ATTR_PORT_STATUS:
304                 printf("\tport status\n");
305                 printf("\tport = %u\n", apsu->port);
306                 printf("\tstate = %s\n", port_status_str(apsu->status));
307                 break;
308         
309         case ATTR_PORT_STATISTICS:
310                 printf("\tport statistics\n");
311                 printf("\tport = %u\n", apsi->port);
312                 printf("\treceived = %llu\n", apsi->recv);
313                 printf("\tsend = %llu\n", apsi->sent);
314                 printf("\tCRC = %llu\n", apsi->crc);
315                 break;
316         
317         case ATTR_STATS_RESET:
318                 printf("\tport statistics reset requested\n");
319                 break;
320         
321         
322         case ATTR_CABLETEST_DO:
323                 printf("\tstart cabletest\n");
324                 printf("\tport = %u\n", acd->port);
325                 printf("\taction = %u\n", acd->action);
326                 break;
327         
328         case ATTR_CABLETEST_RESULT:
329                 printf("\tcabletest result\n");
330                 printf("\tport = %u\n", acr->port);
331                 if (at->size > 1) {
332                         printf("\tv1 = %u\n", acr->v1);
333                         printf("\tv2 = %u\n", acr->v2);
334                 }
335                 break;
336         
337         case ATTR_VLAN_TYPE:
338                 printf("\tVLAN type = %s\n", vlan_type_code(*byte));
339                 break;
340         
341         case ATTR_VLAN_PORT_CONF:
342                 printf("\tport based VLAN configuration\n");
343                 printf("\tVLAN = %u\n", avc->vlan);
344                 ports = at->size - sizeof(struct attr_vlan_conf);
345                 for (p = 0; p < ports; p++)
346                         printf("\tport %d = %s\n", p + 1, vlan_code_str(avc->ports[p]));
347                 break;
348         
349         case ATTR_VLAN_DOT_CONF:
350                 printf("\t802.1Q based VLAN configuration\n");
351                 printf("\tVLAN = %u\n", avc->vlan);
352                 ports = at->size - sizeof(struct attr_vlan_conf);
353                 for (p = 0; p < ports; p++)
354                         printf("\tport %d = %s\n", p + 1, vlan_code_str(avc->ports[p]));
355                 break;
356         
357         case ATTR_VLAN_DESTROY:
358                 printf("\tdestroy VLAN = %u\n", *word);
359                 break;
360         
361         case ATTR_VLAN_PVID:
362                 printf("\tVLAN PVID\n");
363                 printf("\tport = %u\n", ap->port);
364                 printf("\tVLAN = %u\n", ap->vlan);
365                 break;
366         
367         case ATTR_QOS_TYPE:
368                 printf("\tQoS type = %s\n", qos_type_str(*byte));
369                 break;
370         
371         case ATTR_QOS_CONFIG:
372                 printf("\tQoS configuration\n");
373                 printf("\tport = %u\n", aq->port);
374                 printf("\tpriority = %s\n", qos_prio_str(aq->prio));
375                 break;
376         
377         case ATTR_BITRATE_INPUT:
378                 printf("\tinput bitrate\n");
379                 printf("\tport = %u\n", ab->port);
380                 printf("\tbitrate = %s\n", bitrate_str(ab->bitrate));
381                 break;
382         
383         case ATTR_BITRATE_OUTPUT:
384                 printf("\toutput bitrate\n");
385                 printf("\tport = %u\n", ab->port);
386                 printf("\tbitrate = %s\n", bitrate_str(ab->bitrate));
387                 break;
388         
389         case ATTR_STORM_ENABLE:
390                 printf("\tstorm filtering = %s\n", *byte ? "yes" : "no");
391                 break;
392         
393         case ATTR_STORM_BITRATE:
394                 printf("\tstorm filtering bitrate\n");
395                 printf("\tport = %u\n", ab->port);
396                 printf("\tbitrate = %s\n", bitrate_str(ab->bitrate));
397                 break;
398         
399         case ATTR_MIRROR:
400                 printf("\tport mirroring\n");
401                 if (am->outport == 0) {
402                         printf("\tdisabled\n");
403                         break;
404                 }
405                 
406                 printf("\toutput port = %u\n", am->outport);
407                 ports = at->size - sizeof(struct attr_mirror);
408                 for (p = 0; p < ports; p++)
409                         printf("\tport %u = %s\n", p + 1, am->ports[p] ? "yes" : "no");
410                 break;
411         
412         case ATTR_PORTS_COUNT:
413                 printf("\tports count = %u\n", *byte);
414                 break;
415         
416         case ATTR_IGMP_ENABLE_VLAN:
417                 printf("\tIGMP filtering\n");
418                 printf("\tenable = %s\n", aiv->enable ? "yes" : "no");
419                 printf("\tVLAN = %u\n", aiv->vlan);
420                 break;
421         
422         case ATTR_IGMP_BLOCK_UNK:
423                 printf("\tblock unknown IGMP = %s\n", *byte ? "yes" : "no");
424                 break;
425         
426         case ATTR_IGMP_VALID_V3:
427                 printf("\tvalidate IGMPv3 = %s\n", *byte ? "yes" : "no");
428                 break;
429         
430         default:
431                 printf("\tunknown\n");
432         }
433         
434         printf("\n");
435 }
436
437
438 static const char* code_str (unsigned char code)
439 {
440         switch (code) {
441         
442         case CODE_READ_REQ:
443                 return "read request";
444         
445         case CODE_READ_REP:
446                 return "read reply";
447         
448         case CODE_WRITE_REQ:
449                 return "write request";
450         
451         case CODE_WRITE_REP:
452                 return "write reply";
453         
454         default:
455                 return "unknown";
456         }
457 }
458
459
460 static const char* error_str (unsigned char err)
461 {
462         switch (err) {
463         
464         case 0:
465                 return "none";
466         
467         case ERROR_READONLY:
468                 return "read only";
469         
470         case ERROR_INVALID_VALUE:
471                 return "invalid value";
472         
473         case ERROR_DENIED:
474                 return "access denied";
475         
476         default:
477                 return "unknown";
478         }
479 }
480
481
482 static void print_packet (const List *attr, const struct nsdp_cmd *nc)
483 {
484         const ListNode *ln;
485         const struct attr *at;
486         
487         
488         printf("---------------------------------\n");
489         printf("code = %s (%u)\n", code_str(nc->code), nc->code);
490         printf("error = %s (%u)\n", error_str(nc->error), nc->error);
491         if (nc->attr_error != 0)
492                 printf("erroneous attribute = %04X\n", nc->attr_error);
493         printf("source address = %s:%u\n", inet_ntoa(nc->remote_addr.sin_addr), ntohs(nc->remote_addr.sin_port));
494         printf("client MAC = %s\n", ether_ntoa(&nc->client_mac));
495         printf("switch MAC = %s\n", ether_ntoa(&nc->switch_mac));
496         printf("sequence number = %u\n\n", nc->seqnum);
497         printf("received %d attribute(s)\n\n", attr->count);
498         
499         for (ln = attr->first; ln != NULL; ln = ln->next) {
500                 at = ln->data;
501                 print_attr(at);
502         }
503         
504         printf("---------------------------------\n\n");
505 }
506
507
508 static void handler (int sig)
509 {
510         (void)sig;
511         printf("interrupt\n");
512 }
513
514
515 int main (void)
516 {
517         int err = 0, sw_sock = -1, cl_sock = -1;
518         List *attr;
519         struct nsdp_cmd nc;
520         struct sockaddr_in sw_local, cl_local;
521         struct pollfd fds[2];
522         struct sigaction sa;
523         
524         
525         sw_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
526         if (sw_sock < 0) {
527                 perror("socket");
528                 err = 1;
529                 goto end;
530         };
531         
532         cl_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
533         if (cl_sock < 0) {
534                 perror("socket");
535                 err = 1;
536                 goto end;
537         };
538         
539         
540         memset(&sw_local, 0, sizeof(struct sockaddr_in));
541         sw_local.sin_family = AF_INET;
542         sw_local.sin_addr.s_addr = htonl(INADDR_ANY);
543         sw_local.sin_port = htons(SWITCH_PORT);
544         
545         cl_local = sw_local;
546         cl_local.sin_port = htons(CLIENT_PORT);
547         
548         if (bind(sw_sock, (struct sockaddr*)&sw_local, sizeof(struct sockaddr_in)) < 0) {
549                 perror("bind");
550                 err = 2;
551                 goto end;
552         }
553         
554         if (bind(cl_sock, (struct sockaddr*)&cl_local, sizeof(struct sockaddr_in)) < 0) {
555                 perror("bind");
556                 err = 2;
557                 goto end;
558         }
559         
560         fds[0].fd = sw_sock;
561         fds[0].events = POLLIN;
562         fds[0].revents = 0;
563         fds[1].fd = cl_sock;
564         fds[1].events = POLLIN;
565         fds[1].revents = 0;
566         
567         memset(&sa, 0, sizeof(struct sigaction));
568         sa.sa_handler = handler;
569         sigaction(SIGINT, &sa, NULL);
570         sigaction(SIGTERM, &sa, NULL);
571         
572         attr = createEmptyList();
573         
574         while (1) {
575                 err = poll(fds, 2, -1);
576                 if (err < 0) {
577                         perror("poll");
578                         break;
579                 } else if (err == 0) {
580                         continue;
581                 }
582                 
583                 memset(&nc, 0, sizeof(struct nsdp_cmd));
584                 nc.remote_addr.sin_family = AF_INET;
585                 
586                 if (fds[0].revents & POLLIN) {
587                         nc.remote_addr.sin_port = htons(CLIENT_PORT);
588                         err = recvNsdpPacket(sw_sock, &nc, attr, NULL);
589                 } else {
590                         nc.remote_addr.sin_port = htons(SWITCH_PORT);
591                         err = recvNsdpPacket(cl_sock, &nc, attr, NULL);
592                 }
593                 
594                 if (err < 0)
595                         continue;
596                 
597                 print_packet(attr, &nc);
598                 
599                 clearList(attr, (void(*)(void*))freeAttr);
600         }
601         
602         destroyList(attr, (void(*)(void*))freeAttr);
603         
604 end:
605         close(sw_sock);
606         close(cl_sock);
607         
608         return err;
609 }
610