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